diff options
-rw-r--r-- | py/asmthumb.c | 14 | ||||
-rw-r--r-- | py/asmthumb.h | 10 | ||||
-rw-r--r-- | py/compile.c | 247 | ||||
-rw-r--r-- | py/emit.h | 31 | ||||
-rw-r--r-- | py/emitbc.c | 51 | ||||
-rw-r--r-- | py/emitcpy.c | 41 | ||||
-rw-r--r-- | py/emitinlinethumb.c | 2 | ||||
-rw-r--r-- | py/emitnative.c | 39 | ||||
-rw-r--r-- | py/emitpass1.c | 7 | ||||
-rw-r--r-- | py/lexer.c | 107 | ||||
-rw-r--r-- | py/lexerunix.c | 50 | ||||
-rw-r--r-- | py/malloc.c | 34 | ||||
-rw-r--r-- | py/misc.h | 4 | ||||
-rw-r--r-- | py/modstruct.c | 2 | ||||
-rw-r--r-- | py/mpconfig.h | 5 | ||||
-rw-r--r-- | py/obj.h | 4 | ||||
-rw-r--r-- | py/objcomplex.c | 29 | ||||
-rw-r--r-- | py/objexcept.c | 59 | ||||
-rw-r--r-- | py/objfloat.c | 2 | ||||
-rw-r--r-- | py/objfun.c | 10 | ||||
-rw-r--r-- | py/parse.c | 66 | ||||
-rw-r--r-- | py/parse.h | 1 | ||||
-rw-r--r-- | py/parsehelper.c | 8 | ||||
-rw-r--r-- | py/runtime.c | 15 | ||||
-rw-r--r-- | py/unicode.c | 2 | ||||
-rw-r--r-- | py/vm.c | 26 | ||||
-rw-r--r-- | stmhal/Makefile | 3 | ||||
-rw-r--r-- | stmhal/modstm.c | 120 | ||||
-rw-r--r-- | stmhal/modstm.h | 1 | ||||
-rw-r--r-- | stmhal/mpconfigport.h | 7 | ||||
-rw-r--r-- | stmhal/qstrdefsport.h | 16 | ||||
-rw-r--r-- | tests/basics/compare-multi.py | 4 | ||||
-rw-r--r-- | tests/basics/fun-defargs2.py | 6 | ||||
-rw-r--r-- | unix/main.c | 10 |
34 files changed, 739 insertions, 294 deletions
diff --git a/py/asmthumb.c b/py/asmthumb.c index f37b1ff8fe..e8c8927a9c 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -22,7 +22,7 @@ struct _asm_thumb_t { byte *code_base; byte dummy_data[8]; - int max_num_labels; + uint max_num_labels; int *label_offsets; int num_locals; uint push_reglist; @@ -212,7 +212,7 @@ void asm_thumb_exit(asm_thumb_t *as) { asm_thumb_write_op16(as, OP_POP_RLIST_PC(as->push_reglist)); } -void asm_thumb_label_assign(asm_thumb_t *as, int label) { +void asm_thumb_label_assign(asm_thumb_t *as, uint label) { assert(label < as->max_num_labels); if (as->pass == ASM_THUMB_PASS_2) { // assign label offset @@ -225,7 +225,7 @@ void asm_thumb_label_assign(asm_thumb_t *as, int label) { } } -STATIC int get_label_dest(asm_thumb_t *as, int label) { +STATIC int get_label_dest(asm_thumb_t *as, uint label) { assert(label < as->max_num_labels); return as->label_offsets[label]; } @@ -308,7 +308,7 @@ void asm_thumb_ite_ge(asm_thumb_t *as) { #define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) -void asm_thumb_b_n(asm_thumb_t *as, int label) { +void asm_thumb_b_n(asm_thumb_t *as, uint label) { int dest = get_label_dest(as, label); int rel = dest - as->code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction @@ -321,7 +321,7 @@ void asm_thumb_b_n(asm_thumb_t *as, int label) { #define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) -void asm_thumb_bcc_n(asm_thumb_t *as, int cond, int label) { +void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label) { int dest = get_label_dest(as, label); int rel = dest - as->code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction @@ -380,7 +380,7 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) #define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) #define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff)) -void asm_thumb_b_label(asm_thumb_t *as, int label) { +void asm_thumb_b_label(asm_thumb_t *as, uint label) { int dest = get_label_dest(as, label); int rel = dest - as->code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction @@ -403,7 +403,7 @@ void asm_thumb_b_label(asm_thumb_t *as, int label) { #define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f)) #define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff)) -void asm_thumb_bcc_label(asm_thumb_t *as, int cond, int label) { +void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { int dest = get_label_dest(as, label); int rel = dest - as->code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction diff --git a/py/asmthumb.h b/py/asmthumb.h index 60a86ea50b..f9226f1eb0 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -53,7 +53,7 @@ void *asm_thumb_get_code(asm_thumb_t *as); void asm_thumb_entry(asm_thumb_t *as, int num_locals); void asm_thumb_exit(asm_thumb_t *as); -void asm_thumb_label_assign(asm_thumb_t *as, int label); +void asm_thumb_label_assign(asm_thumb_t *as, uint label); // argument order follows ARM, in general dest is first // note there is a difference between movw and mov.w, and many others! @@ -67,8 +67,8 @@ void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b); void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8); void asm_thumb_ite_ge(asm_thumb_t *as); -void asm_thumb_b_n(asm_thumb_t *as, int label); -void asm_thumb_bcc_n(asm_thumb_t *as, int cond, int label); +void asm_thumb_b_n(asm_thumb_t *as, uint label); +void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label); void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32_src); // convenience void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience @@ -76,7 +76,7 @@ void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience -void asm_thumb_b_label(asm_thumb_t *as, int label); // convenience ? -void asm_thumb_bcc_label(asm_thumb_t *as, int cc, int label); // convenience: picks narrow or wide branch +void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience ? +void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience ? diff --git a/py/compile.c b/py/compile.c index 3ea6dd3a61..4738c0ae55 100644 --- a/py/compile.c +++ b/py/compile.c @@ -43,10 +43,10 @@ typedef struct _compiler_t { uint8_t had_error; // try to keep compiler clean from nlr uint8_t func_arg_is_super; // used to compile special case of super() function call - int next_label; + uint next_label; - int break_label; - int continue_label; + uint break_label; + uint continue_label; int break_continue_except_level; uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT @@ -78,6 +78,19 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha comp->had_error = true; } +STATIC const mp_map_elem_t mp_constants_table[] = { + // Extra constants as defined by a port + MICROPY_EXTRA_CONSTANTS +}; + +STATIC const mp_map_t mp_constants_map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_constants_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_constants_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_constants_table, +}; + mp_parse_node_t fold_constants(mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_STRUCT(pn)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; @@ -168,10 +181,12 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { } break; -#if MICROPY_EMIT_CPYTHON case PN_power: - // can overflow; enabled only to compare with CPython - if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { + if (0) { +#if MICROPY_EMIT_CPYTHON + } else if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { + // int**x + // can overflow; enabled only to compare with CPython mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2]; if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) { int power = MP_PARSE_NODE_LEAF_SMALL_INT(pns2->nodes[0]); @@ -184,9 +199,27 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ans); } } +#endif + } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_trailer_period) && MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { + // id.id + // look it up in constant table, see if it can be replaced with an integer + mp_parse_node_struct_t* pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); + qstr q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]); + mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP); + if (elem != NULL) { + mp_obj_t dest[2]; + mp_load_method_maybe(elem->value, q_attr, dest); + if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) { + machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]); + if (MP_PARSE_FITS_SMALL_INT(val)) { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val); + } + } + } } break; -#endif } } @@ -196,7 +229,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra); STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn); -STATIC int comp_next_label(compiler_t *comp) { +STATIC uint comp_next_label(compiler_t *comp) { return comp->next_label++; } @@ -467,7 +500,7 @@ STATIC void cpython_c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) { if (jump_if == false) { - int label2 = comp_next_label(comp); + uint label2 = comp_next_label(comp); for (int i = 0; i < n - 1; i++) { cpython_c_if_cond(comp, pns->nodes[i], true, label2, true); } @@ -485,7 +518,7 @@ STATIC void cpython_c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if cpython_c_if_cond(comp, pns->nodes[i], false, label, true); } } else { - int label2 = comp_next_label(comp); + uint label2 = comp_next_label(comp); for (int i = 0; i < n - 1; i++) { cpython_c_if_cond(comp, pns->nodes[i], false, label2, true); } @@ -528,7 +561,7 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) { if (jump_if == false) { - int label2 = comp_next_label(comp); + uint label2 = comp_next_label(comp); for (int i = 0; i < n - 1; i++) { c_if_cond(comp, pns->nodes[i], true, label2); } @@ -546,7 +579,7 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la c_if_cond(comp, pns->nodes[i], false, label); } } else { - int label2 = comp_next_label(comp); + uint label2 = comp_next_label(comp); for (int i = 0; i < n - 1; i++) { c_if_cond(comp, pns->nodes[i], false, label2); } @@ -1202,7 +1235,7 @@ void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0]; mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1]; - int l_fail = comp_next_label(comp); + uint l_fail = comp_next_label(comp); c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition compile_node(comp, pns_test_if_expr->nodes[0]); // success value EMIT(return_value); @@ -1236,31 +1269,35 @@ void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } } -// q1 holds the base, q2 the full name -// eg a -> q1=q2=a -// a.b.c -> q1=a, q2=a.b.c -void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) { +// q_base holds the base of the name +// eg a -> q_base=a +// a.b.c -> q_base=a +void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { bool is_as = false; if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; // a name of the form x as y; unwrap it - *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); + *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); pn = pns->nodes[0]; is_as = true; } - if (MP_PARSE_NODE_IS_ID(pn)) { + if (MP_PARSE_NODE_IS_NULL(pn)) { + // empty name (eg, from . import x) + *q_base = MP_QSTR_; + EMIT_ARG(import_name, MP_QSTR_); // import the empty string + } else if (MP_PARSE_NODE_IS_ID(pn)) { // just a simple name - *q2 = MP_PARSE_NODE_LEAF_ARG(pn); + qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn); if (!is_as) { - *q1 = *q2; + *q_base = q_full; } - EMIT_ARG(import_name, *q2); + EMIT_ARG(import_name, q_full); } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dotted_name) { // a name of the form a.b.c if (!is_as) { - *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); + *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); } int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); int len = n - 1; @@ -1278,33 +1315,29 @@ void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) { memcpy(str_dest, str_src, str_src_len); str_dest += str_src_len; } - *q2 = qstr_build_end(q_ptr); - EMIT_ARG(import_name, *q2); + qstr q_full = qstr_build_end(q_ptr); + EMIT_ARG(import_name, q_full); if (is_as) { for (int i = 1; i < n; i++) { EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); } } } else { - // TODO not implemented - // This covers relative imports starting with dot(s) like "from .foo import" - compile_syntax_error(comp, pn, "Relative imports not implemented"); - return; + // shouldn't happen + assert(0); } } else { - // TODO not implemented - // This covers relative imports with dots only like "from .. import" - compile_syntax_error(comp, pn, "Relative imports not implemented"); - return; + // shouldn't happen + assert(0); } } void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) { - EMIT_ARG(load_const_small_int, 0); // ?? - EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - qstr q1, q2; - do_import_name(comp, pn, &q1, &q2); - EMIT_ARG(store_id, q1); + EMIT_ARG(load_const_small_int, 0); // level 0 import + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything + qstr q_base; + do_import_name(comp, pn, &q_base); + EMIT_ARG(store_id, q_base); } void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -1312,8 +1345,44 @@ void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { + mp_parse_node_t pn_import_source = pns->nodes[0]; + + // extract the preceeding .'s (if any) for a relative import, to compute the import level + uint import_level = 0; + do { + mp_parse_node_t pn_rel; + if (MP_PARSE_NODE_IS_TOKEN(pn_import_source) || MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_one_or_more_period_or_ellipsis)) { + // This covers relative imports with dots only like "from .. import" + pn_rel = pn_import_source; + pn_import_source = MP_PARSE_NODE_NULL; + } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_import_from_2b)) { + // This covers relative imports starting with dot(s) like "from .foo import" + mp_parse_node_struct_t *pns_2b = (mp_parse_node_struct_t*)pn_import_source; + pn_rel = pns_2b->nodes[0]; + pn_import_source = pns_2b->nodes[1]; + assert(!MP_PARSE_NODE_IS_NULL(pn_import_source)); // should not be + } else { + // Not a relative import + break; + } + + // get the list of . and/or ...'s + mp_parse_node_t *nodes; + int n = list_get(&pn_rel, PN_one_or_more_period_or_ellipsis, &nodes); + + // count the total number of .'s + for (int i = 0; i < n; i++) { + if (MP_PARSE_NODE_IS_TOKEN_KIND(nodes[i], MP_TOKEN_DEL_PERIOD)) { + import_level++; + } else { + // should be an MP_TOKEN_ELLIPSIS + import_level += 3; + } + } + } while (0); + if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { - EMIT_ARG(load_const_small_int, 0); // level 0 for __import__ + EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple #if MICROPY_EMIT_CPYTHON @@ -1324,12 +1393,12 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { #endif // do the import - qstr dummy_q, id1; - do_import_name(comp, pns->nodes[0], &dummy_q, &id1); + qstr dummy_q; + do_import_name(comp, pn_import_source, &dummy_q); EMIT(import_star); } else { - EMIT_ARG(load_const_small_int, 0); // level 0 for __import__ + EMIT_ARG(load_const_small_int, import_level); // build the "fromlist" tuple mp_parse_node_t *pn_nodes; @@ -1369,8 +1438,8 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { #endif // do the import - qstr dummy_q, id1; - do_import_name(comp, pns->nodes[0], &dummy_q, &id1); + qstr dummy_q; + do_import_name(comp, pn_import_source, &dummy_q); for (int i = 0; i < n; i++) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name)); mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i]; @@ -1415,7 +1484,7 @@ void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { - int l_end = comp_next_label(comp); + uint l_end = comp_next_label(comp); c_if_cond(comp, pns->nodes[0], true, l_end); EMIT_ARG(load_global, MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { @@ -1430,9 +1499,9 @@ void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // TODO proper and/or short circuiting - int l_end = comp_next_label(comp); + uint l_end = comp_next_label(comp); - int l_fail = comp_next_label(comp); + uint l_fail = comp_next_label(comp); c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition compile_node(comp, pns->nodes[1]); // if block @@ -1493,10 +1562,10 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } #define START_BREAK_CONTINUE_BLOCK \ - int old_break_label = comp->break_label; \ - int old_continue_label = comp->continue_label; \ - int break_label = comp_next_label(comp); \ - int continue_label = comp_next_label(comp); \ + uint old_break_label = comp->break_label; \ + uint old_continue_label = comp->continue_label; \ + uint break_label = comp_next_label(comp); \ + uint continue_label = comp_next_label(comp); \ comp->break_label = break_label; \ comp->continue_label = continue_label; \ comp->break_continue_except_level = comp->cur_except_level; @@ -1511,7 +1580,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // compared to CPython, we have an optimised version of while loops #if MICROPY_EMIT_CPYTHON - int done_label = comp_next_label(comp); + uint done_label = comp_next_label(comp); EMIT_ARG(setup_loop, break_label); EMIT_ARG(label_assign, continue_label); c_if_cond(comp, pns->nodes[0], false, done_label); // condition @@ -1526,7 +1595,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { EMIT(pop_block); } #else - int top_label = comp_next_label(comp); + uint top_label = comp_next_label(comp); EMIT_ARG(jump, continue_label); EMIT_ARG(label_assign, top_label); compile_node(comp, pns->nodes[1]); // body @@ -1548,8 +1617,8 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) { START_BREAK_CONTINUE_BLOCK - int top_label = comp_next_label(comp); - int entry_label = comp_next_label(comp); + uint top_label = comp_next_label(comp); + uint entry_label = comp_next_label(comp); // compile: start, duplicated on stack compile_node(comp, pn_start); @@ -1559,7 +1628,7 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, EMIT_ARG(label_assign, top_label); // at this point we actually have 1 less element on the stack - EMIT_ARG(set_stack_size, EMIT(get_stack_size) - 1); + EMIT_ARG(adjust_stack_size, -1); // store next value to var c_assign(comp, pn_var, ASSIGN_STORE); @@ -1646,8 +1715,8 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { START_BREAK_CONTINUE_BLOCK - int pop_label = comp_next_label(comp); - int end_label = comp_next_label(comp); + uint pop_label = comp_next_label(comp); + uint end_label = comp_next_label(comp); // I don't think our implementation needs SETUP_LOOP/POP_BLOCK for for-statements #if MICROPY_EMIT_CPYTHON @@ -1680,29 +1749,28 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) { - // this function is a bit of a hack at the moment - // don't understand how the stack works with exceptions, so we force it to return to the correct value - // setup code - int stack_size = EMIT(get_stack_size); - int l1 = comp_next_label(comp); - int success_label = comp_next_label(comp); + uint l1 = comp_next_label(comp); + uint success_label = comp_next_label(comp); EMIT_ARG(setup_except, l1); compile_increase_except_level(comp); compile_node(comp, pn_body); // body EMIT(pop_block); - EMIT_ARG(jump, success_label); - EMIT_ARG(label_assign, l1); - int l2 = comp_next_label(comp); + EMIT_ARG(jump, success_label); // jump over exception handler + + EMIT_ARG(label_assign, l1); // start of exception handler + EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state + + uint l2 = comp_next_label(comp); for (int i = 0; i < n_except; i++) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_excepts[i], PN_try_stmt_except)); // should be mp_parse_node_struct_t *pns_except = (mp_parse_node_struct_t*)pn_excepts[i]; qstr qstr_exception_local = 0; - int end_finally_label = comp_next_label(comp); + uint end_finally_label = comp_next_label(comp); if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) { // this is a catch all exception handler @@ -1737,7 +1805,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, EMIT(pop_top); - int l3 = 0; + uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); EMIT_ARG(setup_finally, l3); @@ -1760,28 +1828,29 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, } EMIT_ARG(jump, l2); EMIT_ARG(label_assign, end_finally_label); + EMIT_ARG(adjust_stack_size, 3); // stack adjust for the 3 exception items } compile_decrease_except_level(comp); EMIT(end_finally); + EMIT_ARG(adjust_stack_size, -5); // stack adjust EMIT_ARG(label_assign, success_label); compile_node(comp, pn_else); // else block, can be null EMIT_ARG(label_assign, l2); - EMIT_ARG(set_stack_size, stack_size); } void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) { - // don't understand how the stack works with exceptions, so we force it to return to the correct value - int stack_size = EMIT(get_stack_size); - int l_finally_block = comp_next_label(comp); + uint l_finally_block = comp_next_label(comp); EMIT_ARG(setup_finally, l_finally_block); compile_increase_except_level(comp); if (n_except == 0) { assert(MP_PARSE_NODE_IS_NULL(pn_else)); + EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state compile_node(comp, pn_body); + EMIT_ARG(adjust_stack_size, -3); } else { compile_try_except(comp, pn_body, n_except, pn_except, pn_else); } @@ -1792,8 +1861,6 @@ void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except compile_decrease_except_level(comp); EMIT(end_finally); - - EMIT_ARG(set_stack_size, stack_size); } void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -1830,7 +1897,7 @@ void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, m // no more pre-bits, compile the body of the with compile_node(comp, body); } else { - int l_end = comp_next_label(comp); + uint l_end = comp_next_label(comp); if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) { // this pre-bit is of the form "a as b" mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; @@ -1987,14 +2054,13 @@ void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else)); mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns->nodes[1]; - int stack_size = EMIT(get_stack_size); - int l_fail = comp_next_label(comp); - int l_end = comp_next_label(comp); + uint l_fail = comp_next_label(comp); + uint l_end = comp_next_label(comp); c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition compile_node(comp, pns->nodes[0]); // success value EMIT_ARG(jump, l_end); EMIT_ARG(label_assign, l_fail); - EMIT_ARG(set_stack_size, stack_size); // force stack size reset + EMIT_ARG(adjust_stack_size, -1); // adjust stack size compile_node(comp, pns_test_if_else->nodes[1]); // failure value EMIT_ARG(label_assign, l_end); } @@ -2019,7 +2085,7 @@ void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) { - int l_end = comp_next_label(comp); + uint l_end = comp_next_label(comp); int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < n; i += 1) { compile_node(comp, pns->nodes[i]); @@ -2031,7 +2097,7 @@ void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { - int l_end = comp_next_label(comp); + uint l_end = comp_next_label(comp); int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < n; i += 1) { compile_node(comp, pns->nodes[i]); @@ -2048,11 +2114,10 @@ void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { - int stack_size = EMIT(get_stack_size); int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); compile_node(comp, pns->nodes[0]); bool multi = (num_nodes > 3); - int l_fail = 0; + uint l_fail = 0; if (multi) { l_fail = comp_next_label(comp); } @@ -2099,13 +2164,13 @@ void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { } } if (multi) { - int l_end = comp_next_label(comp); + uint l_end = comp_next_label(comp); EMIT_ARG(jump, l_end); EMIT_ARG(label_assign, l_fail); + EMIT_ARG(adjust_stack_size, 1); EMIT(rot_two); EMIT(pop_top); EMIT_ARG(label_assign, l_end); - EMIT_ARG(set_stack_size, stack_size + 1); // force stack size } } @@ -2799,8 +2864,8 @@ void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse // for loop mp_parse_node_struct_t *pns_comp_for2 = (mp_parse_node_struct_t*)pn_iter; compile_node(comp, pns_comp_for2->nodes[1]); - int l_end2 = comp_next_label(comp); - int l_top2 = comp_next_label(comp); + uint l_end2 = comp_next_label(comp); + uint l_top2 = comp_next_label(comp); EMIT(get_iter); EMIT_ARG(label_assign, l_top2); EMIT_ARG(for_iter, l_end2); @@ -2946,8 +3011,8 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { EMIT_ARG(build_set, 0); } - int l_end = comp_next_label(comp); - int l_top = comp_next_label(comp); + uint l_end = comp_next_label(comp); + uint l_top = comp_next_label(comp); EMIT_ARG(load_id, qstr_arg); EMIT_ARG(label_assign, l_top); EMIT_ARG(for_iter, l_end); @@ -3066,7 +3131,7 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass compile_syntax_error(comp, nodes[i], "inline assembler 'label' requires 1 argument"); return; } - int lab = comp_next_label(comp); + uint lab = comp_next_label(comp); if (pass > PASS_1) { EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0])); } @@ -24,15 +24,14 @@ typedef struct _emit_method_table_t { void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope); void (*end_pass)(emit_t *emit); bool (*last_emit_was_return_value)(emit_t *emit); - int (*get_stack_size)(emit_t *emit); - void (*set_stack_size)(emit_t *emit, int size); + void (*adjust_stack_size)(emit_t *emit, int delta); void (*set_line_number)(emit_t *emit, int line); void (*load_id)(emit_t *emit, qstr qstr); void (*store_id)(emit_t *emit, qstr qstr); void (*delete_id)(emit_t *emit, qstr qstr); - void (*label_assign)(emit_t *emit, int l); + void (*label_assign)(emit_t *emit, uint l); void (*import_name)(emit_t *emit, qstr qstr); void (*import_from)(emit_t *emit, qstr qstr); void (*import_star)(emit_t *emit); @@ -68,21 +67,21 @@ typedef struct _emit_method_table_t { void (*pop_top)(emit_t *emit); void (*rot_two)(emit_t *emit); void (*rot_three)(emit_t *emit); - void (*jump)(emit_t *emit, int label); - void (*pop_jump_if_true)(emit_t *emit, int label); - void (*pop_jump_if_false)(emit_t *emit, int label); - void (*jump_if_true_or_pop)(emit_t *emit, int label); - void (*jump_if_false_or_pop)(emit_t *emit, int label); - void (*setup_loop)(emit_t *emit, int label); - void (*break_loop)(emit_t *emit, int label, int except_depth); - void (*continue_loop)(emit_t *emit, int label, int except_depth); - void (*setup_with)(emit_t *emit, int label); + void (*jump)(emit_t *emit, uint label); + void (*pop_jump_if_true)(emit_t *emit, uint label); + void (*pop_jump_if_false)(emit_t *emit, uint label); + void (*jump_if_true_or_pop)(emit_t *emit, uint label); + void (*jump_if_false_or_pop)(emit_t *emit, uint label); + void (*setup_loop)(emit_t *emit, uint label); + void (*break_loop)(emit_t *emit, uint label, int except_depth); + void (*continue_loop)(emit_t *emit, uint label, int except_depth); + void (*setup_with)(emit_t *emit, uint label); void (*with_cleanup)(emit_t *emit); - void (*setup_except)(emit_t *emit, int label); - void (*setup_finally)(emit_t *emit, int label); + void (*setup_except)(emit_t *emit, uint label); + void (*setup_finally)(emit_t *emit, uint label); void (*end_finally)(emit_t *emit); void (*get_iter)(emit_t *emit); - void (*for_iter)(emit_t *emit, int label); + void (*for_iter)(emit_t *emit, uint label); void (*for_iter_end)(emit_t *emit); void (*pop_block)(emit_t *emit); void (*pop_except)(emit_t *emit); @@ -136,7 +135,7 @@ typedef struct _emit_inline_asm_method_table_t { void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope); void (*end_pass)(emit_inline_asm_t *emit); int (*count_params)(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params); - void (*label)(emit_inline_asm_t *emit, int label_num, qstr label_id); + void (*label)(emit_inline_asm_t *emit, uint label_num, qstr label_id); void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args); } emit_inline_asm_method_table_t; diff --git a/py/emitbc.c b/py/emitbc.c index 21d1a61863..fc3e5ed622 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -171,7 +171,7 @@ STATIC void emit_write_byte_code_byte_qstr(emit_t* emit, byte b, qstr qstr) { } // unsigned labels are relative to ip following this instruction, stored as 16 bits -STATIC void emit_write_byte_code_byte_unsigned_label(emit_t* emit, byte b1, int label) { +STATIC void emit_write_byte_code_byte_unsigned_label(emit_t* emit, byte b1, uint label) { uint byte_code_offset; if (emit->pass < PASS_3) { byte_code_offset = 0; @@ -185,7 +185,7 @@ STATIC void emit_write_byte_code_byte_unsigned_label(emit_t* emit, byte b1, int } // signed labels are relative to ip following this instruction, stored as 16 bits, in excess -STATIC void emit_write_byte_code_byte_signed_label(emit_t* emit, byte b1, int label) { +STATIC void emit_write_byte_code_byte_signed_label(emit_t* emit, byte b1, uint label) { int byte_code_offset; if (emit->pass < PASS_3) { byte_code_offset = 0; @@ -232,6 +232,12 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { { byte* c = emit_get_cur_to_write_byte_code(emit, 4); uint n_state = scope->num_locals + scope->stack_size; + if (n_state == 0) { + // Need at least 1 entry in the state, in the case an exception is + // propagated through this function, the exception is returned in + // the highest slot in the state (fastn[0], see vm.c). + n_state = 1; + } c[0] = n_state & 0xff; c[1] = (n_state >> 8) & 0xff; c[2] = scope->exc_stack_size & 0xff; @@ -282,16 +288,12 @@ STATIC void emit_bc_end_pass(emit_t *emit) { } } -bool emit_bc_last_emit_was_return_value(emit_t *emit) { +STATIC bool emit_bc_last_emit_was_return_value(emit_t *emit) { return emit->last_emit_was_return_value; } -int emit_bc_get_stack_size(emit_t *emit) { - return emit->stack_size; -} - -STATIC void emit_bc_set_stack_size(emit_t *emit, int size) { - emit->stack_size = size; +STATIC void emit_bc_adjust_stack_size(emit_t *emit, int delta) { + emit->stack_size += delta; } STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) { @@ -329,7 +331,7 @@ STATIC void emit_bc_pre(emit_t *emit, int stack_size_delta) { emit->last_emit_was_return_value = false; } -STATIC void emit_bc_label_assign(emit_t *emit, int l) { +STATIC void emit_bc_label_assign(emit_t *emit, uint l) { emit_bc_pre(emit, 0); assert(l < emit->max_num_labels); if (emit->pass == PASS_2) { @@ -551,37 +553,37 @@ STATIC void emit_bc_rot_three(emit_t *emit) { emit_write_byte_code_byte(emit, MP_BC_ROT_THREE); } -STATIC void emit_bc_jump(emit_t *emit, int label) { +STATIC void emit_bc_jump(emit_t *emit, uint label) { emit_bc_pre(emit, 0); emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP, label); } -STATIC void emit_bc_pop_jump_if_true(emit_t *emit, int label) { +STATIC void emit_bc_pop_jump_if_true(emit_t *emit, uint label) { emit_bc_pre(emit, -1); emit_write_byte_code_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label); } -STATIC void emit_bc_pop_jump_if_false(emit_t *emit, int label) { +STATIC void emit_bc_pop_jump_if_false(emit_t *emit, uint label) { emit_bc_pre(emit, -1); emit_write_byte_code_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label); } -STATIC void emit_bc_jump_if_true_or_pop(emit_t *emit, int label) { +STATIC void emit_bc_jump_if_true_or_pop(emit_t *emit, uint label) { emit_bc_pre(emit, -1); emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label); } -STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, int label) { +STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) { emit_bc_pre(emit, -1); emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label); } -STATIC void emit_bc_setup_loop(emit_t *emit, int label) { +STATIC void emit_bc_setup_loop(emit_t *emit, uint label) { emit_bc_pre(emit, 0); emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_LOOP, label); } -STATIC void emit_bc_unwind_jump(emit_t *emit, int label, int except_depth) { +STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) { if (except_depth == 0) { emit_bc_jump(emit, label); } else { @@ -591,7 +593,7 @@ STATIC void emit_bc_unwind_jump(emit_t *emit, int label, int except_depth) { } } -STATIC void emit_bc_setup_with(emit_t *emit, int label) { +STATIC void emit_bc_setup_with(emit_t *emit, uint label) { emit_bc_pre(emit, 7); emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label); } @@ -601,13 +603,13 @@ STATIC void emit_bc_with_cleanup(emit_t *emit) { emit_write_byte_code_byte(emit, MP_BC_WITH_CLEANUP); } -STATIC void emit_bc_setup_except(emit_t *emit, int label) { - emit_bc_pre(emit, 6); +STATIC void emit_bc_setup_except(emit_t *emit, uint label) { + emit_bc_pre(emit, 0); emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label); } -STATIC void emit_bc_setup_finally(emit_t *emit, int label) { - emit_bc_pre(emit, 6); +STATIC void emit_bc_setup_finally(emit_t *emit, uint label) { + emit_bc_pre(emit, 0); emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label); } @@ -621,7 +623,7 @@ STATIC void emit_bc_get_iter(emit_t *emit) { emit_write_byte_code_byte(emit, MP_BC_GET_ITER); } -STATIC void emit_bc_for_iter(emit_t *emit, int label) { +STATIC void emit_bc_for_iter(emit_t *emit, uint label) { emit_bc_pre(emit, 1); emit_write_byte_code_byte_unsigned_label(emit, MP_BC_FOR_ITER, label); } @@ -830,8 +832,7 @@ const emit_method_table_t emit_bc_method_table = { emit_bc_start_pass, emit_bc_end_pass, emit_bc_last_emit_was_return_value, - emit_bc_get_stack_size, - emit_bc_set_stack_size, + emit_bc_adjust_stack_size, emit_bc_set_source_line, emit_bc_load_id, diff --git a/py/emitcpy.c b/py/emitcpy.c index 8c608d6a2b..5866d474e9 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -60,12 +60,8 @@ STATIC bool emit_cpy_last_emit_was_return_value(emit_t *emit) { return emit->last_emit_was_return_value; } -STATIC int emit_cpy_get_stack_size(emit_t *emit) { - return emit->stack_size; -} - -STATIC void emit_cpy_set_stack_size(emit_t *emit, int size) { - emit->stack_size = size; +STATIC void emit_cpy_adjust_stack_size(emit_t *emit, int delta) { + emit->stack_size += delta; } STATIC void emit_cpy_set_source_line(emit_t *emit, int source_line) { @@ -100,7 +96,7 @@ static void emit_pre(emit_t *emit, int stack_size_delta, int byte_code_size) { emit->byte_code_offset += byte_code_size; } -STATIC void emit_cpy_label_assign(emit_t *emit, int l) { +STATIC void emit_cpy_label_assign(emit_t *emit, uint l) { emit_pre(emit, 0, 0); assert(l < emit->max_num_labels); if (emit->pass == PASS_2) { @@ -402,7 +398,7 @@ STATIC void emit_cpy_rot_three(emit_t *emit) { } } -STATIC void emit_cpy_jump(emit_t *emit, int label) { +STATIC void emit_cpy_jump(emit_t *emit, uint label) { emit_pre(emit, 0, 3); if (emit->pass == PASS_3) { int dest = emit->label_offsets[label]; @@ -414,49 +410,49 @@ STATIC void emit_cpy_jump(emit_t *emit, int label) { } } -STATIC void emit_cpy_pop_jump_if_true(emit_t *emit, int label) { +STATIC void emit_cpy_pop_jump_if_true(emit_t *emit, uint label) { emit_pre(emit, -1, 3); if (emit->pass == PASS_3) { printf("POP_JUMP_IF_TRUE %d\n", emit->label_offsets[label]); } } -STATIC void emit_cpy_pop_jump_if_false(emit_t *emit, int label) { +STATIC void emit_cpy_pop_jump_if_false(emit_t *emit, uint label) { emit_pre(emit, -1, 3); if (emit->pass == PASS_3) { printf("POP_JUMP_IF_FALSE %d\n", emit->label_offsets[label]); } } -STATIC void emit_cpy_jump_if_true_or_pop(emit_t *emit, int label) { +STATIC void emit_cpy_jump_if_true_or_pop(emit_t *emit, uint label) { emit_pre(emit, -1, 3); if (emit->pass == PASS_3) { printf("JUMP_IF_TRUE_OR_POP %d\n", emit->label_offsets[label]); } } -STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, int label) { +STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, uint label) { emit_pre(emit, -1, 3); if (emit->pass == PASS_3) { printf("JUMP_IF_FALSE_OR_POP %d\n", emit->label_offsets[label]); } } -STATIC void emit_cpy_setup_loop(emit_t *emit, int label) { +STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) { emit_pre(emit, 0, 3); if (emit->pass == PASS_3) { printf("SETUP_LOOP %d\n", emit->label_offsets[label]); } } -STATIC void emit_cpy_break_loop(emit_t *emit, int label, int except_depth) { +STATIC void emit_cpy_break_loop(emit_t *emit, uint label, int except_depth) { emit_pre(emit, 0, 1); if (emit->pass == PASS_3) { printf("BREAK_LOOP\n"); } } -STATIC void emit_cpy_continue_loop(emit_t *emit, int label, int except_depth) { +STATIC void emit_cpy_continue_loop(emit_t *emit, uint label, int except_depth) { if (except_depth == 0) { emit_cpy_jump(emit, label); } else { @@ -467,7 +463,7 @@ STATIC void emit_cpy_continue_loop(emit_t *emit, int label, int except_depth) { } } -STATIC void emit_cpy_setup_with(emit_t *emit, int label) { +STATIC void emit_cpy_setup_with(emit_t *emit, uint label) { emit_pre(emit, 7, 3); if (emit->pass == PASS_3) { printf("SETUP_WITH %d\n", emit->label_offsets[label]); @@ -481,15 +477,15 @@ STATIC void emit_cpy_with_cleanup(emit_t *emit) { } } -STATIC void emit_cpy_setup_except(emit_t *emit, int label) { - emit_pre(emit, 6, 3); +STATIC void emit_cpy_setup_except(emit_t *emit, uint label) { + emit_pre(emit, 0, 3); if (emit->pass == PASS_3) { printf("SETUP_EXCEPT %d\n", emit->label_offsets[label]); } } -STATIC void emit_cpy_setup_finally(emit_t *emit, int label) { - emit_pre(emit, 6, 3); +STATIC void emit_cpy_setup_finally(emit_t *emit, uint label) { + emit_pre(emit, 0, 3); if (emit->pass == PASS_3) { printf("SETUP_FINALLY %d\n", emit->label_offsets[label]); } @@ -509,7 +505,7 @@ STATIC void emit_cpy_get_iter(emit_t *emit) { } } -STATIC void emit_cpy_for_iter(emit_t *emit, int label) { +STATIC void emit_cpy_for_iter(emit_t *emit, uint label) { emit_pre(emit, 1, 3); if (emit->pass == PASS_3) { printf("FOR_ITER %d\n", emit->label_offsets[label]); @@ -793,8 +789,7 @@ const emit_method_table_t emit_cpython_method_table = { emit_cpy_start_pass, emit_cpy_end_pass, emit_cpy_last_emit_was_return_value, - emit_cpy_get_stack_size, - emit_cpy_set_stack_size, + emit_cpy_adjust_stack_size, emit_cpy_set_source_line, emit_cpy_load_id, diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index c5136ab371..db1525672f 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -75,7 +75,7 @@ STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, return n_params; } -STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, int label_num, qstr label_id) { +STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, uint label_num, qstr label_id) { assert(label_num < emit->max_num_labels); emit->label_lookup[label_num] = label_id; asm_thumb_label_assign(emit->as, label_num); diff --git a/py/emitnative.c b/py/emitnative.c index e96b12271a..d2a3df25dd 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -295,12 +295,8 @@ STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) { return emit->last_emit_was_return_value; } -STATIC int emit_native_get_stack_size(emit_t *emit) { - return emit->stack_size; -} - -STATIC void emit_native_set_stack_size(emit_t *emit, int size) { - emit->stack_size = size; +STATIC void emit_native_adjust_stack_size(emit_t *emit, int delta) { + emit->stack_size += delta; } STATIC void emit_native_set_source_line(emit_t *emit, int source_line) { @@ -585,7 +581,7 @@ STATIC void emit_native_delete_id(emit_t *emit, qstr qstr) { emit_common_delete_id(emit, &EXPORT_FUN(method_table), emit->scope, qstr); } -STATIC void emit_native_label_assign(emit_t *emit, int l) { +STATIC void emit_native_label_assign(emit_t *emit, uint l) { emit_native_pre(emit); // need to commit stack because we can jump here from elsewhere need_stack_settled(emit); @@ -920,7 +916,7 @@ STATIC void emit_native_rot_three(emit_t *emit) { emit_post_push_reg_reg_reg(emit, vtype0, REG_TEMP0, vtype2, REG_TEMP2, vtype1, REG_TEMP1); } -STATIC void emit_native_jump(emit_t *emit, int label) { +STATIC void emit_native_jump(emit_t *emit, uint label) { emit_native_pre(emit); #if N_X64 asm_x64_jmp_label(emit->as, label); @@ -930,7 +926,7 @@ STATIC void emit_native_jump(emit_t *emit, int label) { emit_post(emit); } -STATIC void emit_native_pop_jump_pre_helper(emit_t *emit, int label) { +STATIC void emit_native_pop_jump_pre_helper(emit_t *emit, uint label) { vtype_kind_t vtype = peek_vtype(emit); if (vtype == VTYPE_BOOL) { emit_pre_pop_reg(emit, &vtype, REG_RET); @@ -943,7 +939,7 @@ STATIC void emit_native_pop_jump_pre_helper(emit_t *emit, int label) { } } -STATIC void emit_native_pop_jump_if_false(emit_t *emit, int label) { +STATIC void emit_native_pop_jump_if_false(emit_t *emit, uint label) { emit_native_pop_jump_pre_helper(emit, label); #if N_X64 asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET); @@ -955,7 +951,7 @@ STATIC void emit_native_pop_jump_if_false(emit_t *emit, int label) { emit_post(emit); } -STATIC void emit_native_pop_jump_if_true(emit_t *emit, int label) { +STATIC void emit_native_pop_jump_if_true(emit_t *emit, uint label) { emit_native_pop_jump_pre_helper(emit, label); #if N_X64 asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET); @@ -967,35 +963,35 @@ STATIC void emit_native_pop_jump_if_true(emit_t *emit, int label) { emit_post(emit); } -STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, int label) { +STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, uint label) { assert(0); } -STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, int label) { +STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) { assert(0); } -STATIC void emit_native_setup_loop(emit_t *emit, int label) { +STATIC void emit_native_setup_loop(emit_t *emit, uint label) { emit_native_pre(emit); emit_post(emit); } -STATIC void emit_native_break_loop(emit_t *emit, int label, int except_depth) { +STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) { emit_native_jump(emit, label); // TODO properly } -STATIC void emit_native_continue_loop(emit_t *emit, int label, int except_depth) { +STATIC void emit_native_continue_loop(emit_t *emit, uint label, int except_depth) { assert(0); } -STATIC void emit_native_setup_with(emit_t *emit, int label) { +STATIC void emit_native_setup_with(emit_t *emit, uint label) { // not supported, or could be with runtime call assert(0); } STATIC void emit_native_with_cleanup(emit_t *emit) { assert(0); } -STATIC void emit_native_setup_except(emit_t *emit, int label) { +STATIC void emit_native_setup_except(emit_t *emit, uint label) { assert(0); } -STATIC void emit_native_setup_finally(emit_t *emit, int label) { +STATIC void emit_native_setup_finally(emit_t *emit, uint label) { assert(0); } STATIC void emit_native_end_finally(emit_t *emit) { @@ -1013,7 +1009,7 @@ STATIC void emit_native_get_iter(emit_t *emit) { emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } -STATIC void emit_native_for_iter(emit_t *emit, int label) { +STATIC void emit_native_for_iter(emit_t *emit, uint label) { emit_native_pre(emit); vtype_kind_t vtype; emit_access_stack(emit, 1, &vtype, REG_ARG_1); @@ -1304,8 +1300,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_start_pass, emit_native_end_pass, emit_native_last_emit_was_return_value, - emit_native_get_stack_size, - emit_native_set_stack_size, + emit_native_adjust_stack_size, emit_native_set_source_line, emit_native_load_id, diff --git a/py/emitpass1.c b/py/emitpass1.c index 6088489410..301c04ebea 100644 --- a/py/emitpass1.c +++ b/py/emitpass1.c @@ -35,6 +35,10 @@ STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope STATIC void emit_pass1_end_pass(emit_t *emit) { } +STATIC bool emit_pass1_last_emit_was_return_value(emit_t *emit) { + return false; +} + STATIC void emit_pass1_load_id(emit_t *emit, qstr qstr) { // name adding/lookup bool added; @@ -99,8 +103,7 @@ const emit_method_table_t emit_pass1_method_table = { (void*)emit_pass1_dummy, emit_pass1_start_pass, emit_pass1_end_pass, - (void*)emit_pass1_dummy, - (void*)emit_pass1_dummy, + emit_pass1_last_emit_was_return_value, (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, diff --git a/py/lexer.c b/py/lexer.c index 58d54b6980..03605373d0 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -218,8 +218,7 @@ STATIC const char *tok_enc = "%e=" // % %= "^e=" // ^ ^= "=e=" // = == - "!E=" // != - ".c.E."; // . ... + "!E="; // != // TODO static assert that number of tokens is less than 256 so we can safely make this table with byte sized entries STATIC const uint8_t tok_enc_kind[] = { @@ -240,7 +239,6 @@ STATIC const uint8_t tok_enc_kind[] = { MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL, MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL, MP_TOKEN_OP_NOT_EQUAL, - MP_TOKEN_DEL_PERIOD, MP_TOKEN_ELLIPSIS, }; // must have the same order as enum in lexer.h @@ -455,50 +453,55 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs vstr_add_char(&lex->vstr, CUR_CHAR(lex)); } else { n_closing = 0; - if (!is_raw && is_char(lex, '\\')) { + if (is_char(lex, '\\')) { next_char(lex); unichar c = CUR_CHAR(lex); - switch (c) { - case MP_LEXER_CHAR_EOF: break; // TODO a proper error message? - case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it - case '\\': break; - case '\'': break; - case '"': break; - case 'a': c = 0x07; break; - case 'b': c = 0x08; break; - case 't': c = 0x09; break; - case 'n': c = 0x0a; break; - case 'v': c = 0x0b; break; - case 'f': c = 0x0c; break; - case 'r': c = 0x0d; break; - case 'x': - { - uint num = 0; - if (!get_hex(lex, 2, &num)) { - // TODO error message - assert(0); - } - c = num; - break; - } - case 'N': break; // TODO \N{name} only in strings - case 'u': break; // TODO \uxxxx only in strings - case 'U': break; // TODO \Uxxxxxxxx only in strings - default: - if (c >= '0' && c <= '7') { - // Octal sequence, 1-3 chars - int digits = 3; - int num = c - '0'; - while (is_following_odigit(lex) && --digits != 0) { - next_char(lex); - num = num * 8 + (CUR_CHAR(lex) - '0'); + if (is_raw) { + // raw strings allow escaping of quotes, but the backslash is also emitted + vstr_add_char(&lex->vstr, '\\'); + } else { + switch (c) { + case MP_LEXER_CHAR_EOF: break; // TODO a proper error message? + case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it + case '\\': break; + case '\'': break; + case '"': break; + case 'a': c = 0x07; break; + case 'b': c = 0x08; break; + case 't': c = 0x09; break; + case 'n': c = 0x0a; break; + case 'v': c = 0x0b; break; + case 'f': c = 0x0c; break; + case 'r': c = 0x0d; break; + case 'x': + { + uint num = 0; + if (!get_hex(lex, 2, &num)) { + // TODO error message + assert(0); } c = num; - } else { - // unrecognised escape character; CPython lets this through verbatim as '\' and then the character - vstr_add_char(&lex->vstr, '\\'); + break; } - break; + case 'N': break; // TODO \N{name} only in strings + case 'u': break; // TODO \uxxxx only in strings + case 'U': break; // TODO \Uxxxxxxxx only in strings + default: + if (c >= '0' && c <= '7') { + // Octal sequence, 1-3 chars + int digits = 3; + int num = c - '0'; + while (is_following_odigit(lex) && --digits != 0) { + next_char(lex); + num = num * 8 + (CUR_CHAR(lex) - '0'); + } + c = num; + } else { + // unrecognised escape character; CPython lets this through verbatim as '\' and then the character + vstr_add_char(&lex->vstr, '\\'); + } + break; + } } if (c != MP_LEXER_CHAR_EOF) { vstr_add_char(&lex->vstr, c); @@ -555,6 +558,23 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs } } + } else if (is_char(lex, '.')) { + // special handling for . and ... operators, because .. is not a valid operator + + // get first char + vstr_add_char(&lex->vstr, '.'); + next_char(lex); + + if (is_char_and(lex, '.', '.')) { + vstr_add_char(&lex->vstr, '.'); + vstr_add_char(&lex->vstr, '.'); + next_char(lex); + next_char(lex); + tok->kind = MP_TOKEN_ELLIPSIS; + } else { + tok->kind = MP_TOKEN_DEL_PERIOD; + } + } else { // search for encoded delimiter or operator @@ -600,6 +620,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs tok_enc_index = t_index; } else { tok->kind = MP_TOKEN_INVALID; + goto tok_enc_no_match; } break; } @@ -622,6 +643,8 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs // set token kind tok->kind = tok_enc_kind[tok_enc_index]; + tok_enc_no_match: + // compute bracket level for implicit line joining if (tok->kind == MP_TOKEN_DEL_PAREN_OPEN || tok->kind == MP_TOKEN_DEL_BRACKET_OPEN || tok->kind == MP_TOKEN_DEL_BRACE_OPEN) { lex->nested_bracket_level += 1; diff --git a/py/lexerunix.c b/py/lexerunix.c index 73d30f2476..52fbe740ae 100644 --- a/py/lexerunix.c +++ b/py/lexerunix.c @@ -13,23 +13,45 @@ #include <sys/stat.h> #include <sys/types.h> -mp_lexer_t *mp_lexer_new_from_file(const char *filename) { - int fd = open(filename, O_RDONLY); - if (fd < 0) { - return NULL; +typedef struct _mp_lexer_file_buf_t { + int fd; + char buf[20]; + uint len; + uint pos; +} mp_lexer_file_buf_t; + +STATIC unichar file_buf_next_char(mp_lexer_file_buf_t *fb) { + if (fb->pos >= fb->len) { + if (fb->len < sizeof(fb->buf)) { + return MP_LEXER_CHAR_EOF; + } else { + int n = read(fb->fd, fb->buf, sizeof(fb->buf)); + if (n <= 0) { + return MP_LEXER_CHAR_EOF; + } + fb->len = n; + fb->pos = 0; + } } - uint size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - char *data = m_new(char, size); - int read_size = read(fd, data, size); - close(fd); - if (read_size != size) { - printf("error reading file %s\n", filename); - m_del(char, data, size); + return fb->buf[fb->pos++]; +} + +STATIC void file_buf_close(mp_lexer_file_buf_t *fb) { + close(fb->fd); + m_del_obj(mp_lexer_file_buf_t, fb); +} + +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { + mp_lexer_file_buf_t *fb = m_new_obj(mp_lexer_file_buf_t); + fb->fd = open(filename, O_RDONLY); + if (fb->fd < 0) { + m_del_obj(mp_lexer_file_buf_t, fb); return NULL; } - - return mp_lexer_new_from_str_len(qstr_from_str(filename), data, size, size); + int n = read(fb->fd, fb->buf, sizeof(fb->buf)); + fb->len = n; + fb->pos = 0; + return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close); } #endif // MICROPY_ENABLE_LEXER_UNIX diff --git a/py/malloc.c b/py/malloc.c index 45e939b6c2..db2578d9ad 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -53,6 +53,20 @@ void *m_malloc(int num_bytes) { return ptr; } +void *m_malloc_maybe(int num_bytes) { + void *ptr = malloc(num_bytes); + if (ptr == NULL) { + return NULL; + } +#if MICROPY_MEM_STATS + total_bytes_allocated += num_bytes; + current_bytes_allocated += num_bytes; + UPDATE_PEAK(); +#endif + DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); + return ptr; +} + #if MICROPY_ENABLE_FINALISER void *m_malloc_with_finaliser(int num_bytes) { if (num_bytes == 0) { @@ -104,6 +118,26 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) { return new_ptr; } +void *m_realloc_maybe(void *ptr, int old_num_bytes, int new_num_bytes) { + void *new_ptr = realloc(ptr, new_num_bytes); + if (new_ptr == NULL) { + return NULL; + } +#if MICROPY_MEM_STATS + // At first thought, "Total bytes allocated" should only grow, + // after all, it's *total*. But consider for example 2K block + // shrunk to 1K and then grown to 2K again. It's still 2K + // allocated total. If we process only positive increments, + // we'll count 3K. + int diff = new_num_bytes - old_num_bytes; + total_bytes_allocated += diff; + current_bytes_allocated += diff; + UPDATE_PEAK(); +#endif + DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); + return new_ptr; +} + void m_free(void *ptr, int num_bytes) { if (ptr != NULL) { free(ptr); @@ -27,20 +27,24 @@ typedef unsigned int uint; #define m_new0(type, num) ((type*)(m_malloc0(sizeof(type) * (num)))) #define m_new_obj(type) (m_new(type, 1)) #define m_new_obj_var(obj_type, var_type, var_num) ((obj_type*)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num))) +#define m_new_obj_var_maybe(obj_type, var_type, var_num) ((obj_type*)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num))) #if MICROPY_ENABLE_FINALISER #define m_new_obj_with_finaliser(type) ((type*)(m_malloc_with_finaliser(sizeof(type)))) #else #define m_new_obj_with_finaliser(type) m_new_obj(type) #endif #define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) +#define m_renew_maybe(type, ptr, old_num, new_num) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) #define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num)) #define m_del_obj(type, ptr) (m_del(type, ptr, 1)) #define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num))) void *m_malloc(int num_bytes); +void *m_malloc_maybe(int num_bytes); void *m_malloc_with_finaliser(int num_bytes); void *m_malloc0(int num_bytes); void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes); +void *m_realloc_maybe(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); diff --git a/py/modstruct.c b/py/modstruct.c index b5110df1b7..23c2c903de 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -38,7 +38,7 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); assert(fmt_type == '<'); (void)fmt_type; - uint size; + machine_uint_t size; for (size = 0; *fmt; fmt++) { int sz = mp_binary_get_size(*fmt); // TODO diff --git a/py/mpconfig.h b/py/mpconfig.h index 1f2862ab0e..b120c4bb4a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -150,6 +150,11 @@ typedef double mp_float_t; #define MICROPY_EXTRA_BUILTIN_MODULES #endif +// Additional constant definitions for the compiler - see compile.c:mp_constants_table. +#ifndef MICROPY_EXTRA_CONSTANTS +#define MICROPY_EXTRA_CONSTANTS +#endif + /*****************************************************************************/ /* Miscellaneous settings */ @@ -429,11 +429,11 @@ typedef struct _mp_obj_float_t { mp_float_t value; } mp_obj_float_t; mp_float_t mp_obj_float_get(mp_obj_t self_in); -mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); +mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL // complex void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); -mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); +mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL #endif // tuple diff --git a/py/objcomplex.c b/py/objcomplex.c index 66f971da0e..23c67eb6e1 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -11,6 +11,8 @@ #if MICROPY_ENABLE_FLOAT +#include <math.h> + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #include "formatfloat.h" #endif @@ -176,6 +178,33 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im } break; + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_INPLACE_POWER: { + // z1**z2 = exp(z2*ln(z1)) + // = exp(z2*(ln(|z1|)+i*arg(z1))) + // = exp( (x2*ln1 - y2*arg1) + i*(y2*ln1 + x2*arg1) ) + // = exp(x3 + i*y3) + // = exp(x3)*(cos(y3) + i*sin(y3)) + mp_float_t abs1 = MICROPY_FLOAT_C_FUN(sqrt)(lhs_real*lhs_real + lhs_imag*lhs_imag); + if (abs1 == 0) { + if (rhs_imag == 0) { + lhs_real = 1; + rhs_real = 0; + } else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power")); + } + } else { + mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1); + mp_float_t arg1 = MICROPY_FLOAT_C_FUN(atan2)(lhs_imag, lhs_real); + mp_float_t x3 = rhs_real * ln1 - rhs_imag * arg1; + mp_float_t y3 = rhs_imag * ln1 + rhs_real * arg1; + mp_float_t exp_x3 = MICROPY_FLOAT_C_FUN(exp)(x3); + lhs_real = exp_x3 * MICROPY_FLOAT_C_FUN(cos)(y3); + lhs_imag = exp_x3 * MICROPY_FLOAT_C_FUN(sin)(y3); + } + break; + } + default: return MP_OBJ_NULL; // op not supported } diff --git a/py/objexcept.c b/py/objexcept.c index 51e7a2615a..781a00405c 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -20,6 +20,9 @@ typedef struct _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}}; +// Local non-heap memory for allocating an exception when we run out of RAM +STATIC mp_obj_exception_t mp_emergency_exception_obj; + // 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. @@ -51,7 +54,13 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_ 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); + mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, n_args); + if (o == NULL) { + // Couldn't allocate heap memory; use local data instead. + o = &mp_emergency_exception_obj; + // We can't store any args. + n_args = 0; + } o->base.type = type; o->traceback = MP_OBJ_NULL; o->args.base.type = &mp_type_tuple; @@ -196,25 +205,35 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char assert(exc_type->make_new == mp_obj_exception_make_new); // make exception object - mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, 1); - o->base.type = exc_type; - o->traceback = MP_OBJ_NULL; - o->args.base.type = &mp_type_tuple; - o->args.len = 1; - - if (fmt == NULL) { - // no message - assert(0); + mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 1); + if (o == NULL) { + // Couldn't allocate heap memory; use local data instead. + // Unfortunately, we won't be able to format the string... + o = &mp_emergency_exception_obj; + o->base.type = exc_type; + o->traceback = MP_OBJ_NULL; + o->args.base.type = &mp_type_tuple; + o->args.len = 0; } else { - // render exception message and store as .args[0] - // TODO: optimize bufferbloat - vstr_t *vstr = vstr_new(); - va_list ap; - va_start(ap, fmt); - vstr_vprintf(vstr, fmt, ap); - va_end(ap); - o->args.items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); - vstr_free(vstr); + o->base.type = exc_type; + o->traceback = MP_OBJ_NULL; + o->args.base.type = &mp_type_tuple; + o->args.len = 1; + + if (fmt == NULL) { + // no message + assert(0); + } else { + // render exception message and store as .args[0] + // TODO: optimize bufferbloat + vstr_t *vstr = vstr_new(); + va_list ap; + va_start(ap, fmt); + vstr_vprintf(vstr, fmt, ap); + va_end(ap); + o->args.items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); + vstr_free(vstr); + } } return o; @@ -259,7 +278,7 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) { void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) { // make sure self_in is an exception instance // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that) - if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new) { + if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new && self_in != &mp_emergency_exception_obj) { mp_obj_exception_t *self = self_in; // for traceback, we are just using the list object for convenience, it's not really a list of Python objects diff --git a/py/objfloat.c b/py/objfloat.c index 8ccba1024c..1f96ac18e5 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -136,7 +136,7 @@ check_zero_division: case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); default: - return NULL; // op not supported + return MP_OBJ_NULL; // op not supported } return mp_obj_new_float(lhs_val); } diff --git a/py/objfun.c b/py/objfun.c index 0b0df3ba4d..adf05ce404 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -211,9 +211,13 @@ arg_error: } STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { - DEBUG_printf("Input: "); + DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw); + DEBUG_printf("Input pos args: "); dump_args(args, n_args); + DEBUG_printf("Input kw args: "); + dump_args(args + n_args, n_kw * 2); mp_obj_fun_bc_t *self = self_in; + DEBUG_printf("Func n_def_args: %d\n", self->n_def_args); const mp_obj_t *kwargs = args + n_args; mp_obj_t *extra_args = self->extra_args + self->n_def_args; @@ -295,9 +299,9 @@ continue2:; // Now fill in defaults mp_obj_t *d = &flat_args[self->n_args - 1]; mp_obj_t *s = &self->extra_args[self->n_def_args - 1]; - for (int i = self->n_def_args; i > 0; i--) { + for (int i = self->n_def_args; i > 0; i--, d--, s--) { if (*d == MP_OBJ_NULL) { - *d-- = *s--; + *d = *s; } } DEBUG_printf("Args after filling defaults: "); diff --git a/py/parse.c b/py/parse.c index 1381f1293d..6c899ce56d 100644 --- a/py/parse.c +++ b/py/parse.c @@ -86,6 +86,8 @@ typedef struct _rule_stack_t { } rule_stack_t; typedef struct _parser_t { + bool had_memory_error; + uint rule_stack_alloc; uint rule_stack_top; rule_stack_t *rule_stack; @@ -97,9 +99,21 @@ typedef struct _parser_t { mp_lexer_t *lexer; } parser_t; +STATIC inline void memory_error(parser_t *parser) { + parser->had_memory_error = true; +} + STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int arg_i) { + if (parser->had_memory_error) { + return; + } if (parser->rule_stack_top >= parser->rule_stack_alloc) { - parser->rule_stack = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc * 2); + rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc * 2); + if (rs == NULL) { + memory_error(parser); + return; + } + parser->rule_stack = rs; parser->rule_stack_alloc *= 2; } rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; @@ -116,6 +130,7 @@ STATIC void push_rule_from_arg(parser_t *parser, uint arg) { } STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *src_line) { + assert(!parser->had_memory_error); parser->rule_stack_top -= 1; *rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id]; *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i; @@ -129,15 +144,6 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) { return (mp_parse_node_t)(kind | (arg << 5)); } -//int num_parse_nodes_allocated = 0; -mp_parse_node_struct_t *parse_node_new_struct(int src_line, int rule_id, int num_args) { - mp_parse_node_struct_t *pn = m_new_obj_var(mp_parse_node_struct_t, mp_parse_node_t, num_args); - pn->source_line = src_line; - pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8); - //num_parse_nodes_allocated += 1; - return pn; -} - uint mp_parse_node_free(mp_parse_node_t pn) { uint cnt = 0; if (MP_PARSE_NODE_IS_STRUCT(pn)) { @@ -211,18 +217,32 @@ STATIC void result_stack_show(parser_t *parser) { */ STATIC mp_parse_node_t pop_result(parser_t *parser) { + if (parser->had_memory_error) { + return MP_PARSE_NODE_NULL; + } assert(parser->result_stack_top > 0); return parser->result_stack[--parser->result_stack_top]; } STATIC mp_parse_node_t peek_result(parser_t *parser, int pos) { + if (parser->had_memory_error) { + return MP_PARSE_NODE_NULL; + } assert(parser->result_stack_top > pos); return parser->result_stack[parser->result_stack_top - 1 - pos]; } STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) { + if (parser->had_memory_error) { + return; + } if (parser->result_stack_top >= parser->result_stack_alloc) { - parser->result_stack = m_renew(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc * 2); + mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc * 2); + if (pn == NULL) { + memory_error(parser); + return; + } + parser->result_stack = pn; parser->result_stack_alloc *= 2; } parser->result_stack[parser->result_stack_top++] = pn; @@ -283,7 +303,13 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) { } STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule, int num_args) { - mp_parse_node_struct_t *pn = parse_node_new_struct(src_line, rule->rule_id, num_args); + mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, num_args); + if (pn == NULL) { + memory_error(parser); + return; + } + pn->source_line = src_line; + pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8); for (int i = num_args; i > 0; i--) { pn->nodes[i - 1] = pop_result(parser); } @@ -296,6 +322,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p parser_t *parser = m_new_obj(parser_t); + parser->had_memory_error = false; + parser->rule_stack_alloc = 64; parser->rule_stack_top = 0; parser->rule_stack = m_new(rule_stack_t, parser->rule_stack_alloc); @@ -327,7 +355,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p for (;;) { next_rule: - if (parser->rule_stack_top == 0) { + if (parser->rule_stack_top == 0 || parser->had_memory_error) { break; } @@ -596,6 +624,16 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p } } + mp_parse_node_t result; + + // check if we had a memory error + if (parser->had_memory_error) { + *parse_error_kind_out = MP_PARSE_ERROR_MEMORY; + result = MP_PARSE_NODE_NULL; + goto finished; + + } + // check we are at the end of the token stream if (!mp_lexer_is_kind(lex, MP_TOKEN_END)) { goto syntax_error; @@ -609,7 +647,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p // get the root parse node that we created assert(parser->result_stack_top == 1); - mp_parse_node_t result = parser->result_stack[0]; + result = parser->result_stack[0]; finished: // free the memory that we don't need anymore diff --git a/py/parse.h b/py/parse.h index 135de47d13..29bcf36e72 100644 --- a/py/parse.h +++ b/py/parse.h @@ -67,6 +67,7 @@ typedef enum { } mp_parse_input_kind_t; typedef enum { + MP_PARSE_ERROR_MEMORY, MP_PARSE_ERROR_UNEXPECTED_INDENT, MP_PARSE_ERROR_UNMATCHED_UNINDENT, MP_PARSE_ERROR_INVALID_SYNTAX, diff --git a/py/parsehelper.c b/py/parsehelper.c index 3177e9a341..e069657b1d 100644 --- a/py/parsehelper.c +++ b/py/parsehelper.c @@ -11,6 +11,7 @@ #include "obj.h" #include "parsehelper.h" +#define STR_MEMORY "parser could not allocate enough memory" #define STR_UNEXPECTED_INDENT "unexpected indent" #define STR_UNMATCHED_UNINDENT "unindent does not match any outer indentation level" #define STR_INVALID_SYNTAX "invalid syntax" @@ -18,6 +19,10 @@ void mp_parse_show_exception(mp_lexer_t *lex, mp_parse_error_kind_t parse_error_kind) { printf(" File \"%s\", line %d, column %d\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column); switch (parse_error_kind) { + case MP_PARSE_ERROR_MEMORY: + printf("MemoryError: %s\n", STR_MEMORY); + break; + case MP_PARSE_ERROR_UNEXPECTED_INDENT: printf("IndentationError: %s\n", STR_UNEXPECTED_INDENT); break; @@ -36,6 +41,9 @@ void mp_parse_show_exception(mp_lexer_t *lex, mp_parse_error_kind_t parse_error_ mp_obj_t mp_parse_make_exception(mp_parse_error_kind_t parse_error_kind) { // TODO add source file and line number to exception? switch (parse_error_kind) { + case MP_PARSE_ERROR_MEMORY: + return mp_obj_new_exception_msg(&mp_type_MemoryError, STR_MEMORY); + case MP_PARSE_ERROR_UNEXPECTED_INDENT: return mp_obj_new_exception_msg(&mp_type_IndentationError, STR_UNEXPECTED_INDENT); diff --git a/py/runtime.c b/py/runtime.c index ef07e39bff..499905a0fa 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -386,9 +386,19 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } #if MICROPY_ENABLE_FLOAT } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_float)) { - return mp_obj_float_binary_op(op, lhs_val, rhs); + mp_obj_t res = mp_obj_float_binary_op(op, lhs_val, rhs); + if (res == MP_OBJ_NULL) { + goto unsupported_op; + } else { + return res; + } } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) { - return mp_obj_complex_binary_op(op, lhs_val, 0, rhs); + mp_obj_t res = mp_obj_complex_binary_op(op, lhs_val, 0, rhs); + if (res == MP_OBJ_NULL) { + goto unsupported_op; + } else { + return res; + } #endif } } @@ -438,6 +448,7 @@ generic_binary_op: // TODO implement dispatch for reverse binary ops // TODO specify in error message what the operator is +unsupported_op: 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))); diff --git a/py/unicode.c b/py/unicode.c index a20527cb2b..4bdf03387c 100644 --- a/py/unicode.c +++ b/py/unicode.c @@ -22,7 +22,7 @@ // table of attributes for ascii characters STATIC const uint8_t attr[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, AT_SP, AT_SP, AT_SP, 0, AT_SP, 0, 0, + 0, AT_SP, AT_SP, AT_SP, AT_SP, AT_SP, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, AT_SP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, @@ -12,6 +12,8 @@ #include "bc.h" #include "objgenerator.h" +#define DETECT_VM_STACK_OVERFLOW (0) + // Value stack grows up (this makes it incompatible with native C stack, but // makes sure that arguments to functions are in natural order arg1..argN // (Python semantics mandates left-to-right evaluation order, including for @@ -74,6 +76,9 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, // allocate state for locals and stack mp_obj_t temp_state[10]; mp_obj_t *state = &temp_state[0]; +#if DETECT_VM_STACK_OVERFLOW + n_state += 1; +#endif if (n_state > 10) { state = m_new(mp_obj_t, n_state); } @@ -109,6 +114,26 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, // execute the byte code mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2(code, &ip, &state[n_state - 1], &sp, exc_stack, &exc_sp, MP_OBJ_NULL); +#if DETECT_VM_STACK_OVERFLOW + // We can't check the case when an exception is returned in state[n_state - 1] + // and there are no arguments, because in this case our detection slot may have + // been overwritten by the returned exception (which is allowed). + if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_args == 0 && n_args2 == 0)) { + // Just check to see that we have at least 1 null object left in the state. + bool overflow = true; + for (uint i = 0; i < n_state - n_args - n_args2; i++) { + if (state[i] == MP_OBJ_NULL) { + overflow = false; + break; + } + } + if (overflow) { + printf("VM stack overflow state=%p n_state+1=%u\n", state, n_state); + assert(0); + } + } +#endif + switch (vm_return_kind) { case MP_VM_RETURN_NORMAL: *ret = *sp; @@ -166,6 +191,7 @@ outer_dispatch_loop: dispatch_loop: save_ip = ip; int op = *ip++; + //printf("ip=%p sp=%p op=%u\n", save_ip, sp, op); switch (op) { case MP_BC_LOAD_CONST_FALSE: PUSH(mp_const_false); diff --git a/stmhal/Makefile b/stmhal/Makefile index 064db23c35..9789189946 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -77,8 +77,9 @@ SRC_C = \ pyexec.c \ help.c \ input.c \ - modpyb.c \ modos.c \ + modpyb.c \ + modstm.c \ modtime.c \ import.c \ lexerfatfs.c \ diff --git a/stmhal/modstm.c b/stmhal/modstm.c new file mode 100644 index 0000000000..5e72a75bb2 --- /dev/null +++ b/stmhal/modstm.c @@ -0,0 +1,120 @@ +#include <stdio.h> +#include <stdint.h> + +#include <stm32f4xx_hal.h> + +#include "nlr.h" +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "modstm.h" + +STATIC uint32_t get_read_addr(mp_obj_t addr_o, uint align) { + uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff; + if (addr < 0x10000000) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot read from address %08x", addr)); + } + if ((addr & (align - 1)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); + } + return addr; +} + +STATIC uint32_t get_write_addr(mp_obj_t addr_o, uint align) { + uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff; + if (addr < 0x10000000) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot write to address %08x", addr)); + } + if ((addr & (align - 1)) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align)); + } + return addr; +} + +STATIC mp_obj_t stm_read8(mp_obj_t addr) { + uint32_t a = get_read_addr(addr, 1); + uint32_t v = *(uint8_t*)a; + return mp_obj_new_int(v); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read8_obj, stm_read8); + +STATIC mp_obj_t stm_read16(mp_obj_t addr) { + uint32_t a = get_read_addr(addr, 2); + uint32_t v = *(uint16_t*)a; + return mp_obj_new_int(v); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read16_obj, stm_read16); + +STATIC mp_obj_t stm_read32(mp_obj_t addr) { + uint32_t a = get_read_addr(addr, 4); + uint32_t v = *(uint32_t*)a; + return mp_obj_new_int(v); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read32_obj, stm_read32); + +STATIC mp_obj_t stm_write8(mp_obj_t addr, mp_obj_t val) { + uint32_t a = get_write_addr(addr, 1); + uint32_t v = mp_obj_get_int(val); + *(uint8_t*)a = v; + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write8_obj, stm_write8); + +STATIC mp_obj_t stm_write16(mp_obj_t addr, mp_obj_t val) { + uint32_t a = get_write_addr(addr, 2); + uint32_t v = mp_obj_get_int(val); + *(uint16_t*)a = v; + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write16_obj, stm_write16); + +STATIC mp_obj_t stm_write32(mp_obj_t addr, mp_obj_t val) { + uint32_t a = get_write_addr(addr, 4); + uint32_t v = mp_obj_get_int(val); + *(uint32_t*)a = v; + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write32_obj, stm_write32); + +STATIC const mp_map_elem_t stm_module_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_stm) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_read8), (mp_obj_t)&stm_read8_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_read16), (mp_obj_t)&stm_read16_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_read32), (mp_obj_t)&stm_read32_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write8), (mp_obj_t)&stm_write8_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write16), (mp_obj_t)&stm_write16_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write32), (mp_obj_t)&stm_write32_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOA), MP_OBJ_NEW_SMALL_INT(GPIOA_BASE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOB), MP_OBJ_NEW_SMALL_INT(GPIOB_BASE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOC), MP_OBJ_NEW_SMALL_INT(GPIOC_BASE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOD), MP_OBJ_NEW_SMALL_INT(GPIOD_BASE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_IDR), MP_OBJ_NEW_SMALL_INT(0x10) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_BSRRL), MP_OBJ_NEW_SMALL_INT(0x18) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_BSRRH), MP_OBJ_NEW_SMALL_INT(0x1a) }, +}; + +STATIC const mp_obj_dict_t stm_module_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(stm_module_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(stm_module_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)stm_module_globals_table, + }, +}; + +const mp_obj_module_t stm_module = { + .base = { &mp_type_module }, + .name = MP_QSTR_stm, + .globals = (mp_obj_dict_t*)&stm_module_globals, +}; diff --git a/stmhal/modstm.h b/stmhal/modstm.h new file mode 100644 index 0000000000..205cdd2a18 --- /dev/null +++ b/stmhal/modstm.h @@ -0,0 +1 @@ +extern const mp_obj_module_t stm_module; diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 08ba923e40..5529101425 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -31,12 +31,19 @@ extern const struct _mp_obj_fun_native_t mp_builtin_open_obj; // extra built in modules to add to the list of known ones extern const struct _mp_obj_module_t os_module; extern const struct _mp_obj_module_t pyb_module; +extern const struct _mp_obj_module_t stm_module; extern const struct _mp_obj_module_t time_module; #define MICROPY_EXTRA_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \ +// extra constants +#define MICROPY_EXTRA_CONSTANTS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \ + // type definitions for the specific machine #define BYTES_PER_WORD (4) diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 4eb6ea12a0..546b5b1430 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -130,3 +130,19 @@ Q(sleep) // for input Q(input) + +// for stm module +Q(stm) +Q(read8) +Q(read16) +Q(read32) +Q(write8) +Q(write16) +Q(write32) +Q(GPIOA) +Q(GPIOB) +Q(GPIOC) +Q(GPIOD) +Q(GPIO_IDR) +Q(GPIO_BSRRL) +Q(GPIO_BSRRH) diff --git a/tests/basics/compare-multi.py b/tests/basics/compare-multi.py new file mode 100644 index 0000000000..1abd18067d --- /dev/null +++ b/tests/basics/compare-multi.py @@ -0,0 +1,4 @@ +print(1 < 2 < 3) +print(1 < 2 < 3 < 4) +print(1 > 2 < 3) +print(1 < 2 > 3) diff --git a/tests/basics/fun-defargs2.py b/tests/basics/fun-defargs2.py index c9090a3cd2..8b72ed8b15 100644 --- a/tests/basics/fun-defargs2.py +++ b/tests/basics/fun-defargs2.py @@ -11,3 +11,9 @@ foo(1, b=333) # override with keyword foo(a=2, b=333) + +def foo2(a=1, b=2): + print(a, b) + +# default and keyword +foo2(b='two') diff --git a/unix/main.c b/unix/main.c index bcc5ffcd76..f18e40a7fa 100644 --- a/unix/main.c +++ b/unix/main.c @@ -29,7 +29,8 @@ #include <readline/history.h> #endif -// Default emit options +// Command line options, with their defaults +bool compile_only = false; uint emit_opt = MP_EMIT_OPT_NONE; #if MICROPY_ENABLE_GC @@ -87,6 +88,10 @@ STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind return; } + if (compile_only) { + return; + } + // execute it nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -226,6 +231,7 @@ int usage(char **argv) { ); int impl_opts_cnt = 0; printf( +" compile-only -- parse and compile only\n" " emit={bytecode,native,viper} -- set the default code emitter\n" ); impl_opts_cnt++; @@ -273,6 +279,8 @@ void pre_process_options(int argc, char **argv) { exit(usage(argv)); } if (0) { + } else if (strcmp(argv[a + 1], "compile-only") == 0) { + compile_only = true; } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) { emit_opt = MP_EMIT_OPT_BYTE_CODE; } else if (strcmp(argv[a + 1], "emit=native") == 0) { |