summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--py/bc0.h18
-rw-r--r--py/builtintables.c2
-rw-r--r--py/compile.c101
-rw-r--r--py/compile.h1
-rw-r--r--py/emit.h11
-rw-r--r--py/emitbc.c55
-rw-r--r--py/emitcommon.c2
-rw-r--r--py/emitcpy.c18
-rw-r--r--py/emitnative.c12
-rw-r--r--py/emitpass1.c3
-rw-r--r--py/gc.c2
-rw-r--r--py/mpz.c5
-rw-r--r--py/obj.c27
-rw-r--r--py/obj.h15
-rw-r--r--py/objarray.c36
-rw-r--r--py/objarray.h2
-rw-r--r--py/objcomplex.c38
-rw-r--r--py/objdict.c9
-rw-r--r--py/objgenerator.c23
-rw-r--r--py/objint.c82
-rw-r--r--py/objint.h2
-rw-r--r--py/objint_longlong.c8
-rw-r--r--py/objint_mpz.c26
-rw-r--r--py/objlist.c12
-rw-r--r--py/objmodule.c10
-rw-r--r--py/objstr.c17
-rw-r--r--py/objtype.c34
-rw-r--r--py/pfenv.c75
-rw-r--r--py/pfenv.h2
-rw-r--r--py/qstrdefs.h2
-rw-r--r--py/runtime.c47
-rw-r--r--py/runtime.h2
-rw-r--r--py/runtime0.h1
-rw-r--r--py/scope.c21
-rw-r--r--py/scope.h37
-rw-r--r--py/showbc.c14
-rw-r--r--py/vm.c46
-rwxr-xr-xstmhal/boards/make-pins.py75
-rw-r--r--stmhal/exti.c12
-rw-r--r--stmhal/exti.h2
-rw-r--r--stmhal/help.c29
-rw-r--r--stmhal/main.c13
-rw-r--r--stmhal/pybcdc.h92
-rw-r--r--stmhal/qstrdefsport.h3
-rw-r--r--stmhal/servo.c117
-rw-r--r--stmhal/usrsw.c21
-rw-r--r--tests/basics/bytearray1.py1
-rw-r--r--tests/basics/del-attr.py32
-rw-r--r--tests/basics/del-deref.py22
-rw-r--r--tests/basics/del-local.py25
-rw-r--r--tests/basics/del-name.py18
-rw-r--r--tests/basics/del-subscr.py13
-rw-r--r--tests/basics/generator-closure.py26
-rw-r--r--tests/basics/int-bytes.py6
-rw-r--r--tests/basics/string-join.py12
-rw-r--r--unix/modsocket.c21
57 files changed, 983 insertions, 377 deletions
diff --git a/README.md b/README.md
index 0fc5c4c1f1..46aab0fa39 100644
--- a/README.md
+++ b/README.md
@@ -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
----------------
diff --git a/py/bc0.h b/py/bc0.h
index 80a8248de7..e6a0e21241 100644
--- a/py/bc0.h
+++ b/py/bc0.h
@@ -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,
diff --git a/py/emit.h b/py/emit.h
index 20128fc75b..5ce11af92d 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -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 = {
diff --git a/py/gc.c b/py/gc.c
index 7e3ffe9e3e..d39307464b 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -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
diff --git a/py/mpz.c b/py/mpz.c
index a6b024ca87..b42e96ee18 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -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) {
diff --git a/py/obj.c b/py/obj.c
index 8d5467c5e7..844ec41216 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -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"));
+ }
+}
diff --git a/py/obj.h b/py/obj.h
index 77cf7838ee..b944d2fcb5 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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:
diff --git a/py/vm.c b/py/vm.c
index 869a9381ad..b9147d1d32 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -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 = &microsocket_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;
}