diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/bc0.h | 18 | ||||
-rw-r--r-- | py/builtintables.c | 2 | ||||
-rw-r--r-- | py/compile.c | 101 | ||||
-rw-r--r-- | py/compile.h | 1 | ||||
-rw-r--r-- | py/emit.h | 11 | ||||
-rw-r--r-- | py/emitbc.c | 55 | ||||
-rw-r--r-- | py/emitcommon.c | 2 | ||||
-rw-r--r-- | py/emitcpy.c | 18 | ||||
-rw-r--r-- | py/emitnative.c | 12 | ||||
-rw-r--r-- | py/emitpass1.c | 3 | ||||
-rw-r--r-- | py/gc.c | 2 | ||||
-rw-r--r-- | py/mpz.c | 5 | ||||
-rw-r--r-- | py/obj.c | 27 | ||||
-rw-r--r-- | py/obj.h | 15 | ||||
-rw-r--r-- | py/objarray.c | 36 | ||||
-rw-r--r-- | py/objarray.h | 2 | ||||
-rw-r--r-- | py/objcomplex.c | 38 | ||||
-rw-r--r-- | py/objdict.c | 9 | ||||
-rw-r--r-- | py/objgenerator.c | 23 | ||||
-rw-r--r-- | py/objint.c | 82 | ||||
-rw-r--r-- | py/objint.h | 2 | ||||
-rw-r--r-- | py/objint_longlong.c | 8 | ||||
-rw-r--r-- | py/objint_mpz.c | 26 | ||||
-rw-r--r-- | py/objlist.c | 12 | ||||
-rw-r--r-- | py/objmodule.c | 10 | ||||
-rw-r--r-- | py/objstr.c | 17 | ||||
-rw-r--r-- | py/objtype.c | 34 | ||||
-rw-r--r-- | py/pfenv.c | 75 | ||||
-rw-r--r-- | py/pfenv.h | 2 | ||||
-rw-r--r-- | py/qstrdefs.h | 2 | ||||
-rw-r--r-- | py/runtime.c | 47 | ||||
-rw-r--r-- | py/runtime.h | 2 | ||||
-rw-r--r-- | py/runtime0.h | 1 | ||||
-rw-r--r-- | py/scope.c | 21 | ||||
-rw-r--r-- | py/scope.h | 37 | ||||
-rw-r--r-- | py/showbc.c | 14 | ||||
-rw-r--r-- | py/vm.c | 46 |
37 files changed, 525 insertions, 293 deletions
@@ -17,12 +17,13 @@ #define MP_BC_LOAD_FAST_1 (0x21) #define MP_BC_LOAD_FAST_2 (0x22) #define MP_BC_LOAD_FAST_N (0x23) // uint -#define MP_BC_LOAD_DEREF (0x24) // uint -#define MP_BC_LOAD_NAME (0x25) // qstr -#define MP_BC_LOAD_GLOBAL (0x26) // qstr -#define MP_BC_LOAD_ATTR (0x27) // qstr -#define MP_BC_LOAD_METHOD (0x28) // qstr -#define MP_BC_LOAD_BUILD_CLASS (0x29) +#define MP_BC_LOAD_FAST_CHECKED (0x24) // uint +#define MP_BC_LOAD_DEREF (0x25) // uint +#define MP_BC_LOAD_NAME (0x26) // qstr +#define MP_BC_LOAD_GLOBAL (0x27) // qstr +#define MP_BC_LOAD_ATTR (0x28) // qstr +#define MP_BC_LOAD_METHOD (0x29) // qstr +#define MP_BC_LOAD_BUILD_CLASS (0x2a) #define MP_BC_STORE_FAST_0 (0x30) #define MP_BC_STORE_FAST_1 (0x31) @@ -34,12 +35,10 @@ #define MP_BC_STORE_ATTR (0x37) // qstr #define MP_BC_STORE_SUBSCR (0x38) -#define MP_BC_DELETE_FAST_N (0x39) // uint +#define MP_BC_DELETE_FAST (0x39) // uint #define MP_BC_DELETE_DEREF (0x3a) // uint #define MP_BC_DELETE_NAME (0x3b) // qstr #define MP_BC_DELETE_GLOBAL (0x3c) // qstr -#define MP_BC_DELETE_ATTR (0x3d) // qstr -#define MP_BC_DELETE_SUBSCR (0x3e) #define MP_BC_DUP_TOP (0x40) #define MP_BC_DUP_TOP_TWO (0x41) @@ -97,4 +96,3 @@ #define MP_BC_IMPORT_NAME (0xe0) // qstr #define MP_BC_IMPORT_FROM (0xe1) // qstr #define MP_BC_IMPORT_STAR (0xe2) - diff --git a/py/builtintables.c b/py/builtintables.c index 9a46be6e0a..ea864c6c70 100644 --- a/py/builtintables.c +++ b/py/builtintables.c @@ -17,6 +17,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = { // built-in types { MP_OBJ_NEW_QSTR(MP_QSTR_bool), (mp_obj_t)&mp_type_bool }, { MP_OBJ_NEW_QSTR(MP_QSTR_bytes), (mp_obj_t)&mp_type_bytes }, + { MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray }, #if MICROPY_ENABLE_FLOAT { MP_OBJ_NEW_QSTR(MP_QSTR_complex), (mp_obj_t)&mp_type_complex }, #endif @@ -72,7 +73,6 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_repr), (mp_obj_t)&mp_builtin_repr_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sorted), (mp_obj_t)&mp_builtin_sorted_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&mp_builtin_sum_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_builtin_bytearray_obj }, // built-in exceptions { MP_OBJ_NEW_QSTR(MP_QSTR_BaseException), (mp_obj_t)&mp_type_BaseException }, diff --git a/py/compile.c b/py/compile.c index 95fe1d759f..3ea6dd3a61 100644 --- a/py/compile.c +++ b/py/compile.c @@ -38,26 +38,24 @@ typedef enum { typedef struct _compiler_t { qstr source_file; - bool is_repl; - pass_kind_t pass; - bool had_error; // try to keep compiler clean from nlr + uint8_t is_repl; + uint8_t pass; // holds enum type pass_kind_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; int break_label; int continue_label; int break_continue_except_level; - int cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT + uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT - int n_arg_keyword; - bool have_star_arg; - bool have_dbl_star_arg; - bool have_bare_star; - int param_pass; - int param_pass_num_dict_params; - int param_pass_num_default_params; - - bool func_arg_is_super; // used to compile special case of super() function call + uint16_t n_arg_keyword; + uint8_t star_flags; + uint8_t have_bare_star; + uint8_t param_pass; + uint16_t param_pass_num_dict_params; + uint16_t param_pass_num_default_params; scope_t *scope_head; scope_t *scope_cur; @@ -799,7 +797,7 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d EMIT_ARG(load_closure, id->qstr, id->local_num); #else // in Micro Python we load closures using LOAD_FAST - EMIT_ARG(load_fast, id->qstr, id->local_num); + EMIT_ARG(load_fast, id->qstr, id->flags, id->local_num); #endif nfree += 1; } @@ -907,10 +905,10 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint } // save variables (probably don't need to do this, since we can't have nested definitions..?) - bool old_have_bare_star = comp->have_bare_star; - int old_param_pass = comp->param_pass; - int old_param_pass_num_dict_params = comp->param_pass_num_dict_params; - int old_param_pass_num_default_params = comp->param_pass_num_default_params; + uint old_have_bare_star = comp->have_bare_star; + uint old_param_pass = comp->param_pass; + uint old_param_pass_num_dict_params = comp->param_pass_num_dict_params; + uint old_param_pass_num_default_params = comp->param_pass_num_default_params; // compile default parameters @@ -1076,7 +1074,7 @@ void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { // call each decorator for (int i = 0; i < n - num_built_in_decorators; i++) { - EMIT_ARG(call_function, 1, 0, false, false); + EMIT_ARG(call_function, 1, 0, 0); } // store func/class object into name @@ -1423,7 +1421,7 @@ void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) { // assertion message compile_node(comp, pns->nodes[1]); - EMIT_ARG(call_function, 1, 0, false, false); + EMIT_ARG(call_function, 1, 0, 0); } EMIT_ARG(raise_varargs, 1); EMIT_ARG(label_assign, l_end); @@ -1874,7 +1872,7 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // for REPL, evaluate then print the expression EMIT_ARG(load_id, MP_QSTR___repl_print__); compile_node(comp, pns->nodes[0]); - EMIT_ARG(call_function, 1, 0, false, false); + EMIT_ARG(call_function, 1, 0, 0); EMIT(pop_top); } else { @@ -2210,8 +2208,8 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar // get first argument to function bool found = false; for (int i = 0; i < comp->scope_cur->id_info_len; i++) { - if (comp->scope_cur->id_info[i].param) { - EMIT_ARG(load_fast, MP_QSTR_, comp->scope_cur->id_info[i].local_num); + if (comp->scope_cur->id_info[i].flags & ID_FLAG_IS_PARAM) { + EMIT_ARG(load_fast, MP_QSTR_, comp->scope_cur->id_info[i].flags, comp->scope_cur->id_info[i].local_num); found = true; break; } @@ -2220,38 +2218,35 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar printf("TypeError: super() call cannot find self\n"); return; } - EMIT_ARG(call_function, 2, 0, false, false); + EMIT_ARG(call_function, 2, 0, 0); return; } #endif - int old_n_arg_keyword = comp->n_arg_keyword; - bool old_have_star_arg = comp->have_star_arg; - bool old_have_dbl_star_arg = comp->have_dbl_star_arg; + uint old_n_arg_keyword = comp->n_arg_keyword; + uint old_star_flags = comp->star_flags; comp->n_arg_keyword = 0; - comp->have_star_arg = false; - comp->have_dbl_star_arg = false; + comp->star_flags = 0; compile_node(comp, pn_arglist); // arguments to function call; can be null // compute number of positional arguments int n_positional = n_positional_extra + list_len(pn_arglist, PN_arglist) - comp->n_arg_keyword; - if (comp->have_star_arg) { + if (comp->star_flags & MP_EMIT_STAR_FLAG_SINGLE) { n_positional -= 1; } - if (comp->have_dbl_star_arg) { + if (comp->star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { n_positional -= 1; } if (is_method_call) { - EMIT_ARG(call_method, n_positional, comp->n_arg_keyword, comp->have_star_arg, comp->have_dbl_star_arg); + EMIT_ARG(call_method, n_positional, comp->n_arg_keyword, comp->star_flags); } else { - EMIT_ARG(call_function, n_positional, comp->n_arg_keyword, comp->have_star_arg, comp->have_dbl_star_arg); + EMIT_ARG(call_function, n_positional, comp->n_arg_keyword, comp->star_flags); } comp->n_arg_keyword = old_n_arg_keyword; - comp->have_star_arg = old_have_star_arg; - comp->have_dbl_star_arg = old_have_dbl_star_arg; + comp->star_flags = old_star_flags; } void compile_power_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -2331,7 +2326,7 @@ void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_ compile_node(comp, pns_comp_for->nodes[1]); // source of the iterator EMIT(get_iter); - EMIT_ARG(call_function, 1, 0, false, false); + EMIT_ARG(call_function, 1, 0, 0); } void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -2575,20 +2570,20 @@ void compile_classdef(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_arglist_star(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->have_star_arg) { + if (comp->star_flags & MP_EMIT_STAR_FLAG_SINGLE) { compile_syntax_error(comp, (mp_parse_node_t)pns, "can't have multiple *x"); return; } - comp->have_star_arg = true; + comp->star_flags |= MP_EMIT_STAR_FLAG_SINGLE; compile_node(comp, pns->nodes[0]); } void compile_arglist_dbl_star(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->have_dbl_star_arg) { + if (comp->star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { compile_syntax_error(comp, (mp_parse_node_t)pns, "can't have multiple **x"); return; } - comp->have_dbl_star_arg = true; + comp->star_flags |= MP_EMIT_STAR_FLAG_DOUBLE; compile_node(comp, pns->nodes[0]); } @@ -2766,8 +2761,8 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki compile_syntax_error(comp, pn, "same name used for parameter"); return; } - id_info->param = true; id_info->kind = ID_INFO_KIND_LOCAL; + id_info->flags |= ID_FLAG_IS_PARAM; } } @@ -2995,7 +2990,7 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { #if MICROPY_EMIT_CPYTHON EMIT_ARG(load_closure, MP_QSTR___class__, 0); // XXX check this is the correct local num #else - EMIT_ARG(load_fast, MP_QSTR___class__, id->local_num); + EMIT_ARG(load_fast, MP_QSTR___class__, id->flags, id->local_num); #endif } EMIT(return_value); @@ -3102,7 +3097,7 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT; } // note: params always count for 1 local, even if they are a cell - if (id->param || id->kind == ID_INFO_KIND_LOCAL) { + if (id->kind == ID_INFO_KIND_LOCAL || (id->flags & ID_FLAG_IS_PARAM)) { id->local_num = scope->num_locals; scope->num_locals += 1; } @@ -3124,7 +3119,7 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { // in Micro Python the cells come right after the fast locals // parameters are not counted here, since they remain at the start // of the locals, even if they are cell vars - if (!id->param && id->kind == ID_INFO_KIND_CELL) { + if (id->kind == ID_INFO_KIND_CELL && !(id->flags & ID_FLAG_IS_PARAM)) { id->local_num = scope->num_locals; scope->num_locals += 1; } @@ -3141,7 +3136,7 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { for (int j = 0; j < scope->id_info_len; j++) { id_info_t *id2 = &scope->id_info[j]; if (id2->kind == ID_INFO_KIND_FREE && id->qstr == id2->qstr) { - assert(!id2->param); // free vars should not be params + assert(!(id2->flags & ID_FLAG_IS_PARAM)); // free vars should not be params #if MICROPY_EMIT_CPYTHON // in CPython the frees are numbered after the cells id2->local_num = num_cell + num_free; @@ -3159,7 +3154,7 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { if (num_free > 0) { for (int i = 0; i < scope->id_info_len; i++) { id_info_t *id = &scope->id_info[i]; - if (id->param || id->kind != ID_INFO_KIND_FREE) { + if (id->kind != ID_INFO_KIND_FREE || (id->flags & ID_FLAG_IS_PARAM)) { id->local_num += num_free; } } @@ -3201,21 +3196,9 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { } mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is_repl) { - compiler_t *comp = m_new(compiler_t, 1); - + compiler_t *comp = m_new0(compiler_t, 1); comp->source_file = source_file; comp->is_repl = is_repl; - comp->had_error = false; - - comp->break_label = 0; - comp->continue_label = 0; - comp->break_continue_except_level = 0; - comp->cur_except_level = 0; - - comp->func_arg_is_super = false; - - comp->scope_head = NULL; - comp->scope_cur = NULL; // optimise constants pn = fold_constants(pn); diff --git a/py/compile.h b/py/compile.h index d4a17b7a81..10fd603f2e 100644 --- a/py/compile.h +++ b/py/compile.h @@ -1,3 +1,4 @@ +// These must fit in 8 bits; see scope.h enum { MP_EMIT_OPT_NONE, MP_EMIT_OPT_BYTE_CODE, @@ -14,6 +14,9 @@ typedef enum { PASS_3 = 3, // emit code } pass_kind_t; +#define MP_EMIT_STAR_FLAG_SINGLE (0x01) +#define MP_EMIT_STAR_FLAG_DOUBLE (0x02) + typedef struct _emit_t emit_t; typedef struct _emit_method_table_t { @@ -40,9 +43,9 @@ typedef struct _emit_method_table_t { void (*load_const_id)(emit_t *emit, qstr qstr); void (*load_const_str)(emit_t *emit, qstr qstr, bool bytes); void (*load_const_verbatim_str)(emit_t *emit, const char *str); // only needed for emitcpy - void (*load_fast)(emit_t *emit, qstr qstr, int local_num); + void (*load_fast)(emit_t *emit, qstr qstr, uint id_flags, int local_num); void (*load_deref)(emit_t *emit, qstr qstr, int local_num); - void (*load_closure)(emit_t *emit, qstr qstr, int local_num); + void (*load_closure)(emit_t *emit, qstr qstr, int local_num); // only needed for emitcpy void (*load_name)(emit_t *emit, qstr qstr); void (*load_global)(emit_t *emit, qstr qstr); void (*load_attr)(emit_t *emit, qstr qstr); @@ -98,8 +101,8 @@ typedef struct _emit_method_table_t { void (*unpack_ex)(emit_t *emit, int n_left, int n_right); void (*make_function)(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults); void (*make_closure)(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults); - void (*call_function)(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg); - void (*call_method)(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg); + void (*call_function)(emit_t *emit, int n_positional, int n_keyword, uint star_flags); + void (*call_method)(emit_t *emit, int n_positional, int n_keyword, uint star_flags); void (*return_value)(emit_t *emit); void (*raise_varargs)(emit_t *emit, int n_args); void (*yield_value)(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index 11519fdd80..21d1a61863 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -36,6 +36,9 @@ struct _emit_t { byte dummy_data[8]; }; +STATIC void emit_bc_rot_two(emit_t *emit); +STATIC void emit_bc_rot_three(emit_t *emit); + emit_t *emit_bc_new(uint max_num_labels) { emit_t *emit = m_new0(emit_t, 1); emit->max_num_labels = max_num_labels; @@ -318,6 +321,7 @@ STATIC void emit_bc_delete_id(emit_t *emit, qstr qstr) { } STATIC void emit_bc_pre(emit_t *emit, int stack_size_delta) { + assert((int)emit->stack_size + stack_size_delta >= 0); emit->stack_size += stack_size_delta; if (emit->stack_size > emit->scope->stack_size) { emit->scope->stack_size = emit->stack_size; @@ -404,14 +408,20 @@ STATIC void emit_bc_load_null(emit_t *emit) { emit_write_byte_code_byte(emit, MP_BC_LOAD_NULL); }; -STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, int local_num) { +STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) { assert(local_num >= 0); emit_bc_pre(emit, 1); - switch (local_num) { - case 0: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_0); break; - case 1: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_1); break; - case 2: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_2); break; - default: emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break; + if (id_flags & ID_FLAG_IS_DELETED) { + // This local may be deleted, so need to do a checked load. + emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_CHECKED, local_num); + } else { + // This local is never deleted, so can do a fast, uncheched load. + switch (local_num) { + case 0: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_0); break; + case 1: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_1); break; + case 2: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_2); break; + default: emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break; + } } } @@ -487,14 +497,11 @@ STATIC void emit_bc_store_subscr(emit_t *emit) { } STATIC void emit_bc_delete_fast(emit_t *emit, qstr qstr, int local_num) { - assert(local_num >= 0); - emit_bc_pre(emit, 0); - emit_write_byte_code_byte_uint(emit, MP_BC_DELETE_FAST_N, local_num); + emit_write_byte_code_byte_uint(emit, MP_BC_DELETE_FAST, local_num); } STATIC void emit_bc_delete_deref(emit_t *emit, qstr qstr, int local_num) { - emit_bc_pre(emit, 0); - emit_write_byte_code_byte_qstr(emit, MP_BC_DELETE_DEREF, local_num); + emit_write_byte_code_byte_uint(emit, MP_BC_DELETE_DEREF, local_num); } STATIC void emit_bc_delete_name(emit_t *emit, qstr qstr) { @@ -508,13 +515,15 @@ STATIC void emit_bc_delete_global(emit_t *emit, qstr qstr) { } STATIC void emit_bc_delete_attr(emit_t *emit, qstr qstr) { - emit_bc_pre(emit, -1); - emit_write_byte_code_byte_qstr(emit, MP_BC_DELETE_ATTR, qstr); + emit_bc_load_null(emit); + emit_bc_rot_two(emit); + emit_bc_store_attr(emit, qstr); } STATIC void emit_bc_delete_subscr(emit_t *emit) { - emit_bc_pre(emit, -2); - emit_write_byte_code_byte(emit, MP_BC_DELETE_SUBSCR); + emit_bc_load_null(emit); + emit_bc_rot_three(emit); + emit_bc_store_subscr(emit); } STATIC void emit_bc_dup_top(emit_t *emit) { @@ -762,13 +771,13 @@ STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaul } } -STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, uint bytecode_base, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { - if (have_star_arg || have_dbl_star_arg) { - if (!have_star_arg) { +STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, uint bytecode_base, int n_positional, int n_keyword, uint star_flags) { + if (star_flags) { + if (!(star_flags & MP_EMIT_STAR_FLAG_SINGLE)) { // load dummy entry for non-existent pos_seq emit_bc_load_null(emit); emit_bc_rot_two(emit); - } else if (!have_dbl_star_arg) { + } else if (!(star_flags & MP_EMIT_STAR_FLAG_DOUBLE)) { // load dummy entry for non-existent kw_dict emit_bc_load_null(emit); } @@ -780,12 +789,12 @@ STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, uin } } -STATIC void emit_bc_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { - emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, have_star_arg, have_dbl_star_arg); +STATIC void emit_bc_call_function(emit_t *emit, int n_positional, int n_keyword, uint star_flags) { + emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, star_flags); } -STATIC void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { - emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, have_star_arg, have_dbl_star_arg); +STATIC void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, uint star_flags) { + emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, star_flags); } STATIC void emit_bc_return_value(emit_t *emit) { diff --git a/py/emitcommon.c b/py/emitcommon.c index f7494668e0..30f5ace923 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -25,7 +25,7 @@ void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_ta } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) { EMIT(load_global, qstr); } else if (id->kind == ID_INFO_KIND_LOCAL) { - EMIT(load_fast, qstr, id->local_num); + EMIT(load_fast, qstr, id->flags, id->local_num); } else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) { EMIT(load_deref, qstr, id->local_num); } else { diff --git a/py/emitcpy.c b/py/emitcpy.c index 8345c12dca..8c608d6a2b 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -230,7 +230,7 @@ STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) { } } -STATIC void emit_cpy_load_fast(emit_t *emit, qstr qstr, int local_num) { +STATIC void emit_cpy_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) { emit_pre(emit, 1, 3); if (emit->pass == PASS_3) { printf("LOAD_FAST %d %s\n", local_num, qstr_str(qstr)); @@ -675,24 +675,24 @@ STATIC void emit_cpy_unpack_ex(emit_t *emit, int n_left, int n_right) { } } -STATIC void emit_cpy_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { +STATIC void emit_cpy_call_function(emit_t *emit, int n_positional, int n_keyword, uint star_flags) { int s = 0; - if (have_star_arg) { + if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) { s += 1; } - if (have_dbl_star_arg) { + if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { s += 1; } emit_pre(emit, -n_positional - 2 * n_keyword - s, 3); if (emit->pass == PASS_3) { - if (have_star_arg) { - if (have_dbl_star_arg) { + if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) { + if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { printf("CALL_FUNCTION_VAR_KW"); } else { printf("CALL_FUNCTION_VAR"); } } else { - if (have_dbl_star_arg) { + if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) { printf("CALL_FUNCTION_KW"); } else { printf("CALL_FUNCTION"); @@ -702,8 +702,8 @@ STATIC void emit_cpy_call_function(emit_t *emit, int n_positional, int n_keyword } } -STATIC void emit_cpy_call_method(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { - emit_cpy_call_function(emit, n_positional, n_keyword, have_star_arg, have_dbl_star_arg); +STATIC void emit_cpy_call_method(emit_t *emit, int n_positional, int n_keyword, uint star_flags) { + emit_cpy_call_function(emit, n_positional, n_keyword, star_flags); } STATIC void emit_cpy_return_value(emit_t *emit) { diff --git a/py/emitnative.c b/py/emitnative.c index af8b35f45d..e96b12271a 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -308,8 +308,8 @@ STATIC void emit_native_set_source_line(emit_t *emit, int source_line) { STATIC void adjust_stack(emit_t *emit, int stack_size_delta) { DEBUG_printf("adjust stack: stack:%d + delta:%d\n", emit->stack_size, stack_size_delta); + assert((int)emit->stack_size + stack_size_delta >= 0); emit->stack_size += stack_size_delta; - assert(emit->stack_size >= 0); if (emit->pass > PASS_1 && emit->stack_size > emit->scope->stack_size) { emit->scope->stack_size = emit->stack_size; } @@ -704,7 +704,7 @@ STATIC void emit_native_load_const_verbatim_str(emit_t *emit, const char *str) { assert(0); } -STATIC void emit_native_load_fast(emit_t *emit, qstr qstr, int local_num) { +STATIC void emit_native_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) { vtype_kind_t vtype = emit->local_vtype[local_num]; if (vtype == VTYPE_UNBOUND) { printf("ViperTypeError: local %s used before type known\n", qstr_str(qstr)); @@ -1200,9 +1200,9 @@ STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, uint n_pos_de assert(0); } -STATIC void emit_native_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { +STATIC void emit_native_call_function(emit_t *emit, int n_positional, int n_keyword, uint star_flags) { // call special viper runtime routine with type info for args, and wanted type info for return - assert(!have_star_arg && !have_dbl_star_arg); + assert(!star_flags); /* we no longer have these _n specific call_function's * they anyway push args into an array @@ -1239,8 +1239,8 @@ STATIC void emit_native_call_function(emit_t *emit, int n_positional, int n_keyw emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } -STATIC void emit_native_call_method(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) { - assert(!have_star_arg && !have_dbl_star_arg); +STATIC void emit_native_call_method(emit_t *emit, int n_positional, int n_keyword, uint star_flags) { + assert(!star_flags); /* if (n_positional == 0) { diff --git a/py/emitpass1.c b/py/emitpass1.c index d2f7aaa53a..6088489410 100644 --- a/py/emitpass1.c +++ b/py/emitpass1.c @@ -91,7 +91,8 @@ STATIC void emit_pass1_store_id(emit_t *emit, qstr qstr) { } STATIC void emit_pass1_delete_id(emit_t *emit, qstr qstr) { - get_id_for_modification(emit->scope, qstr); + id_info_t *id = get_id_for_modification(emit->scope, qstr); + id->flags |= ID_FLAG_IS_DELETED; } const emit_method_table_t emit_pass1_method_table = { @@ -20,8 +20,6 @@ #define DEBUG_printf(...) (void)0 #endif -typedef unsigned char byte; - #define WORDS_PER_BLOCK (4) #define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD) #define STACK_SIZE (64) // tunable; minimum is 1 @@ -1255,7 +1255,7 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, const char *prefix, char base_ch return s - str; } - // make a copy of mpz digits + // make a copy of mpz digits, so we can do the div/mod calculation mpz_dig_t *dig = m_new(mpz_dig_t, ilen); memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t)); @@ -1295,6 +1295,9 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, const char *prefix, char base_ch } while (!done); + // free the copy of the digits array + m_del(mpz_dig_t, dig, ilen); + if (prefix) { const char *p = &prefix[strlen(prefix)]; while (p > prefix) { @@ -99,6 +99,11 @@ int mp_obj_is_true(mp_obj_t arg) { } } +// returns true if o_in is bool, small int, or long int +bool mp_obj_is_integer(mp_obj_t o_in) { + return MP_OBJ_IS_INT(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bool); +} + bool mp_obj_is_callable(mp_obj_t o_in) { return mp_obj_get_type(o_in)->call != NULL; } @@ -285,8 +290,8 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) { // is_slice determines whether the index is a slice index uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice) { int i; - if (MP_OBJ_IS_SMALL_INT(index)) { - i = MP_OBJ_SMALL_INT_VALUE(index); + if (MP_OBJ_IS_INT(index)) { + i = mp_obj_int_get_checked(index); } else if (MP_OBJ_IS_TYPE(index, &mp_type_bool)) { i = (index == mp_const_true ? 1 : 0); } else { @@ -330,3 +335,21 @@ mp_obj_t mp_identity(mp_obj_t self) { return self; } MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity); + +bool mp_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) { + return false; + } + o->type->buffer_p.get_buffer(o, bufinfo, BUFFER_READ); + if (bufinfo->buf == NULL) { + return false; + } + return true; +} + +void mp_get_buffer_raise(mp_obj_t obj, buffer_info_t *bufinfo) { + if (!mp_get_buffer(obj, bufinfo)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Object with buffer protocol required")); + } +} @@ -163,8 +163,8 @@ typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, uint n_args, uint n_kw, const mp typedef mp_obj_t (*mp_unary_op_fun_t)(int op, mp_obj_t); typedef mp_obj_t (*mp_binary_op_fun_t)(int op, mp_obj_t, mp_obj_t); typedef void (*mp_load_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest); // for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self -typedef bool (*mp_store_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t value); // return true if store succeeded -typedef bool (*mp_store_item_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); // return true if store succeeded +typedef bool (*mp_store_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t value); // return true if store succeeded; if value==MP_OBJ_NULL then delete +typedef bool (*mp_store_item_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); // return true if store succeeded; if value==MP_OBJ_NULL then delete typedef struct _mp_method_t { qstr name; @@ -196,6 +196,8 @@ typedef struct _buffer_info_t { typedef struct _mp_buffer_p_t { machine_int_t (*get_buffer)(mp_obj_t obj, buffer_info_t *bufinfo, int flags); } mp_buffer_p_t; +bool mp_get_buffer(mp_obj_t obj, buffer_info_t *bufinfo); +void mp_get_buffer_raise(mp_obj_t obj, buffer_info_t *bufinfo); // Stream protocol typedef struct _mp_stream_p_t { @@ -217,9 +219,10 @@ struct _mp_obj_type_t { mp_binary_op_fun_t binary_op; // can return NULL if op not supported mp_load_attr_fun_t load_attr; - mp_store_attr_fun_t store_attr; - // Implements container[index] = val; note that load_item is implemented - // by binary_op(RT_BINARY_OP_SUBSCR) + mp_store_attr_fun_t store_attr; // if value is MP_OBJ_NULL, then delete that attribute + + // Implements container[index] = val. If val == MP_OBJ_NULL, then it's a delete. + // Note that load_item is implemented by binary_op(RT_BINARY_OP_SUBSCR) mp_store_item_fun_t store_item; mp_fun_1_t getiter; @@ -259,6 +262,7 @@ extern const mp_obj_type_t mp_type_bool; extern const mp_obj_type_t mp_type_int; extern const mp_obj_type_t mp_type_str; extern const mp_obj_type_t mp_type_bytes; +extern const mp_obj_type_t mp_type_bytearray; extern const mp_obj_type_t mp_type_float; extern const mp_obj_type_t mp_type_complex; extern const mp_obj_type_t mp_type_tuple; @@ -365,6 +369,7 @@ void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); void mp_obj_print_exception(mp_obj_t exc); int mp_obj_is_true(mp_obj_t arg); +bool mp_obj_is_integer(mp_obj_t o_in); // returns true if o_in is bool, small int, or long int 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); diff --git a/py/objarray.c b/py/objarray.c index 4f9fa49bcb..15268112a2 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -88,19 +88,20 @@ STATIC mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m return array_construct(*typecode, args[1]); } -// This is top-level factory function, not virtual method -// TODO: "bytearray" really should be type, not function -STATIC mp_obj_t mp_builtin_bytearray(mp_obj_t arg) { - if (MP_OBJ_IS_SMALL_INT(arg)) { - uint len = MP_OBJ_SMALL_INT_VALUE(arg); +STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + if (n_args > 1) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected # of arguments, %d given", n_args)); + } + + if (MP_OBJ_IS_SMALL_INT(args[0])) { + uint len = MP_OBJ_SMALL_INT_VALUE(args[0]); mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, len); memset(o->items, 0, len); return o; } - return array_construct(BYTEARRAY_TYPECODE, arg); + return array_construct(BYTEARRAY_TYPECODE, args[0]); } -MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bytearray_obj, mp_builtin_bytearray); STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) { mp_obj_array_t *o = o_in; @@ -127,7 +128,7 @@ STATIC mp_obj_t array_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array)); + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray)); mp_obj_array_t *self = self_in; if (self->free == 0) { int item_sz = mp_binary_get_size(self->typecode); @@ -142,6 +143,10 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(array_append_obj, array_append); STATIC bool array_store_item(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + // delete item; does this need to be implemented? + return false; + } mp_obj_array_t *o = self_in; uint index = mp_get_index(o->base.type, o->len, index_in, false); mp_binary_set_val(o->typecode, o->items, index, value); @@ -174,9 +179,22 @@ const mp_obj_type_t mp_type_array = { .locals_dict = (mp_obj_t)&array_locals_dict, }; +const mp_obj_type_t mp_type_bytearray = { + { &mp_type_type }, + .name = MP_QSTR_bytearray, + .print = array_print, + .make_new = bytearray_make_new, + .getiter = array_iterator_new, + .unary_op = array_unary_op, + .binary_op = array_binary_op, + .store_item = array_store_item, + .buffer_p = { .get_buffer = array_get_buffer }, + .locals_dict = (mp_obj_t)&array_locals_dict, +}; + STATIC mp_obj_array_t *array_new(char typecode, uint n) { mp_obj_array_t *o = m_new_obj(mp_obj_array_t); - o->base.type = &mp_type_array; + o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array; o->typecode = typecode; o->free = 0; o->len = n; diff --git a/py/objarray.h b/py/objarray.h index 620426ce37..0f6ede86f6 100644 --- a/py/objarray.h +++ b/py/objarray.h @@ -1,3 +1 @@ -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bytearray_obj); - mp_obj_t mp_obj_new_bytearray(uint n, void *items); diff --git a/py/objcomplex.c b/py/objcomplex.c index 769977ad80..66f971da0e 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -144,22 +144,40 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im lhs_imag -= rhs_imag; break; case MP_BINARY_OP_MULTIPLY: - case MP_BINARY_OP_INPLACE_MULTIPLY: - { - mp_float_t real = lhs_real * rhs_real - lhs_imag * rhs_imag; + case MP_BINARY_OP_INPLACE_MULTIPLY: { + mp_float_t real; + multiply: + real = lhs_real * rhs_real - lhs_imag * rhs_imag; lhs_imag = lhs_real * rhs_imag + lhs_imag * rhs_real; lhs_real = real; break; } - /* TODO floor(?) the value case MP_BINARY_OP_FLOOR_DIVIDE: - case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: val = lhs_val / rhs_val; break; - */ - /* TODO + case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't do truncated division of a complex number")); + case MP_BINARY_OP_TRUE_DIVIDE: - case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: val = lhs_val / rhs_val; break; - */ - return NULL; // op not supported + case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: + if (rhs_imag == 0) { + if (rhs_real == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "complex division by zero")); + } + lhs_real /= rhs_real; + lhs_imag /= rhs_real; + } else if (rhs_real == 0) { + mp_float_t real = lhs_imag / rhs_imag; + lhs_imag = -lhs_real / rhs_imag; + lhs_real = real; + } else { + mp_float_t rhs_len_sq = rhs_real*rhs_real + rhs_imag*rhs_imag; + rhs_real /= rhs_len_sq; + rhs_imag /= -rhs_len_sq; + goto multiply; + } + break; + + default: + return MP_OBJ_NULL; // op not supported } return mp_obj_new_complex(lhs_real, lhs_imag); } diff --git a/py/objdict.c b/py/objdict.c index 80337198e9..85986448c7 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -114,6 +114,14 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } } +STATIC bool dict_store_item(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + mp_obj_dict_delete(self_in, index); + } else { + mp_obj_dict_store(self_in, index, value); + } + return true; +} /******************************************************************************/ /* dict iterator */ @@ -484,6 +492,7 @@ const mp_obj_type_t mp_type_dict = { .make_new = dict_make_new, .unary_op = dict_unary_op, .binary_op = dict_binary_op, + .store_item = dict_store_item, .getiter = dict_getiter, .locals_dict = (mp_obj_t)&dict_locals_dict, }; diff --git a/py/objgenerator.c b/py/objgenerator.c index 975681af88..6468aa20db 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -236,17 +236,10 @@ mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj machine_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8); bytecode += 4; - // bytecode prelude: initialise closed over variables - // TODO - // for now we just make sure there are no cells variables - // need to work out how to implement closed over variables in generators - assert(bytecode[0] == 0); - bytecode += 1; - + // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; o->code_info = code_info; - o->ip = bytecode; o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state o->exc_sp = (mp_exc_stack_t*)(o->state + n_state) - 1; o->n_state = n_state; @@ -259,5 +252,19 @@ mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj o->state[n_state - 1 - n_args - i] = args2[i]; } + // set rest of state to MP_OBJ_NULL + for (uint i = 0; i < n_state - n_args - n_args2; i++) { + o->state[i] = MP_OBJ_NULL; + } + + // bytecode prelude: initialise closed over variables + for (uint n_local = *bytecode++; n_local > 0; n_local--) { + uint local_num = *bytecode++; + o->state[n_state - 1 - local_num] = mp_obj_new_cell(o->state[n_state - 1 - local_num]); + } + + // set ip to start of actual byte code + o->ip = bytecode; + return o; } diff --git a/py/objint.c b/py/objint.c index e1b67a16b3..69954168de 100644 --- a/py/objint.c +++ b/py/objint.c @@ -70,15 +70,13 @@ void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, } } -#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE || MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG - #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG -typedef mp_longint_impl_t fmt_int_t; +typedef mp_longint_impl_t fmt_int_t; #else -typedef mp_small_int_t fmt_int_t; +typedef mp_small_int_t fmt_int_t; #endif -static const uint log_base2_floor[] = { +STATIC const uint log_base2_floor[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, @@ -90,7 +88,7 @@ static const uint log_base2_floor[] = { 4, 4, 4, 5 }; -uint int_as_str_size_formatted(uint base, const char *prefix, char comma) { +STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) { if (base < 2 || base > 32) { return 0; } @@ -110,22 +108,29 @@ uint int_as_str_size_formatted(uint base, const char *prefix, char comma) { // formatted size will be in *fmt_size. char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, int base, const char *prefix, char base_char, char comma) { - if (!MP_OBJ_IS_INT(self_in)) { - buf[0] = '\0'; - *fmt_size = 0; - return *buf; - } fmt_int_t num; + if (MP_OBJ_IS_SMALL_INT(self_in)) { + // A small int; get the integer value to format. + num = mp_obj_get_int(self_in); +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { + // Not a small int. #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG - mp_obj_int_t *self = self_in; - if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { - // mp_obj_get_int truncates to machine_int_t + mp_obj_int_t *self = self_in; + // Get the value to format; mp_obj_get_int truncates to machine_int_t. num = self->val; - } else +#else + // Delegate to the implementation for the long int. + return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma); #endif - { - num = mp_obj_get_int(self_in); +#endif + } else { + // Not an int. + buf[0] = '\0'; + *fmt_size = 0; + return *buf; } + char sign = '\0'; if (num < 0) { num = -num; @@ -180,12 +185,11 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se return b; } +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + bool mp_obj_int_is_positive(mp_obj_t self_in) { return mp_obj_get_int(self_in) >= 0; } -#endif // LONGLONG or NONE - -#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE // This is called for operations on SMALL_INT that are not handled by mp_unary_op mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { @@ -261,6 +265,43 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_ return MP_OBJ_NULL; } +STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) { + buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo); + + assert(bufinfo.len >= sizeof(machine_int_t)); + // TODO: Support long ints + // TODO: Support byteorder param + // TODO: Support signed param + return mp_obj_new_int_from_uint(*(machine_uint_t*)bufinfo.buf); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_obj, 1, 3, int_from_bytes); + +STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) { + machine_int_t val = mp_obj_int_get_checked(args[0]); + + uint len = MP_OBJ_SMALL_INT_VALUE(args[1]); + byte *data; + + // TODO: Support long ints + // TODO: Support byteorder param + // TODO: Support signed param + mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data); + memset(data, 0, len); + memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t)); + return mp_obj_str_builder_end(o); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 2, 4, int_to_bytes); + +STATIC const mp_map_elem_t int_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_from_bytes), (mp_obj_t)&int_from_bytes_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_to_bytes), (mp_obj_t)&int_to_bytes_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table); + const mp_obj_type_t mp_type_int = { { &mp_type_type }, .name = MP_QSTR_int, @@ -268,4 +309,5 @@ const mp_obj_type_t mp_type_int = { .make_new = mp_obj_int_make_new, .unary_op = mp_obj_int_unary_op, .binary_op = mp_obj_int_binary_op, + .locals_dict = (mp_obj_t)&int_locals_dict, }; diff --git a/py/objint.h b/py/objint.h index 7ee476269c..5b21d55fe8 100644 --- a/py/objint.h +++ b/py/objint.h @@ -10,6 +10,8 @@ typedef struct _mp_obj_int_t { void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind); char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, int base, const char *prefix, char base_char, char comma); +char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, + int base, const char *prefix, char base_char, char comma); bool mp_obj_int_is_positive(mp_obj_t self_in); 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); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 332f0bbb8a..24435415fb 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -22,6 +22,14 @@ #define SUFFIX "" #endif +bool mp_obj_int_is_positive(mp_obj_t self_in) { + if (MP_OBJ_IS_SMALL_INT(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0; + } + mp_obj_int_t *self = self_in; + return self->val >= 0; +} + mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { mp_obj_int_t *o = o_in; switch (op) { diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 6410ecc64d..583ce4cb78 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -1,6 +1,7 @@ #include <stdint.h> #include <string.h> #include <stdio.h> +#include <assert.h> #include "nlr.h" #include "misc.h" @@ -29,30 +30,21 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { // // The resulting formatted string will be returned from this function and the // formatted size will be in *fmt_size. -char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, - int base, const char *prefix, char base_char, char comma) { - mpz_t small_mpz; - mpz_t *mpz; - mpz_dig_t small_dig[(sizeof(mp_small_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE]; - - if (MP_OBJ_IS_SMALL_INT(self_in)) { - mpz_init_fixed_from_int(&small_mpz, small_dig, - sizeof(small_dig) / sizeof(small_dig[0]), - MP_OBJ_SMALL_INT_VALUE(self_in)); - mpz = &small_mpz; - } else { - mp_obj_int_t *self = self_in; - mpz = &self->mpz; - } +// +// This particular routine should only be called for the mpz representation of the int. +char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, + int base, const char *prefix, char base_char, char comma) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); + mp_obj_int_t *self = self_in; - uint needed_size = mpz_as_str_size_formatted(mpz, base, prefix, comma); + uint needed_size = mpz_as_str_size_formatted(&self->mpz, base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; } char *str = *buf; - *fmt_size = mpz_as_str_inpl(mpz, base, prefix, base_char, comma, str); + *fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str); return str; } diff --git a/py/objlist.c b/py/objlist.c index 371d1cb26e..a3b7e79abb 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -19,6 +19,7 @@ typedef struct _mp_obj_list_t { STATIC mp_obj_t mp_obj_new_list_iterator(mp_obj_list_t *list, int cur); STATIC mp_obj_list_t *list_new(uint n); STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in); +STATIC mp_obj_t list_pop(uint n_args, const mp_obj_t *args); // TODO: Move to mpconfig.h #define LIST_MIN_ALLOC 4 @@ -146,6 +147,16 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } } +STATIC bool list_store_item(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + mp_obj_t args[2] = {self_in, index}; + list_pop(2, args); + } else { + mp_obj_list_store(self_in, index, value); + } + return true; +} + STATIC mp_obj_t list_getiter(mp_obj_t o_in) { return mp_obj_new_list_iterator(o_in, 0); } @@ -349,6 +360,7 @@ const mp_obj_type_t mp_type_list = { .make_new = list_make_new, .unary_op = list_unary_op, .binary_op = list_binary_op, + .store_item = list_store_item, .getiter = list_getiter, .locals_dict = (mp_obj_t)&list_locals_dict, }; diff --git a/py/objmodule.c b/py/objmodule.c index df7c991b8c..15ccd68ac2 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -27,8 +27,14 @@ STATIC void module_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { STATIC bool module_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { mp_obj_module_t *self = self_in; - // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation? - mp_obj_dict_store(self->globals, MP_OBJ_NEW_QSTR(attr), value); + if (value == MP_OBJ_NULL) { + // delete attribute + mp_obj_dict_delete(self->globals, MP_OBJ_NEW_QSTR(attr)); + } else { + // store attribute + // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation? + mp_obj_dict_store(self->globals, MP_OBJ_NEW_QSTR(attr), value); + } return true; } diff --git a/py/objstr.c b/py/objstr.c index e37d7b22fd..519ff464d6 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -221,9 +221,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len); switch (op) { case MP_BINARY_OP_SUBSCR: - // TODO: need predicate to check for int-like type (bools are such for example) - // ["no", "yes"][1 == 2] is common idiom - if (MP_OBJ_IS_SMALL_INT(rhs_in)) { + if (mp_obj_is_integer(rhs_in)) { uint index = mp_get_index(mp_obj_get_type(lhs_in), lhs_len, rhs_in, false); if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_bytes)) { return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)lhs_data[index]); @@ -329,17 +327,19 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { mp_obj_t *seq_items; if (MP_OBJ_IS_TYPE(arg, &mp_type_tuple)) { mp_obj_tuple_get(arg, &seq_len, &seq_items); - } else if (MP_OBJ_IS_TYPE(arg, &mp_type_list)) { - mp_obj_list_get(arg, &seq_len, &seq_items); } else { - goto bad_arg; + if (!MP_OBJ_IS_TYPE(arg, &mp_type_list)) { + // arg is not a list, try to convert it to one + arg = mp_type_list.make_new((mp_obj_t)&mp_type_list, 1, 0, &arg); + } + mp_obj_list_get(arg, &seq_len, &seq_items); } // count required length int required_len = 0; for (int i = 0; i < seq_len; i++) { if (!MP_OBJ_IS_STR(seq_items[i])) { - goto bad_arg; + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "join expected a list of str's")); } if (i > 0) { required_len += sep_len; @@ -363,9 +363,6 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { // return joined string return mp_obj_str_builder_end(joined_str); - -bad_arg: - 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') diff --git a/py/objtype.c b/py/objtype.c index 92f1f57035..cb8cfc5325 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -257,11 +257,23 @@ STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { STATIC bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { mp_obj_class_t *self = self_in; - mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; - return true; + if (value == MP_OBJ_NULL) { + // delete attribute + mp_map_elem_t *el = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return el != NULL; + } else { + // store attribute + mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; + return true; + } } bool class_store_item(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + // delete item + // TODO implement me! + return false; + } mp_obj_class_t *self = self_in; mp_obj_t member = mp_obj_class_lookup(self->base.type, MP_QSTR___setitem__); if (member != MP_OBJ_NULL) { @@ -356,11 +368,19 @@ STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { if (self->locals_dict != NULL) { assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict); - mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - // note that locals_map may be in ROM, so add will fail in that case - if (elem != NULL) { - elem->value = value; - return true; + if (value == MP_OBJ_NULL) { + // delete attribute + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + // note that locals_map may be in ROM, so remove will fail in that case + return elem != NULL; + } else { + // store attribute + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + // note that locals_map may be in ROM, so add will fail in that case + if (elem != NULL) { + elem->value = value; + return true; + } } } diff --git a/py/pfenv.c b/py/pfenv.c index b91390d6d9..310ca07aa4 100644 --- a/py/pfenv.c +++ b/py/pfenv.c @@ -77,15 +77,80 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in return len; } -int pfenv_print_int(const pfenv_t *pfenv, int x, int sgn, int base, int base_char, int flags, char fill, int width) { - // XXX this really needs to be a dedicated function, since converting to a mp_int looses the MSB - return pfenv_print_mp_int(pfenv, MP_OBJ_NEW_SMALL_INT((machine_int_t)x), sgn, base, base_char, flags, fill, width); -} - // 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null // We can use 16 characters for 32-bit and 32 characters for 64-bit #define INT_BUF_SIZE (sizeof(machine_int_t) * 4) +// This function is used by stmhal port to implement printf. +// It needs to be a separate function to pfenv_print_mp_int, since converting to a mp_int looses the MSB. +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 ((machine_int_t)x < 0) { + sign = '-'; + x = -x; + } else if (flags & PF_FLAG_SHOW_SIGN) { + sign = '+'; + } else if (flags & PF_FLAG_SPACE_SIGN) { + sign = ' '; + } + } + + char buf[INT_BUF_SIZE]; + char *b = buf + INT_BUF_SIZE; + + if (x == 0) { + *(--b) = '0'; + } else { + do { + int c = x % base; + x /= base; + if (c >= 10) { + c += base_char - 10; + } else { + c += '0'; + } + *(--b) = c; + } while (b > buf && x != 0); + } + + char prefix_char = '\0'; + + if (flags & PF_FLAG_SHOW_PREFIX) { + if (base == 2) { + prefix_char = base_char + 'b' - 'a'; + } else if (base == 8) { + prefix_char = base_char + 'o' - 'a'; + } else if (base == 16) { + prefix_char = base_char + 'x' - 'a'; + } + } + + int len = 0; + if (flags & PF_FLAG_PAD_AFTER_SIGN) { + if (sign) { + len += pfenv_print_strn(pfenv, &sign, 1, flags, fill, 1); + width--; + } + if (prefix_char) { + len += pfenv_print_strn(pfenv, "0", 1, flags, fill, 1); + len += pfenv_print_strn(pfenv, &prefix_char, 1, flags, fill, 1); + width -= 2; + } + } else { + if (prefix_char && b > &buf[1]) { + *(--b) = prefix_char; + *(--b) = '0'; + } + if (sign && b > buf) { + *(--b) = sign; + } + } + + len += pfenv_print_strn(pfenv, b, buf + INT_BUF_SIZE - b, flags, fill, width); + return len; +} + int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width) { if (!MP_OBJ_IS_INT(x)) { // This will convert booleans to int, or raise an error for diff --git a/py/pfenv.h b/py/pfenv.h index 6240b47acb..9e687e4b95 100644 --- a/py/pfenv.h +++ b/py/pfenv.h @@ -18,7 +18,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, 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); int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_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); diff --git a/py/qstrdefs.h b/py/qstrdefs.h index a379da3910..342160bbc7 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -96,6 +96,7 @@ Q(eval) Q(exec) Q(filter) Q(float) +Q(from_bytes) Q(getattr) Q(globals) Q(hash) @@ -127,6 +128,7 @@ Q(sum) Q(super) Q(str) Q(sys) +Q(to_bytes) Q(tuple) Q(type) Q(value) diff --git a/py/runtime.c b/py/runtime.c index 3d1ae72c2f..ef07e39bff 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -132,8 +132,8 @@ 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(&dict_locals->map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + // TODO convert KeyError to NameError if qstr not found + mp_obj_dict_delete(dict_locals, MP_OBJ_NEW_QSTR(qstr)); } void mp_store_global(qstr qstr, mp_obj_t obj) { @@ -141,6 +141,12 @@ void mp_store_global(qstr qstr, mp_obj_t obj) { mp_obj_dict_store(dict_globals, MP_OBJ_NEW_QSTR(qstr), obj); } +void mp_delete_global(qstr qstr) { + DEBUG_OP_printf("delete global %s\n", qstr_str(qstr)); + // TODO convert KeyError to NameError if qstr not found + mp_obj_dict_delete(dict_globals, MP_OBJ_NEW_QSTR(qstr)); +} + mp_obj_t mp_unary_op(int op, mp_obj_t arg) { DEBUG_OP_printf("unary %d %p\n", op, arg); @@ -835,37 +841,18 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { void mp_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { DEBUG_OP_printf("store subscr %p[%p] <- %p\n", base, index, value); - if (MP_OBJ_IS_TYPE(base, &mp_type_list)) { - // list store - mp_obj_list_store(base, index, value); - } else if (MP_OBJ_IS_TYPE(base, &mp_type_dict)) { - // dict store - mp_obj_dict_store(base, index, value); - } else { - mp_obj_type_t *type = mp_obj_get_type(base); - if (type->store_item != NULL) { - bool r = type->store_item(base, index, value); - if (r) { - return; - } - // TODO: call base classes here? + mp_obj_type_t *type = mp_obj_get_type(base); + if (type->store_item != NULL) { + bool r = type->store_item(base, index, value); + if (r) { + return; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); + // TODO: call base classes here? } -} - -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 { + if (value == MP_OBJ_NULL) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base))); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); } } diff --git a/py/runtime.h b/py/runtime.h index ab34be2da9..867d633520 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -20,6 +20,7 @@ mp_obj_t mp_load_build_class(void); void mp_store_name(qstr qstr, mp_obj_t obj); void mp_store_global(qstr qstr, mp_obj_t obj); void mp_delete_name(qstr qstr); +void mp_delete_global(qstr qstr); mp_obj_t mp_unary_op(int op, mp_obj_t arg); mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs); @@ -51,7 +52,6 @@ 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/runtime0.h b/py/runtime0.h index be598c670e..6ee70aa01d 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -1,4 +1,5 @@ // taken from python source, Include/code.h +// These must fit in 8 bits; see scope.h #define MP_SCOPE_FLAG_OPTIMISED 0x01 #define MP_SCOPE_FLAG_NEWLOCALS 0x02 #define MP_SCOPE_FLAG_VARARGS 0x04 diff --git a/py/scope.c b/py/scope.c index cc4be7c85d..51701727e6 100644 --- a/py/scope.c +++ b/py/scope.c @@ -10,10 +10,8 @@ #include "scope.h" scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, uint unique_code_id, uint emit_options) { - scope_t *scope = m_new(scope_t, 1); + scope_t *scope = m_new0(scope_t, 1); scope->kind = kind; - scope->parent = NULL; - scope->next = NULL; scope->pn = pn; scope->source_file = source_file; switch (kind) { @@ -43,19 +41,10 @@ scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, uint default: assert(0); } - scope->id_info_alloc = 8; - scope->id_info_len = 0; - scope->id_info = m_new(id_info_t, scope->id_info_alloc); - - scope->scope_flags = 0; - scope->num_params = 0; - /* not needed - scope->num_default_params = 0; - scope->num_dict_params = 0; - */ - scope->num_locals = 0; scope->unique_code_id = unique_code_id; scope->emit_options = emit_options; + scope->id_info_alloc = 8; + scope->id_info = m_new(id_info_t, scope->id_info_alloc); return scope; } @@ -84,10 +73,10 @@ id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added) { // handled by the compiler because it adds arguments before compiling the body id_info_t *id_info = &scope->id_info[scope->id_info_len++]; - id_info->param = false; id_info->kind = 0; - id_info->qstr = qstr; + id_info->flags = 0; id_info->local_num = 0; + id_info->qstr = qstr; *added = true; return id_info; } diff --git a/py/scope.h b/py/scope.h index 7ecd1e19f9..07b41fe721 100644 --- a/py/scope.h +++ b/py/scope.h @@ -6,15 +6,18 @@ enum { ID_INFO_KIND_FREE, // in a function f, belongs to the parent of f }; -typedef struct _id_info_t { - // TODO compress this info to make structure smaller in memory - bool param; - int kind; - qstr qstr; +enum { + ID_FLAG_IS_PARAM = 0x01, + ID_FLAG_IS_DELETED = 0x02, +}; +typedef struct _id_info_t { + uint8_t kind; + uint8_t flags; // when it's an ID_INFO_KIND_LOCAL this is the unique number of the local // whet it's an ID_INFO_KIND_CELL/FREE this is the unique number of the closed over variable - int local_num; + uint16_t local_num; + qstr qstr; } id_info_t; // scope is a "block" in Python parlance @@ -26,20 +29,16 @@ typedef struct _scope_t { mp_parse_node_t pn; qstr source_file; qstr simple_name; - int id_info_alloc; - int id_info_len; - id_info_t *id_info; - uint scope_flags; // see runtime0.h - int num_params; - /* not needed - int num_default_params; - int num_dict_params; - */ - int num_locals; - int stack_size; // maximum size of the locals stack - int exc_stack_size; // maximum size of the exception stack uint unique_code_id; - uint emit_options; + uint8_t scope_flags; // see runtime0.h + uint8_t emit_options; // see compile.h + uint16_t num_params; + uint16_t num_locals; + uint16_t stack_size; // maximum size of the locals stack + uint16_t exc_stack_size; // maximum size of the exception stack + uint16_t id_info_alloc; + uint16_t id_info_len; + id_info_t *id_info; } scope_t; scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, uint unique_code_id, uint emit_options); diff --git a/py/showbc.c b/py/showbc.c index 823769c0ef..c1e420f433 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -123,6 +123,11 @@ void mp_byte_code_print(const byte *ip, int len) { printf("LOAD_FAST_N " UINT_FMT, unum); break; + case MP_BC_LOAD_FAST_CHECKED: + DECODE_UINT; + printf("LOAD_FAST_CHECKED " UINT_FMT, unum); + break; + case MP_BC_LOAD_DEREF: DECODE_UINT; printf("LOAD_DEREF " UINT_FMT, unum); @@ -193,9 +198,14 @@ void mp_byte_code_print(const byte *ip, int len) { printf("STORE_SUBSCR"); break; - case MP_BC_DELETE_FAST_N: + case MP_BC_DELETE_FAST: + DECODE_UINT; + printf("DELETE_FAST " UINT_FMT, unum); + break; + + case MP_BC_DELETE_DEREF: DECODE_UINT; - printf("DELETE_FAST_N " UINT_FMT, unum); + printf("DELETE_DEREF " UINT_FMT, unum); break; case MP_BC_DELETE_NAME: @@ -95,14 +95,15 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, state[n_state - 1 - n_args - i] = args2[i]; } + // set rest of state to MP_OBJ_NULL + for (uint i = 0; i < n_state - n_args - n_args2; i++) { + state[i] = MP_OBJ_NULL; + } + // bytecode prelude: initialise closed over variables for (uint n_local = *ip++; n_local > 0; n_local--) { uint local_num = *ip++; - if (local_num < n_args + n_args2) { - state[n_state - 1 - local_num] = mp_obj_new_cell(state[n_state - 1 - local_num]); - } else { - state[n_state - 1 - local_num] = mp_obj_new_cell(MP_OBJ_NULL); - } + state[n_state - 1 - local_num] = mp_obj_new_cell(state[n_state - 1 - local_num]); } // execute the byte code @@ -241,9 +242,23 @@ dispatch_loop: PUSH(fastn[-unum]); break; + case MP_BC_LOAD_FAST_CHECKED: + DECODE_UINT; + obj1 = fastn[-unum]; + if (obj1 == MP_OBJ_NULL) { + local_name_error: + nlr_raise(mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment")); + } + PUSH(obj1); + break; + case MP_BC_LOAD_DEREF: DECODE_UINT; - PUSH(mp_obj_cell_get(fastn[-unum])); + obj1 = mp_obj_cell_get(fastn[-unum]); + if (obj1 == MP_OBJ_NULL) { + goto local_name_error; + } + PUSH(obj1); break; case MP_BC_LOAD_NAME: @@ -314,19 +329,30 @@ dispatch_loop: sp -= 3; break; - case MP_BC_DELETE_FAST_N: + case MP_BC_DELETE_FAST: DECODE_UINT; + if (fastn[-unum] == MP_OBJ_NULL) { + goto local_name_error; + } fastn[-unum] = MP_OBJ_NULL; break; + case MP_BC_DELETE_DEREF: + DECODE_UINT; + if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) { + goto local_name_error; + } + mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL); + break; + case MP_BC_DELETE_NAME: DECODE_QSTR; mp_delete_name(qst); break; - case MP_BC_DELETE_SUBSCR: - mp_delete_subscr(sp[-1], sp[0]); - sp -= 2; + case MP_BC_DELETE_GLOBAL: + DECODE_QSTR; + mp_delete_global(qst); break; case MP_BC_DUP_TOP: |