summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorScott Shawcroft <scott@chickadee.tech>2016-10-10 11:42:59 -0700
committerScott Shawcroft <scott@chickadee.tech>2016-10-10 11:42:59 -0700
commita52fd670e66e72dc60d460016a2f1f03a65dbeb6 (patch)
tree3b5af151ff68fcbf772e5348efd43d770445508c /py
parenta6254f4344be4f54232149adb5d834ab9561846c (diff)
parent89bfbfdeee2c86a18ccab6dce41bbd3e4597c981 (diff)
Merge remote-tracking branch 'micropython/master'
Diffstat (limited to 'py')
-rw-r--r--py/argcheck.c5
-rw-r--r--py/compile.c54
-rw-r--r--py/emitbc.c36
-rw-r--r--py/emitcommon.c16
-rw-r--r--py/modio.c2
-rw-r--r--py/modmicropython.c1
-rw-r--r--py/modstruct.c4
-rw-r--r--py/modthread.c2
-rw-r--r--py/objbool.c23
-rw-r--r--py/objfun.c33
-rw-r--r--py/objset.c29
-rw-r--r--py/objstr.c5
-rw-r--r--py/objstringio.c2
-rw-r--r--py/runtime.c4
-rw-r--r--py/runtime.h1
-rw-r--r--py/scope.c89
-rw-r--r--py/scope.h21
-rw-r--r--py/stream.c18
-rw-r--r--py/vm.c51
19 files changed, 181 insertions, 215 deletions
diff --git a/py/argcheck.c b/py/argcheck.c
index 5733c77f1..a6c769ee8 100644
--- a/py/argcheck.c
+++ b/py/argcheck.c
@@ -105,10 +105,9 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
out_vals[i].u_bool = mp_obj_is_true(given_arg);
} else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_INT) {
out_vals[i].u_int = mp_obj_get_int(given_arg);
- } else if ((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ) {
- out_vals[i].u_obj = given_arg;
} else {
- assert(0);
+ assert((allowed[i].flags & MP_ARG_KIND_MASK) == MP_ARG_OBJ);
+ out_vals[i].u_obj = given_arg;
}
}
if (pos_found < n_pos) {
diff --git a/py/compile.c b/py/compile.c
index 7207ac2e0..0ea8a3c15 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -499,8 +499,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
// sequence of many items
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);
- } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
- // TODO can we ever get here? can it be compiled?
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
goto cannot_assign;
} else {
// sequence with 2 items
@@ -900,8 +899,7 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
for (int i = 0; i < n; i++) {
c_del_stmt(comp, pns1->nodes[i]);
}
- } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
- // TODO not implemented; can't del comprehension? can we get here?
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) {
goto cannot_delete;
} else {
// sequence with 2 items
@@ -1172,17 +1170,14 @@ STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) {
bool added;
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added);
- if (!added && id_info->kind != ID_INFO_KIND_FREE) {
+ if (added) {
+ scope_find_local_and_close_over(comp->scope_cur, id_info, qst);
+ if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
+ compile_syntax_error(comp, pn, "no binding for nonlocal found");
+ }
+ } else if (id_info->kind != ID_INFO_KIND_FREE) {
compile_syntax_error(comp, pn, "identifier redefined as nonlocal");
- return;
- }
- id_info_t *id_info2 = scope_find_local_in_parent(comp->scope_cur, qst);
- if (id_info2 == NULL || !(id_info2->kind == ID_INFO_KIND_LOCAL || id_info2->kind == ID_INFO_KIND_CELL || id_info2->kind == ID_INFO_KIND_FREE)) {
- compile_syntax_error(comp, pn, "no binding for nonlocal found");
- return;
}
- id_info->kind = ID_INFO_KIND_FREE;
- scope_close_over_in_parents(comp->scope_cur, qst);
}
STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -1495,6 +1490,8 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
EMIT_ARG(label_assign, l1); // start of exception handler
EMIT(start_except_handler);
+ // at this point the top of the stack contains the exception instance that was raised
+
uint l2 = comp_next_label(comp);
for (int i = 0; i < n_except; i++) {
@@ -1528,16 +1525,13 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
EMIT_ARG(pop_jump_if, false, end_finally_label);
}
- EMIT(pop_top);
-
+ // either discard or store the exception instance
if (qstr_exception_local == 0) {
EMIT(pop_top);
} else {
compile_store_id(comp, qstr_exception_local);
}
- EMIT(pop_top);
-
uint l3 = 0;
if (qstr_exception_local != 0) {
l3 = comp_next_label(comp);
@@ -1561,7 +1555,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
}
EMIT_ARG(jump, l2);
EMIT_ARG(label_assign, end_finally_label);
- EMIT_ARG(adjust_stack_size, 3); // stack adjust for the 3 exception items
+ EMIT_ARG(adjust_stack_size, 1); // stack adjust for the exception instance
}
compile_decrease_except_level(comp);
@@ -1711,14 +1705,12 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns
EMIT_LOAD_GLOBAL(MP_QSTR_StopAsyncIteration);
EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH);
EMIT_ARG(pop_jump_if, false, try_finally_label);
- EMIT(pop_top);
- EMIT(pop_top);
- EMIT(pop_top);
+ EMIT(pop_top); // pop exception instance
EMIT(pop_except);
EMIT_ARG(jump, while_else_label);
EMIT_ARG(label_assign, try_finally_label);
- EMIT_ARG(adjust_stack_size, 3);
+ EMIT_ARG(adjust_stack_size, 1); // if we jump here, the exc is on the stack
compile_decrease_except_level(comp);
EMIT(end_finally);
EMIT(end_except_handler);
@@ -1779,9 +1771,21 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
EMIT_ARG(label_assign, try_exception_label); // start of exception handler
EMIT(start_except_handler);
- EMIT(rot_three);
+
+ // at this point the stack contains: ..., __aexit__, self, exc
+ EMIT(dup_top);
+ #if MICROPY_CPYTHON_COMPAT
+ EMIT_ARG(load_attr, MP_QSTR___class__); // get type(exc)
+ #else
+ compile_load_id(comp, MP_QSTR_type);
+ EMIT(rot_two);
+ EMIT_ARG(call_function, 1, 0, 0); // get type(exc)
+ #endif
EMIT(rot_two);
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // dummy traceback value
+ // at this point the stack contains: ..., __aexit__, self, type(exc), exc, None
EMIT_ARG(call_method, 3, 0, 0);
+
compile_yield_from(comp);
EMIT_ARG(pop_jump_if, true, no_reraise_label);
EMIT_ARG(raise_varargs, 0);
@@ -1790,7 +1794,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
EMIT(pop_except);
EMIT_ARG(jump, end_label);
- EMIT_ARG(adjust_stack_size, 5);
+ EMIT_ARG(adjust_stack_size, 3); // adjust for __aexit__, self, exc
compile_decrease_except_level(comp);
EMIT(end_finally);
EMIT(end_except_handler);
@@ -3279,7 +3283,7 @@ STATIC void scope_compute_things(scope_t *scope) {
// __class__ is not counted as a local; if it's used then it becomes a ID_INFO_KIND_CELL
continue;
}
- if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
+ if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
}
// params always count for 1 local, even if they are a cell
diff --git a/py/emitbc.c b/py/emitbc.c
index 8c712e1fd..d6f2bf333 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -302,15 +302,6 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, byte b1, mp_uint
c[2] = bytecode_offset >> 8;
}
-#if MICROPY_EMIT_NATIVE
-STATIC void mp_emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
- (void)emit;
- (void)op;
- (void)arg1;
- (void)arg2;
-}
-#endif
-
void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
emit->pass = pass;
emit->stack_size = 0;
@@ -408,9 +399,7 @@ void mp_emit_bc_end_pass(emit_t *emit) {
}
// check stack is back to zero size
- if (emit->stack_size != 0) {
- mp_printf(&mp_plat_print, "ERROR: stack size not back to zero; got %d\n", emit->stack_size);
- }
+ assert(emit->stack_size == 0);
emit_write_code_info_byte(emit, 0); // end of line number info
@@ -528,9 +517,10 @@ void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break;
case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break;
case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break;
- no_other_choice:
- case MP_TOKEN_ELLIPSIS: emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj)); break;
- default: assert(0); goto no_other_choice; // to help flow control analysis
+ default:
+ assert(tok == MP_TOKEN_ELLIPSIS);
+ emit_write_bytecode_byte_obj(emit, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));
+ break;
}
}
@@ -751,10 +741,9 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept
}
void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) {
- // TODO We can probably optimise the amount of needed stack space, since
- // we don't actually need 4 slots during the entire with block, only in
- // the cleanup handler in certain cases. It needs some thinking.
- emit_bc_pre(emit, 4);
+ // The SETUP_WITH opcode pops ctx_mgr from the top of the stack
+ // and then pushes 3 entries: __exit__, ctx_mgr, as_value.
+ emit_bc_pre(emit, 2);
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
}
@@ -762,8 +751,9 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {
mp_emit_bc_pop_block(emit);
mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE);
mp_emit_bc_label_assign(emit, label);
- emit_bc_pre(emit, -4);
+ emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method
emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP);
+ emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_with
}
void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) {
@@ -955,16 +945,16 @@ void mp_emit_bc_yield_from(emit_t *emit) {
}
void mp_emit_bc_start_except_handler(emit_t *emit) {
- mp_emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
+ mp_emit_bc_adjust_stack_size(emit, 4); // stack adjust for the exception instance, +3 for possible UNWIND_JUMP state
}
void mp_emit_bc_end_except_handler(emit_t *emit) {
- mp_emit_bc_adjust_stack_size(emit, -5); // stack adjust
+ mp_emit_bc_adjust_stack_size(emit, -3); // stack adjust
}
#if MICROPY_EMIT_NATIVE
const emit_method_table_t emit_bc_method_table = {
- mp_emit_bc_set_native_type,
+ NULL, // set_native_type is never called when emitting bytecode
mp_emit_bc_start_pass,
mp_emit_bc_end_pass,
mp_emit_bc_last_emit_was_return_value,
diff --git a/py/emitcommon.c b/py/emitcommon.c
index 435188f36..e914431d3 100644
--- a/py/emitcommon.c
+++ b/py/emitcommon.c
@@ -35,13 +35,7 @@ void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) {
bool added;
id_info_t *id = scope_find_or_add_id(scope, qst, &added);
if (added) {
- id_info_t *id2 = scope_find_local_in_parent(scope, qst);
- if (id2 != NULL && (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE)) {
- id->kind = ID_INFO_KIND_FREE;
- scope_close_over_in_parents(scope, qst);
- } else {
- id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
- }
+ scope_find_local_and_close_over(scope, id, qst);
}
}
@@ -50,12 +44,12 @@ void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) {
bool added;
id_info_t *id = scope_find_or_add_id(scope, qst, &added);
if (added) {
- if (scope->kind == SCOPE_MODULE || scope->kind == SCOPE_CLASS) {
- id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
- } else {
+ if (SCOPE_IS_FUNC_LIKE(scope->kind)) {
id->kind = ID_INFO_KIND_LOCAL;
+ } else {
+ id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
}
- } else if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
+ } else if (SCOPE_IS_FUNC_LIKE(scope->kind) && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
// rebind as a local variable
id->kind = ID_INFO_KIND_LOCAL;
}
diff --git a/py/modio.c b/py/modio.c
index 2a38af602..d5da0b1db 100644
--- a/py/modio.c
+++ b/py/modio.c
@@ -102,7 +102,7 @@ STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) {
assert(out_sz == self->len);
self->len = 0;
if (err != 0) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err)));
+ mp_raise_OSError(err);
}
}
diff --git a/py/modmicropython.c b/py/modmicropython.c
index 31ae7025f..f7d74db2e 100644
--- a/py/modmicropython.c
+++ b/py/modmicropython.c
@@ -120,6 +120,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_
STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) },
+ { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) },
#if MICROPY_PY_MICROPYTHON_MEM_INFO
#if MICROPY_MEM_STATS
{ MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) },
diff --git a/py/modstruct.c b/py/modstruct.c
index 5c07b8102..88411ff0f 100644
--- a/py/modstruct.c
+++ b/py/modstruct.c
@@ -156,9 +156,6 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
}
for (uint i = 0; i < num_items;) {
- if (*fmt == '\0') {
- break;
- }
mp_uint_t sz = 1;
if (unichar_isdigit(*fmt)) {
sz = get_fmt_num(&fmt);
@@ -191,6 +188,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, byte* end_p, siz
for (i = 0; i < n_args;) {
mp_uint_t sz = 1;
if (*fmt == '\0') {
+ // more arguments given than used by format string; CPython raises struct.error here
break;
}
if (unichar_isdigit(*fmt)) {
diff --git a/py/modthread.c b/py/modthread.c
index 24b94f1c8..c358cdf9e 100644
--- a/py/modthread.c
+++ b/py/modthread.c
@@ -93,7 +93,7 @@ STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) {
self->locked = true;
return mp_const_true;
} else {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-ret)));
+ mp_raise_OSError(-ret);
}
#endif
}
diff --git a/py/objbool.c b/py/objbool.c
index 8882a835d..5bc04bb6f 100644
--- a/py/objbool.c
+++ b/py/objbool.c
@@ -56,26 +56,19 @@ STATIC mp_obj_t bool_make_new(const mp_obj_type_t *type_in, size_t n_args, size_
(void)type_in;
mp_arg_check_num(n_args, n_kw, 0, 1, false);
- switch (n_args) {
- case 0:
- return mp_const_false;
- case 1:
- default: // must be 0 or 1
- if (mp_obj_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; }
+ if (n_args == 0) {
+ return mp_const_false;
+ } else {
+ return mp_obj_new_bool(mp_obj_is_true(args[0]));
}
}
STATIC mp_obj_t bool_unary_op(mp_uint_t op, mp_obj_t o_in) {
- mp_int_t value = ((mp_obj_bool_t*)MP_OBJ_TO_PTR(o_in))->value;
- switch (op) {
- case MP_UNARY_OP_BOOL: return o_in;
- // needs to hash to the same value as if converting to an integer
- case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(value);
- case MP_UNARY_OP_POSITIVE: return MP_OBJ_NEW_SMALL_INT(value);
- case MP_UNARY_OP_NEGATIVE: return MP_OBJ_NEW_SMALL_INT(-value);
- case MP_UNARY_OP_INVERT: return MP_OBJ_NEW_SMALL_INT(~value);
- default: return MP_OBJ_NULL; // op not supported
+ if (op == MP_UNARY_OP_LEN) {
+ return MP_OBJ_NULL;
}
+ mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in);
+ return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value));
}
STATIC mp_obj_t bool_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
diff --git a/py/objfun.c b/py/objfun.c
index 3fd25fb22..405f38127 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -266,23 +266,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
#endif
mp_obj_t result;
- switch (vm_return_kind) {
- case MP_VM_RETURN_NORMAL:
- // return value is in *sp
- result = *code_state->sp;
- break;
-
- case MP_VM_RETURN_EXCEPTION:
- // return value is in state[n_state - 1]
- result = code_state->state[n_state - 1];
- break;
-
- case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
- default:
- assert(0);
- result = mp_const_none;
- vm_return_kind = MP_VM_RETURN_NORMAL;
- break;
+ if (vm_return_kind == MP_VM_RETURN_NORMAL) {
+ // return value is in *sp
+ result = *code_state->sp;
+ } else {
+ // must be an exception because normal functions can't yield
+ assert(vm_return_kind == MP_VM_RETURN_EXCEPTION);
+ // return value is in fastn[0]==state[n_state - 1]
+ result = code_state->state[n_state - 1];
}
// free the state if it was allocated on the heap
@@ -409,17 +400,15 @@ STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, size_t n_args, size_t n_kw, con
ret = ((viper_fun_2_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8));
} else if (n_args == 3) {
ret = ((viper_fun_3_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 4), mp_convert_obj_to_native(args[1], self->type_sig >> 8), mp_convert_obj_to_native(args[2], self->type_sig >> 12));
- } else if (n_args == 4) {
+ } else {
+ // compiler allows at most 4 arguments
+ assert(n_args == 4);
ret = ((viper_fun_4_t)fun)(
mp_convert_obj_to_native(args[0], self->type_sig >> 4),
mp_convert_obj_to_native(args[1], self->type_sig >> 8),
mp_convert_obj_to_native(args[2], self->type_sig >> 12),
mp_convert_obj_to_native(args[3], self->type_sig >> 16)
);
- } else {
- // TODO 5 or more arguments not supported for viper call
- assert(0);
- ret = 0;
}
return mp_convert_native_to_obj(ret, self->type_sig);
diff --git a/py/objset.c b/py/objset.c
index fb89c07f3..6b6f95f9b 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -57,27 +57,21 @@ STATIC bool is_set_or_frozenset(mp_obj_t o) {
;
}
-#if MICROPY_PY_BUILTINS_FROZENSET
-STATIC void check_set_or_frozenset(mp_obj_t o) {
- if (!is_set_or_frozenset(o)) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required"));
- }
-}
-#else
-#define check_set_or_frozenset(o) check_set(o)
-#endif
+// This macro is shorthand for mp_check_self to verify the argument is a
+// set or frozenset for methods that operate on both of these types.
+#define check_set_or_frozenset(o) mp_check_self(is_set_or_frozenset(o))
+// This function is used to verify the argument for methods that modify
+// the set object, and raises an exception if the arg is a frozenset.
STATIC void check_set(mp_obj_t o) {
- if (!MP_OBJ_IS_TYPE(o, &mp_type_set)) {
- // Emulate CPython behavior
+ #if MICROPY_PY_BUILTINS_FROZENSET
+ if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) {
+ // Mutable method called on frozenset; emulate CPython behavior, eg:
// AttributeError: 'frozenset' object has no attribute 'add'
- #if MICROPY_PY_BUILTINS_FROZENSET
- if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"));
- }
- #endif
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required"));
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"));
}
+ #endif
+ mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set));
}
STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
@@ -441,6 +435,7 @@ STATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) {
}
STATIC mp_obj_t set_update(size_t n_args, const mp_obj_t *args) {
+ check_set(args[0]);
for (mp_uint_t i = 1; i < n_args; i++) {
set_update_int(MP_OBJ_TO_PTR(args[0]), args[i]);
}
diff --git a/py/objstr.c b/py/objstr.c
index 406ccf290..f082e9559 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -881,9 +881,14 @@ STATIC mp_obj_t arg_as_int(mp_obj_t arg) {
return arg;
}
+#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
STATIC NORETURN void terse_str_format_value_error(void) {
mp_raise_ValueError("bad format string");
}
+#else
+// define to nothing to improve coverage
+#define terse_str_format_value_error()
+#endif
STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
vstr_t vstr;
diff --git a/py/objstringio.c b/py/objstringio.c
index eb2e516bb..eb0cc4eb3 100644
--- a/py/objstringio.c
+++ b/py/objstringio.c
@@ -177,7 +177,7 @@ STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, s
STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
diff --git a/py/runtime.c b/py/runtime.c
index c3e187d8a..003c9f8b4 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1405,6 +1405,10 @@ NORETURN void mp_raise_TypeError(const char *msg) {
mp_raise_msg(&mp_type_TypeError, msg);
}
+NORETURN void mp_raise_OSError(int errno_) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_)));
+}
+
NORETURN void mp_not_implemented(const char *msg) {
mp_raise_msg(&mp_type_NotImplementedError, msg);
}
diff --git a/py/runtime.h b/py/runtime.h
index 29b38853f..80488098a 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -137,6 +137,7 @@ NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg);
//NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...);
NORETURN void mp_raise_ValueError(const char *msg);
NORETURN void mp_raise_TypeError(const char *msg);
+NORETURN void mp_raise_OSError(int errno_);
NORETURN void mp_not_implemented(const char *msg); // Raise NotImplementedError with given message
NORETURN void mp_exc_recursion_depth(void);
diff --git a/py/scope.c b/py/scope.c
index 632e52752..8fe6f960a 100644
--- a/py/scope.c
+++ b/py/scope.c
@@ -30,37 +30,26 @@
#if MICROPY_ENABLE_COMPILER
+// these low numbered qstrs should fit in 8 bits
+STATIC const uint8_t scope_simple_name_table[] = {
+ [SCOPE_MODULE] = MP_QSTR__lt_module_gt_,
+ [SCOPE_LAMBDA] = MP_QSTR__lt_lambda_gt_,
+ [SCOPE_LIST_COMP] = MP_QSTR__lt_listcomp_gt_,
+ [SCOPE_DICT_COMP] = MP_QSTR__lt_dictcomp_gt_,
+ [SCOPE_SET_COMP] = MP_QSTR__lt_setcomp_gt_,
+ [SCOPE_GEN_EXPR] = MP_QSTR__lt_genexpr_gt_,
+};
+
scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options) {
scope_t *scope = m_new0(scope_t, 1);
scope->kind = kind;
scope->pn = pn;
scope->source_file = source_file;
- switch (kind) {
- case SCOPE_MODULE:
- scope->simple_name = MP_QSTR__lt_module_gt_;
- break;
- case SCOPE_FUNCTION:
- case SCOPE_CLASS:
- assert(MP_PARSE_NODE_IS_STRUCT(pn));
- scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn)->nodes[0]);
- break;
- case SCOPE_LAMBDA:
- scope->simple_name = MP_QSTR__lt_lambda_gt_;
- break;
- case SCOPE_LIST_COMP:
- scope->simple_name = MP_QSTR__lt_listcomp_gt_;
- break;
- case SCOPE_DICT_COMP:
- scope->simple_name = MP_QSTR__lt_dictcomp_gt_;
- break;
- case SCOPE_SET_COMP:
- scope->simple_name = MP_QSTR__lt_setcomp_gt_;
- break;
- case SCOPE_GEN_EXPR:
- scope->simple_name = MP_QSTR__lt_genexpr_gt_;
- break;
- default:
- assert(0);
+ if (kind == SCOPE_FUNCTION || kind == SCOPE_CLASS) {
+ assert(MP_PARSE_NODE_IS_STRUCT(pn));
+ scope->simple_name = MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pn)->nodes[0]);
+ } else {
+ scope->simple_name = scope_simple_name_table[kind];
}
scope->raw_code = mp_emit_glue_new_raw_code();
scope->emit_options = emit_options;
@@ -117,22 +106,10 @@ id_info_t *scope_find_global(scope_t *scope, qstr qst) {
return scope_find(scope, qst);
}
-id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qst) {
- if (scope->parent == NULL) {
- return NULL;
- }
- for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
- id_info_t *id = scope_find(s, qst);
- if (id != NULL) {
- return id;
- }
- }
- return NULL;
-}
-
-void scope_close_over_in_parents(scope_t *scope, qstr qst) {
+STATIC void scope_close_over_in_parents(scope_t *scope, qstr qst) {
assert(scope->parent != NULL); // we should have at least 1 parent
- for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
+ for (scope_t *s = scope->parent;; s = s->parent) {
+ assert(s->parent != NULL); // we should not get to the outer scope
bool added;
id_info_t *id = scope_find_or_add_id(s, qst, &added);
if (added) {
@@ -140,16 +117,34 @@ void scope_close_over_in_parents(scope_t *scope, qstr qst) {
id->kind = ID_INFO_KIND_FREE;
} else {
// variable is declared in this scope, so finish
- switch (id->kind) {
- case ID_INFO_KIND_LOCAL: id->kind = ID_INFO_KIND_CELL; break; // variable local to this scope, close it over
- case ID_INFO_KIND_FREE: break; // variable already closed over in a parent scope
- case ID_INFO_KIND_CELL: break; // variable already closed over in this scope
- default: assert(0); // TODO
+ if (id->kind == ID_INFO_KIND_LOCAL) {
+ // variable local to this scope, close it over
+ id->kind = ID_INFO_KIND_CELL;
+ } else {
+ // ID_INFO_KIND_FREE: variable already closed over in a parent scope
+ // ID_INFO_KIND_CELL: variable already closed over in this scope
+ assert(id->kind == ID_INFO_KIND_FREE || id->kind == ID_INFO_KIND_CELL);
}
return;
}
}
- assert(0); // we should have found the variable in one of the parents
+}
+
+void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst) {
+ if (scope->parent != NULL) {
+ for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
+ id_info_t *id2 = scope_find(s, qst);
+ if (id2 != NULL) {
+ if (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE) {
+ id->kind = ID_INFO_KIND_FREE;
+ scope_close_over_in_parents(scope, qst);
+ return;
+ }
+ break;
+ }
+ }
+ }
+ id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
}
#endif // MICROPY_ENABLE_COMPILER
diff --git a/py/scope.h b/py/scope.h
index fac936a72..826064d7e 100644
--- a/py/scope.h
+++ b/py/scope.h
@@ -52,15 +52,27 @@ typedef struct _id_info_t {
qstr qst;
} id_info_t;
+#define SCOPE_IS_FUNC_LIKE(s) ((s) >= SCOPE_LAMBDA)
+
// scope is a "block" in Python parlance
-typedef enum { SCOPE_MODULE, SCOPE_FUNCTION, SCOPE_LAMBDA, SCOPE_LIST_COMP, SCOPE_DICT_COMP, SCOPE_SET_COMP, SCOPE_GEN_EXPR, SCOPE_CLASS } scope_kind_t;
+typedef enum {
+ SCOPE_MODULE,
+ SCOPE_CLASS,
+ SCOPE_LAMBDA,
+ SCOPE_LIST_COMP,
+ SCOPE_DICT_COMP,
+ SCOPE_SET_COMP,
+ SCOPE_GEN_EXPR,
+ SCOPE_FUNCTION,
+} scope_kind_t;
+
typedef struct _scope_t {
scope_kind_t kind;
struct _scope_t *parent;
struct _scope_t *next;
mp_parse_node_t pn;
- qstr source_file;
- qstr simple_name;
+ uint16_t source_file; // a qstr
+ uint16_t simple_name; // a qstr
mp_raw_code_t *raw_code;
uint8_t scope_flags; // see runtime0.h
uint8_t emit_options; // see compile.h
@@ -80,7 +92,6 @@ void scope_free(scope_t *scope);
id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added);
id_info_t *scope_find(scope_t *scope, qstr qstr);
id_info_t *scope_find_global(scope_t *scope, qstr qstr);
-id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qstr);
-void scope_close_over_in_parents(scope_t *scope, qstr qstr);
+void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst);
#endif // __MICROPY_INCLUDED_PY_SCOPE_H__
diff --git a/py/stream.c b/py/stream.c
index 24f47e24c..5610faf74 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -159,7 +159,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl
}
break;
}
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
}
if (out_sz < more_bytes) {
@@ -227,7 +227,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl
// this as EOF.
return mp_const_none;
}
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
} else {
vstr.len = out_sz;
return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr);
@@ -256,7 +256,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte fla
// no single byte could be readily written to it."
return mp_const_none;
}
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
} else {
return MP_OBJ_NEW_SMALL_INT(out_sz);
}
@@ -315,7 +315,7 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {
if (mp_is_nonblocking_error(error)) {
return mp_const_none;
}
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
} else {
return MP_OBJ_NEW_SMALL_INT(out_sz);
}
@@ -343,7 +343,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
}
break;
}
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
}
if (out_sz == 0) {
break;
@@ -402,7 +402,7 @@ STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args)
goto done;
}
}
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
}
if (out_sz == 0) {
done:
@@ -457,7 +457,7 @@ STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) {
int error;
mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);
if (res == MP_STREAM_ERROR) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
}
// TODO: Could be uint64
@@ -478,7 +478,7 @@ STATIC mp_obj_t stream_flush(mp_obj_t self) {
int error;
mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error);
if (res == MP_STREAM_ERROR) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
}
return mp_const_none;
}
@@ -500,7 +500,7 @@ STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) {
int error;
mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error);
if (res == MP_STREAM_ERROR) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error)));
+ mp_raise_OSError(error);
}
return mp_obj_new_int(res);
diff --git a/py/vm.c b/py/vm.c
index da8697fad..363824e5f 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -587,6 +587,8 @@ dispatch_loop:
// and __exit__ method (with self) underneath it. Bytecode calls __exit__,
// and "deletes" it off stack, shifting "exception control block"
// to its place.
+ // The bytecode emitter ensures that there is enough space on the Python
+ // value stack to hold the __exit__ method plus an additional 4 entries.
if (TOP() == mp_const_none) {
// stack: (..., __exit__, ctx_mgr, None)
sp[1] = mp_const_none;
@@ -620,31 +622,26 @@ dispatch_loop:
}
sp -= 2; // we removed (__exit__, ctx_mgr)
} else {
- assert(mp_obj_is_exception_type(TOP()));
- // stack: (..., __exit__, ctx_mgr, traceback, exc_val, exc_type)
- // Need to pass (sp[0], sp[-1], sp[-2]) as arguments so must reverse the
- // order of these on the value stack (don't want to create a temporary
- // array because it increases stack footprint of the VM).
- mp_obj_t obj = sp[-2];
- sp[-2] = sp[0];
- sp[0] = obj;
- mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp - 4);
+ assert(mp_obj_is_exception_instance(TOP()));
+ // stack: (..., __exit__, ctx_mgr, exc_instance)
+ // Need to pass (exc_type, exc_instance, None) as arguments to __exit__.
+ sp[1] = sp[0];
+ sp[0] = MP_OBJ_FROM_PTR(mp_obj_get_type(sp[0]));
+ sp[2] = mp_const_none;
+ sp -= 2;
+ mp_obj_t ret_value = mp_call_method_n_kw(3, 0, sp);
if (mp_obj_is_true(ret_value)) {
// We need to silence/swallow the exception. This is done
// by popping the exception and the __exit__ handler and
// replacing it with None, which signals END_FINALLY to just
// execute the finally handler normally.
- sp -= 4;
SET_TOP(mp_const_none);
assert(exc_sp >= exc_stack);
POP_EXC_BLOCK();
} else {
// We need to re-raise the exception. We pop __exit__ handler
- // and copy the 3 exception values down (remembering that they
- // are reversed due to above code).
- sp[-4] = sp[0];
- sp[-3] = sp[-1];
- sp -= 2;
+ // by copying the exception instance down to the new top-of-stack.
+ sp[0] = sp[3];
}
}
DISPATCH();
@@ -698,18 +695,12 @@ unwind_jump:;
ENTRY(MP_BC_END_FINALLY):
MARK_EXC_IP_SELECTIVE();
- // not fully implemented
- // if TOS is an exception, reraises the exception (3 values on TOS)
// if TOS is None, just pops it and continues
- // if TOS is an integer, does something else
- // else error
- if (mp_obj_is_exception_type(TOP())) {
- RAISE(sp[-1]);
- }
+ // if TOS is an integer, finishes coroutine and returns control to caller
+ // if TOS is an exception, reraises the exception
if (TOP() == mp_const_none) {
sp--;
- } else {
- assert(MP_OBJ_IS_SMALL_INT(TOP()));
+ } else if (MP_OBJ_IS_SMALL_INT(TOP())) {
// We finished "finally" coroutine and now dispatch back
// to our caller, based on TOS value
mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP());
@@ -719,6 +710,9 @@ unwind_jump:;
assert(reason == UNWIND_JUMP);
goto unwind_jump;
}
+ } else {
+ assert(mp_obj_is_exception_instance(TOP()));
+ RAISE(TOP());
}
DISPATCH();
@@ -751,14 +745,9 @@ unwind_jump:;
// matched against: SETUP_EXCEPT
ENTRY(MP_BC_POP_EXCEPT):
- // TODO need to work out how blocks work etc
- // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
assert(exc_sp >= exc_stack);
assert(currently_in_except_block);
- //sp = (mp_obj_t*)(*exc_sp--);
- //exc_sp--; // discard ip
POP_EXC_BLOCK();
- //sp -= 3; // pop 3 exception values
DISPATCH();
ENTRY(MP_BC_BUILD_TUPLE): {
@@ -1359,10 +1348,8 @@ unwind_loop:
mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);
// save this exception in the stack so it can be used in a reraise, if needed
exc_sp->prev_exc = nlr.ret_val;
- // push(traceback, exc-val, exc-type)
- PUSH(mp_const_none);
+ // push exception object so it can be handled by bytecode
PUSH(MP_OBJ_FROM_PTR(nlr.ret_val));
- PUSH(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type));
code_state->sp = sp;
#if MICROPY_STACKLESS