diff options
57 files changed, 983 insertions, 377 deletions
@@ -32,7 +32,7 @@ Additional components: - examples/ -- a few example Python scripts. "make" is used to build the components, or "gmake" on BSD-based systems. -You will also need bash and python (2.7 or 3.3) for the stm port. +You will also need bash and python (2.7 or 3.3). The Unix version ---------------- @@ -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: diff --git a/stmhal/boards/make-pins.py b/stmhal/boards/make-pins.py index ee11934985..e3a3f583a5 100755 --- a/stmhal/boards/make-pins.py +++ b/stmhal/boards/make-pins.py @@ -92,17 +92,23 @@ class Pin(object): self.port = port self.pin = pin self.alt_fn = [] - self.board_name = None self.alt_fn_count = 0 self.adc_num = 0 self.adc_channel = 0 + self.board_pin = False def port_letter(self): return chr(self.port + ord('A')) - def pin_name(self): + def cpu_pin_name(self): return '{:s}{:d}'.format(self.port_letter(), self.pin) + def is_board_pin(self): + return self.board_pin + + def set_is_board_pin(self): + self.board_pin = True + def parse_adc(self, adc_str): if (adc_str[:3] != 'ADC'): return @@ -127,7 +133,7 @@ class Pin(object): def alt_fn_name(self, null_if_0=False): if null_if_0 and self.alt_fn_count == 0: return 'NULL' - return 'pin_{:s}_af'.format(self.pin_name()) + return 'pin_{:s}_af'.format(self.cpu_pin_name()) def adc_num_str(self): str = '' @@ -152,27 +158,40 @@ class Pin(object): print('};') print('') print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s}, {:s}, {:d});'.format( - self.pin_name(), self.port_letter(), self.pin, + self.cpu_pin_name(), self.port_letter(), self.pin, self.alt_fn_count, self.alt_fn_name(null_if_0=True), self.adc_num_str(), self.adc_channel)) print('') def print_header(self, hdr_file): hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.pin_name())) + format(self.cpu_pin_name())) if self.alt_fn_count > 0: hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. - format(self.pin_name())) + format(self.cpu_pin_name())) + +class NamedPin(object): + + def __init__(self, name, pin): + self._name = name + self._pin = pin + + def pin(self): + return self._pin + + def name(self): + return self._name class Pins(object): def __init__(self): - self.pins = [] - self.board_pins = [] + self.cpu_pins = [] # list of NamedPin objects + self.board_pins = [] # list of NamedPin objects def find_pin(self, port_num, pin_num): - for pin in self.pins: + for named_pin in self.cpu_pins: + pin = named_pin.pin() if pin.port == port_num and pin.pin == pin_num: return pin @@ -190,7 +209,7 @@ class Pins(object): pin.parse_af(af_idx - af_col, row[af_idx]) elif af_idx == af_col + 16: pin.parse_adc(row[af_idx]) - self.pins.append(pin) + self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) def parse_board_file(self, filename): with open(filename, 'r') as csvfile: @@ -202,26 +221,24 @@ class Pins(object): continue pin = self.find_pin(port_num, pin_num) if pin: - pin.board_name = row[0] - self.board_pins.append(pin) + pin.set_is_board_pin() + self.board_pins.append(NamedPin(row[0], pin)) - def print_named(self, label, pins): + def print_named(self, label, named_pins): print('const pin_named_pin_t pin_{:s}_pins[] = {{'.format(label)) - for pin in pins: - if pin.board_name: - if label == 'board': - pin_name = pin.board_name - else: - pin_name = pin.pin_name() - print(' {{ "{:s}", &pin_{:s} }},'.format(pin_name, pin.pin_name())) + for named_pin in named_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + print(' {{ "{:s}", &pin_{:s} }},'.format(named_pin.name(), pin.cpu_pin_name())) print(' { NULL, NULL }') print('};') def print(self): - for pin in self.pins: - if pin.board_name: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): pin.print() - self.print_named('cpu', self.pins) + self.print_named('cpu', self.cpu_pins) print('') self.print_named('board', self.board_pins) @@ -230,10 +247,11 @@ class Pins(object): print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) for channel in range(16): adc_found = False - for pin in self.pins: - if (pin.board_name and + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if (pin.is_board_pin() and (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): - print(' &pin_{:s}, // {:d}'.format(pin.pin_name(), channel)) + print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel)) adc_found = True break if not adc_found: @@ -243,8 +261,9 @@ class Pins(object): def print_header(self, hdr_filename): with open(hdr_filename, 'wt') as hdr_file: - for pin in self.pins: - if pin.board_name: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): pin.print_header(hdr_file) hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') diff --git a/stmhal/exti.c b/stmhal/exti.c index 552efdf080..5ea3db62bb 100644 --- a/stmhal/exti.c +++ b/stmhal/exti.c @@ -105,9 +105,12 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { OTG_HS_WKUP_IRQn, TAMP_STAMP_IRQn, RTC_WKUP_IRQn }; +// Set override_callback_obj to true if you want to unconditionally set the +// callback function. +// // NOTE: param is for C callers. Python can use closure to get an object bound // with the function. -uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_obj_t callback_obj, void *param) { +uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_obj_t callback_obj, bool override_callback_obj, void *param) { const pin_obj_t *pin = NULL; uint v_line; @@ -143,7 +146,7 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_ob } exti_vector_t *v = &exti_vector[v_line]; - if (v->callback_obj != mp_const_none && callback_obj != mp_const_none) { + if (!override_callback_obj && v->callback_obj != mp_const_none && callback_obj != mp_const_none) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d is already in use", v_line)); } @@ -272,7 +275,7 @@ STATIC mp_obj_t exti_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp mp_obj_t mode_obj = args[1]; mp_obj_t trigger_obj = args[2]; mp_obj_t callback_obj = args[3]; - self->line = exti_register(line_obj, mode_obj, trigger_obj, callback_obj, NULL); + self->line = exti_register(line_obj, mode_obj, trigger_obj, callback_obj, false, NULL); return self; } @@ -315,7 +318,8 @@ void Handle_EXTI_Irq(uint32_t line) { } else { // Uncaught exception; disable the callback so it doesn't run again. v->callback_obj = mp_const_none; - printf("Uncaught exception in EXTI interrupt handler on line %lu\n", line); + exti_disable(line); + printf("Uncaught exception in EXTI interrupt handler line %lu\n", line); mp_obj_print_exception((mp_obj_t)nlr.ret_val); } gc_unlock(); diff --git a/stmhal/exti.h b/stmhal/exti.h index a6b50b26e8..6feb9dceaf 100644 --- a/stmhal/exti.h +++ b/stmhal/exti.h @@ -22,7 +22,7 @@ void exti_init(void); -uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp_obj_t callback_obj, void *param); +uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp_obj_t callback_obj, bool override_callback_obj, void *param); void exti_enable(uint line); void exti_disable(uint line); diff --git a/stmhal/help.c b/stmhal/help.c index 25d3fcb57e..76dcb2f4ee 100644 --- a/stmhal/help.c +++ b/stmhal/help.c @@ -14,27 +14,36 @@ STATIC const char *help_text = "Specific commands for the board:\n" " pyb.info() -- print some general information\n" " pyb.gc() -- run the garbage collector\n" -" pyb.repl_info(<val>) -- enable/disable printing of info after each command\n" -" pyb.delay(<n>) -- wait for n milliseconds\n" -" pyb.udelay(<n>) -- wait for n microseconds\n" +" pyb.repl_info(val) -- enable/disable printing of info after each command\n" +" pyb.delay(n) -- wait for n milliseconds\n" +" pyb.udelay(n) -- wait for n microseconds\n" " pyb.switch() -- return True/False if switch pressed or not\n" -" pyb.Led(<n>) -- create Led object for LED n (n=1,2,3,4)\n" +" pyb.switch(f) -- call the given function when the switch is pressed\n" +" pyb.Led(n) -- create Led object for LED n (n=1,2,3,4)\n" " Led methods: on(), off(), toggle(), intensity(<n>)\n" -" pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n" -" Servo methods: angle(<x>)\n" +" pyb.Servo(n) -- create Servo object for servo n (n=1,2,3,4)\n" +" Servo methods: calibrate(...), pulse_width([p]), angle([x, [t]]), speed([x, [t]])\n" " pyb.Accel() -- create an Accelerometer object\n" -" Accelerometer methods: x(), y(), z(), tilt()\n" +" Accelerometer methods: x(), y(), z(), tilt(), filtered_xyz()\n" " pyb.rng() -- get a 30-bit hardware random number\n" -" pyb.gpio(<port>) -- get port value (port='A4' for example)\n" -" pyb.gpio(<port>, <val>) -- set port value, True or False, 1 or 0\n" -" pyb.ADC(<port>) -- make an analog port object (port='C0' for example)\n" +" pyb.gpio_in(port, [m]) -- set IO port to input, mode m\n" +" pyb.gpio_out(port, [m]) -- set IO port to output, mode m\n" +" pyb.gpio(port) -- get digital port value\n" +" pyb.gpio(port, val) -- set digital port value, True or False, 1 or 0\n" +" pyb.ADC(port) -- make an analog port object\n" " ADC methods: read()\n" "\n" +"Ports are numbered X1-X12, X17-X22, Y1-Y12, or by their MCU name\n" +"Port input modes are: pyb.PULL_NONE, pyb.PULL_UP, pyb.PULL_DOWN\n" +"Port output modes are: pyb.PUSH_PULL, pyb.OPEN_DRAIN\n" +"\n" "Control commands:\n" " CTRL-A -- on a blank line, enter raw REPL mode\n" " CTRL-B -- on a blank line, enter normal REPL mode\n" " CTRL-C -- interrupt a running program\n" " CTRL-D -- on a blank line, do a soft reset of the board\n" +"\n" +"For further help on a specific object, type help(obj)\n" ; STATIC void pyb_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { diff --git a/stmhal/main.c b/stmhal/main.c index e5ba67dc1d..64d9022aef 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -133,6 +133,10 @@ static const char fresh_main_py[] = "# main.py -- put your code here!\n" ; +static const char fresh_pybcdc_inf[] = +#include "pybcdc.h" +; + int main(void) { // TODO disable JTAG @@ -206,7 +210,9 @@ soft_reset: } HAL_Delay(20); if (i % 30 == 29) { - reset_mode = (reset_mode + 1) & 7; + if (++reset_mode > 3) { + reset_mode = 1; + } led_state(2, reset_mode & 1); led_state(3, reset_mode & 2); led_state(4, reset_mode & 4); @@ -310,6 +316,11 @@ soft_reset: // TODO check we could write n bytes f_close(&fp); + // create .inf driver file + f_open(&fp, "0:/pybcdc.inf", FA_WRITE | FA_CREATE_ALWAYS); + f_write(&fp, fresh_pybcdc_inf, sizeof(fresh_pybcdc_inf) - 1 /* don't count null terminator */, &n); + f_close(&fp); + // keep LED on for at least 200ms sys_tick_wait_at_least(start_tick, 200); led_state(PYB_LED_R2, 0); diff --git a/stmhal/pybcdc.h b/stmhal/pybcdc.h new file mode 100644 index 0000000000..44685a05ba --- /dev/null +++ b/stmhal/pybcdc.h @@ -0,0 +1,92 @@ +"; Windows USB CDC ACM Setup File\r\n" +"; Based on INF files which were:\r\n" +"; Copyright (c) 2000 Microsoft Corporation\r\n" +"; Copyright (C) 2007 Microchip Technology Inc.\r\n" +"; Likely to be covered by the MLPL as found at:\r\n" +"; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.\r\n" +"\r\n" +"[Version]\r\n" +"Signature=\"$Windows NT$\"\r\n" +"Class=Ports\r\n" +"ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}\r\n" +"Provider=%MFGNAME%\r\n" +"LayoutFile=layout.inf\r\n" +"DriverVer=03/11/2010,5.1.2600.3\r\n" +"\r\n" +"[Manufacturer]\r\n" +"%MFGNAME%=DeviceList, NTamd64\r\n" +"\r\n" +"[DestinationDirs]\r\n" +"DefaultDestDir=12\r\n" +"\r\n" +";---------------------------------------------------------------------\r\n" +"; Windows 2000/XP/Server2003/Vista/Server2008/7 - 32bit Sections\r\n" +"\r\n" +"[DriverInstall.nt]\r\n" +"include=mdmcpq.inf\r\n" +"CopyFiles=DriverCopyFiles.nt\r\n" +"AddReg=DriverInstall.nt.AddReg\r\n" +"\r\n" +"[DriverCopyFiles.nt]\r\n" +"usbser.sys,,,0x20\r\n" +"\r\n" +"[DriverInstall.nt.AddReg]\r\n" +"HKR,,DevLoader,,*ntkern\r\n" +"HKR,,NTMPDriver,,usbser.sys\r\n" +"HKR,,EnumPropPages32,,\"MsPorts.dll,SerialPortPropPageProvider\"\r\n" +"\r\n" +"[DriverInstall.nt.Services]\r\n" +"AddService=usbser, 0x00000002, DriverService.nt\r\n" +"\r\n" +"[DriverService.nt]\r\n" +"DisplayName=%SERVICE%\r\n" +"ServiceType=1\r\n" +"StartType=3\r\n" +"ErrorControl=1\r\n" +"ServiceBinary=%12%\\usbser.sys\r\n" +"\r\n" +";---------------------------------------------------------------------\r\n" +"; Windows XP/Server2003/Vista/Server2008/7 - 64bit Sections\r\n" +"\r\n" +"[DriverInstall.NTamd64]\r\n" +"include=mdmcpq.inf\r\n" +"CopyFiles=DriverCopyFiles.NTamd64\r\n" +"AddReg=DriverInstall.NTamd64.AddReg\r\n" +"\r\n" +"[DriverCopyFiles.NTamd64]\r\n" +"usbser.sys,,,0x20\r\n" +"\r\n" +"[DriverInstall.NTamd64.AddReg]\r\n" +"HKR,,DevLoader,,*ntkern\r\n" +"HKR,,NTMPDriver,,usbser.sys\r\n" +"HKR,,EnumPropPages32,,\"MsPorts.dll,SerialPortPropPageProvider\"\r\n" +"\r\n" +"[DriverInstall.NTamd64.Services]\r\n" +"AddService=usbser, 0x00000002, DriverService.NTamd64\r\n" +"\r\n" +"[DriverService.NTamd64]\r\n" +"DisplayName=%SERVICE%\r\n" +"ServiceType=1\r\n" +"StartType=3\r\n" +"ErrorControl=1\r\n" +"ServiceBinary=%12%\\usbser.sys\r\n" +"\r\n" +";---------------------------------------------------------------------\r\n" +"; Vendor and Product ID Definitions\r\n" +"\r\n" +"[SourceDisksFiles]\r\n" +"[SourceDisksNames]\r\n" +"[DeviceList]\r\n" +"%DESCRIPTION%=DriverInstall, USB\\VID_0483&PID_5740&MI_00, USB\\VID_0483&PID_5740&MI_01\r\n" +"\r\n" +"[DeviceList.NTamd64]\r\n" +"%DESCRIPTION%=DriverInstall, USB\\VID_0483&PID_5740&MI_00, USB\\VID_0483&PID_5740&MI_01\r\n" +"\r\n" +";---------------------------------------------------------------------\r\n" +"; String Definitions\r\n" +"\r\n" +"[Strings]\r\n" +"MFGFILENAME=\"pybcdc\"\r\n" +"MFGNAME=\"Micro Python\"\r\n" +"DESCRIPTION=\"Pyboard USB Comm Port\"\r\n" +"SERVICE=\"USB Serial Driver\"\r\n" diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 2c41f1b787..4eb6ea12a0 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -108,7 +108,10 @@ Q(dma) // for Servo object Q(Servo) +Q(pulse_width) +Q(calibrate) Q(angle) +Q(speed) // for os module Q(os) diff --git a/stmhal/servo.c b/stmhal/servo.c index 79a6843b7a..df002b8aed 100644 --- a/stmhal/servo.c +++ b/stmhal/servo.c @@ -20,11 +20,16 @@ typedef struct _pyb_servo_obj_t { mp_obj_base_t base; - uint16_t servo_id; - uint16_t time_left; + uint8_t servo_id; + uint8_t pulse_min; // units of 10us + uint8_t pulse_max; // units of 10us + uint8_t pulse_centre; // units of 10us + uint8_t pulse_angle_90; // units of 10us; pulse at 90 degrees, minus pulse_centre + uint8_t pulse_speed_100; // units of 10us; pulse at 100% forward speed, minus pulse_centre + uint16_t pulse_cur; // units of 10us + uint16_t pulse_dest; // units of 10us int16_t pulse_accum; - uint16_t pulse_cur; - uint16_t pulse_dest; + uint16_t time_left; } pyb_servo_obj_t; STATIC pyb_servo_obj_t pyb_servo_obj[PYB_SERVO_NUM]; @@ -36,9 +41,14 @@ void servo_init(void) { for (int i = 0; i < PYB_SERVO_NUM; i++) { pyb_servo_obj[i].base.type = &pyb_servo_type; pyb_servo_obj[i].servo_id = i + 1; - pyb_servo_obj[i].time_left = 0; - pyb_servo_obj[i].pulse_cur = 150; // units of 10us + pyb_servo_obj[i].pulse_min = 64; + pyb_servo_obj[i].pulse_max = 242; + pyb_servo_obj[i].pulse_centre = 150; + pyb_servo_obj[i].pulse_angle_90 = 97; + pyb_servo_obj[i].pulse_speed_100 = 70; + pyb_servo_obj[i].pulse_cur = 150; pyb_servo_obj[i].pulse_dest = 0; + pyb_servo_obj[i].time_left = 0; } } @@ -47,6 +57,13 @@ void servo_timer_irq_callback(void) { for (int i = 0; i < PYB_SERVO_NUM; i++) { pyb_servo_obj_t *s = &pyb_servo_obj[i]; if (s->pulse_cur != s->pulse_dest) { + // clamp pulse to within min/max + if (s->pulse_dest < s->pulse_min) { + s->pulse_dest = s->pulse_min; + } else if (s->pulse_dest > s->pulse_max) { + s->pulse_dest = s->pulse_max; + } + // adjust cur to get closer to dest if (s->time_left <= 1) { s->pulse_cur = s->pulse_dest; s->time_left = 0; @@ -57,6 +74,7 @@ void servo_timer_irq_callback(void) { s->time_left--; need_it = true; } + // set the pulse width switch (s->servo_id) { case 1: TIM5->CCR1 = s->pulse_cur; break; case 2: TIM5->CCR2 = s->pulse_cur; break; @@ -135,7 +153,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(pyb_pwm_set_obj, pyb_pwm_set); STATIC void pyb_servo_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_servo_obj_t *self = self_in; - print(env, "<Servo %lu at %lu>", self->servo_id, self->pulse_cur); + print(env, "<Servo %lu at %luus>", self->servo_id, 10 * self->pulse_cur); } STATIC mp_obj_t pyb_servo_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { @@ -159,20 +177,64 @@ STATIC mp_obj_t pyb_servo_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con return s; } +STATIC mp_obj_t pyb_servo_pulse_width(uint n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = args[0]; + if (n_args == 1) { + // get pulse width, in us + return mp_obj_new_int(10 * self->pulse_cur); + } else { + // set pulse width, in us + self->pulse_dest = mp_obj_get_int(args[1]) / 10; + self->time_left = 0; + servo_timer_irq_callback(); + return mp_const_none; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_pulse_width_obj, 1, 2, pyb_servo_pulse_width); + +STATIC mp_obj_t pyb_servo_calibrate(uint n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = args[0]; + if (n_args == 1) { + // get calibration values + mp_obj_t tuple[5]; + tuple[0] = mp_obj_new_int(10 * self->pulse_min); + tuple[1] = mp_obj_new_int(10 * self->pulse_max); + tuple[2] = mp_obj_new_int(10 * self->pulse_centre); + tuple[3] = mp_obj_new_int(10 * (self->pulse_angle_90 + self->pulse_centre)); + tuple[4] = mp_obj_new_int(10 * (self->pulse_speed_100 + self->pulse_centre)); + return mp_obj_new_tuple(5, tuple); + } else if (n_args >= 4) { + // set min, max, centre + self->pulse_min = mp_obj_get_int(args[1]) / 10; + self->pulse_max = mp_obj_get_int(args[2]) / 10; + self->pulse_centre = mp_obj_get_int(args[3]) / 10; + if (n_args == 4) { + return mp_const_none; + } else if (n_args == 6) { + self->pulse_angle_90 = mp_obj_get_int(args[4]) / 10 - self->pulse_centre; + self->pulse_speed_100 = mp_obj_get_int(args[5]) / 10 - self->pulse_centre; + return mp_const_none; + } + } + + // bad number of arguments + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "calibrate expecting 1, 4 or 6 arguments, got %d", n_args)); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_calibrate_obj, 1, 6, pyb_servo_calibrate); + STATIC mp_obj_t pyb_servo_angle(uint n_args, const mp_obj_t *args) { pyb_servo_obj_t *self = args[0]; if (n_args == 1) { // get angle - return mp_obj_new_int((self->pulse_cur - 152) * 90 / 85); + return mp_obj_new_int((self->pulse_cur - self->pulse_centre) * 90 / self->pulse_angle_90); } else { #if MICROPY_ENABLE_FLOAT - machine_int_t v = 152 + 85.0 * mp_obj_get_float(args[1]) / 90.0; + self->pulse_dest = self->pulse_centre + self->pulse_angle_90 * mp_obj_get_float(args[1]) / 90.0; #else - machine_int_t v = 152 + 85 * mp_obj_get_int(args[1]) / 90; + self->pulse_dest = self->pulse_centre + self->pulse_angle_90 * mp_obj_get_int(args[1]) / 90; #endif - if (v < 65) { v = 65; } - if (v > 210) { v = 210; } - self->pulse_dest = v; if (n_args == 2) { // set angle immediately self->time_left = 0; @@ -188,8 +250,37 @@ STATIC mp_obj_t pyb_servo_angle(uint n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_angle_obj, 1, 3, pyb_servo_angle); +STATIC mp_obj_t pyb_servo_speed(uint n_args, const mp_obj_t *args) { + pyb_servo_obj_t *self = args[0]; + if (n_args == 1) { + // get speed + return mp_obj_new_int((self->pulse_cur - self->pulse_centre) * 100 / self->pulse_speed_100); + } else { +#if MICROPY_ENABLE_FLOAT + self->pulse_dest = self->pulse_centre + self->pulse_speed_100 * mp_obj_get_float(args[1]) / 100.0; +#else + self->pulse_dest = self->pulse_centre + self->pulse_speed_100 * mp_obj_get_int(args[1]) / 100; +#endif + if (n_args == 2) { + // set speed immediately + self->time_left = 0; + } else { + // set speed over a given time (given in milli seconds) + self->time_left = mp_obj_get_int(args[2]) / 20; + self->pulse_accum = 0; + } + servo_timer_irq_callback(); + return mp_const_none; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_speed_obj, 1, 3, pyb_servo_speed); + STATIC const mp_map_elem_t pyb_servo_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width), (mp_obj_t)&pyb_servo_pulse_width_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_calibrate), (mp_obj_t)&pyb_servo_calibrate_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_angle), (mp_obj_t)&pyb_servo_angle_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_speed), (mp_obj_t)&pyb_servo_speed_obj }, }; STATIC MP_DEFINE_CONST_DICT(pyb_servo_locals_dict, pyb_servo_locals_dict_table); diff --git a/stmhal/usrsw.c b/stmhal/usrsw.c index 453c3dfa82..5133392ccd 100644 --- a/stmhal/usrsw.c +++ b/stmhal/usrsw.c @@ -49,14 +49,9 @@ void switch_init0(void) { HAL_GPIO_Init(MICROPY_HW_USRSW_PIN.gpio, &init); } -// this function inits the callback and EXTI function of the switch +// this function inits the callback pointer void switch_init(void) { switch_user_callback_obj = mp_const_none; - exti_register((mp_obj_t)&MICROPY_HW_USRSW_PIN, - MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_EXTI_MODE), - MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_PULL), - (mp_obj_t)&switch_callback_obj, - NULL); } int switch_get(void) { @@ -70,9 +65,19 @@ int switch_get(void) { static mp_obj_t pyb_switch(uint n_args, mp_obj_t *args) { if (n_args == 0) { return switch_get() ? mp_const_true : mp_const_false; + } else { + switch_user_callback_obj = args[0]; + // Init the EXTI each time this function is called, since the EXTI + // may have been disabled by an exception in the interrupt, or the + // user disabling the line explicitly. + exti_register((mp_obj_t)&MICROPY_HW_USRSW_PIN, + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_EXTI_MODE), + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_PULL), + switch_user_callback_obj == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj, + true, + NULL); + return mp_const_none; } - switch_user_callback_obj = args[0]; - return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_switch_obj, 0, 1, pyb_switch); diff --git a/tests/basics/bytearray1.py b/tests/basics/bytearray1.py index 201b5b6590..e564165b9f 100644 --- a/tests/basics/bytearray1.py +++ b/tests/basics/bytearray1.py @@ -1,5 +1,6 @@ print(bytearray(4)) a = bytearray([1, 2, 200]) +print(type(a)) print(a[0], a[2]) print(a[-1]) print(a) diff --git a/tests/basics/del-attr.py b/tests/basics/del-attr.py new file mode 100644 index 0000000000..bec7afb848 --- /dev/null +++ b/tests/basics/del-attr.py @@ -0,0 +1,32 @@ +class C: + def f(): + pass + +# del a class attribute + +del C.f +try: + print(C.x) +except AttributeError: + print("AttributeError") +try: + del C.f +except AttributeError: + print("AttributeError") + +# del an instance attribute + +c = C() + +c.x = 1 +print(c.x) + +del c.x +try: + print(c.x) +except AttributeError: + print("AttributeError") +try: + del c.x +except AttributeError: + print("AttributeError") diff --git a/tests/basics/del-deref.py b/tests/basics/del-deref.py new file mode 100644 index 0000000000..1e7c0e41f4 --- /dev/null +++ b/tests/basics/del-deref.py @@ -0,0 +1,22 @@ +def f(): + x = 1 + y = 2 + def g(): + nonlocal x + print(y) + try: + print(x) + except NameError: + print("NameError") + def h(): + nonlocal x + print(y) + try: + del x + except NameError: + print("NameError") + print(x, y) + del x + g() + h() +f() diff --git a/tests/basics/del-local.py b/tests/basics/del-local.py new file mode 100644 index 0000000000..05aa98b424 --- /dev/null +++ b/tests/basics/del-local.py @@ -0,0 +1,25 @@ +# delete local then try to reference it +def f(): + x = 1 + y = 2 + print(x, y) + del x + print(y) + try: + print(x) + except NameError: + print("NameError"); +f() + +# delete local then try to delete it again +def g(): + x = 3 + y = 4 + print(x, y) + del x + print(y) + try: + del x + except NameError: + print("NameError"); +g() diff --git a/tests/basics/del-name.py b/tests/basics/del-name.py new file mode 100644 index 0000000000..f75a2f5dc6 --- /dev/null +++ b/tests/basics/del-name.py @@ -0,0 +1,18 @@ +# del global + +x = 1 +print(x) +del x +try: + print(x) +except NameError: + print("NameError") +try: + del x +except: # NameError: + # FIXME uPy returns KeyError for this + print("NameError") + +class C: + def f(): + pass diff --git a/tests/basics/del-subscr.py b/tests/basics/del-subscr.py new file mode 100644 index 0000000000..67910c6234 --- /dev/null +++ b/tests/basics/del-subscr.py @@ -0,0 +1,13 @@ +l = [1, 2, 3] +print(l) +del l[0] +print(l) +del l[-1] +print(l) + +d = {1:2, 3:4, 5:6} +del d[1] +del d[3] +print(d) +del d[5] +print(d) diff --git a/tests/basics/generator-closure.py b/tests/basics/generator-closure.py new file mode 100644 index 0000000000..d8a517edeb --- /dev/null +++ b/tests/basics/generator-closure.py @@ -0,0 +1,26 @@ +# a generator that closes over outer variables +def f(): + x = 1 # closed over by g + def g(): + yield x + yield x + 1 + return g() +for i in f(): + print(i) + +# a generator that has its variables closed over +def f(): + x = 1 # closed over by g + def g(): + return x + 1 + yield g() + x = 2 + yield g() +for i in f(): + print(i) + +# using comprehensions, the inner generator closes over y +generator_of_generators = (((x, y) for x in range(2)) for y in range(3)) +for i in generator_of_generators: + for j in i: + print(j) diff --git a/tests/basics/int-bytes.py b/tests/basics/int-bytes.py new file mode 100644 index 0000000000..45965ed464 --- /dev/null +++ b/tests/basics/int-bytes.py @@ -0,0 +1,6 @@ +print((10).to_bytes(1, "little")) +print((111111).to_bytes(4, "little")) +print((100).to_bytes(10, "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x01\0\0\0\0\0\0\0", "little")) +print(int.from_bytes(b"\x00\x01\0\0\0\0\0\0", "little")) diff --git a/tests/basics/string-join.py b/tests/basics/string-join.py new file mode 100644 index 0000000000..275a804c64 --- /dev/null +++ b/tests/basics/string-join.py @@ -0,0 +1,12 @@ +print(','.join(())) +print(','.join(('a',))) +print(','.join(('a', 'b'))) + +print(','.join([])) +print(','.join(['a'])) +print(','.join(['a', 'b'])) + +print(''.join('')) +print(''.join('abc')) +print(','.join('abc')) +print(','.join('abc' for i in range(5))) diff --git a/unix/modsocket.c b/unix/modsocket.c index 62f10300f8..8f47a8b157 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -34,21 +34,6 @@ STATIC const mp_obj_type_t microsocket_type; { if (err_flag == -1) \ { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error_val)); } } -STATIC void get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) { - mp_obj_base_t *o = (mp_obj_base_t *)obj; - if (o->type->buffer_p.get_buffer == NULL) { - goto error; - } - o->type->buffer_p.get_buffer(o, bufinfo, BUFFER_READ); - if (bufinfo->buf == NULL) { - goto error; - } - return; - -error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Operation not supported")); -} - STATIC mp_obj_socket_t *socket_new(int fd) { mp_obj_socket_t *o = m_new_obj(mp_obj_socket_t); o->base.type = µsocket_type; @@ -96,7 +81,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = self_in; buffer_info_t bufinfo; - get_buffer(addr_in, &bufinfo); + mp_get_buffer_raise(addr_in, &bufinfo); int r = connect(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); RAISE_ERRNO(r, errno); return mp_const_none; @@ -106,7 +91,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = self_in; buffer_info_t bufinfo; - get_buffer(addr_in, &bufinfo); + mp_get_buffer_raise(addr_in, &bufinfo); int r = bind(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len); RAISE_ERRNO(r, errno); return mp_const_none; @@ -184,7 +169,7 @@ STATIC mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) { optlen = sizeof(val); } else { buffer_info_t bufinfo; - get_buffer(args[3], &bufinfo); + mp_get_buffer_raise(args[3], &bufinfo); optval = bufinfo.buf; optlen = bufinfo.len; } |