aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--py/builtinimport.c20
-rw-r--r--py/compile.c172
-rw-r--r--py/emitbc.c6
-rw-r--r--py/emitglue.c3
-rw-r--r--py/makeqstrdata.py28
-rw-r--r--py/obj.c48
-rw-r--r--py/obj.h29
-rw-r--r--py/objdict.c4
-rw-r--r--py/objfun.c1
-rw-r--r--py/objint_longlong.c2
-rw-r--r--py/objint_mpz.c2
-rw-r--r--py/objlist.c2
-rw-r--r--py/objset.c2
-rw-r--r--py/objstr.c21
-rw-r--r--py/objtuple.c2
-rw-r--r--py/py.mk5
-rw-r--r--py/qstrdefs.h3
-rw-r--r--py/runtime.c44
-rw-r--r--py/showbc.c9
-rw-r--r--py/vm.c8
-rw-r--r--tests/basics/equal.py75
-rw-r--r--tests/basics/import-pkg3.py6
-rw-r--r--tests/bytecode/mp-tests/assign2.py15
-rw-r--r--tests/bytecode/mp-tests/yield2.py3
24 files changed, 334 insertions, 176 deletions
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 5102a9bde..501ced764 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -19,6 +19,13 @@
#include "runtime.h"
#include "builtin.h"
+#if 0 // print debugging info
+#define DEBUG_PRINT (1)
+#define DEBUG_printf DEBUG_printf
+#else // don't print debugging info
+#define DEBUG_printf(...) (void)0
+#endif
+
#define PATH_SEP_CHAR '/'
mp_obj_t mp_sys_path;
@@ -129,14 +136,14 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
}
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
- /*
- printf("import:\n");
+#if DEBUG_PRINT
+ printf("__import__:\n");
for (int i = 0; i < n_args; i++) {
printf(" ");
mp_obj_print(args[i], PRINT_REPR);
printf("\n");
}
- */
+#endif
mp_obj_t fromtuple = mp_const_none;
int level = 0;
@@ -158,6 +165,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
// check if module already exists
mp_obj_t module_obj = mp_module_get(mp_obj_str_get_qstr(args[0]));
if (module_obj != MP_OBJ_NULL) {
+ DEBUG_printf("Module already loaded\n");
// If it's not a package, return module right away
char *p = strchr(mod_str, '.');
if (p == NULL) {
@@ -171,6 +179,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);
return mp_module_get(pkg_name);
}
+ DEBUG_printf("Module not yet loaded\n");
uint last = 0;
VSTR_FIXED(path, MICROPY_PATH_MAX)
@@ -182,6 +191,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
if (i == mod_len || mod_str[i] == '.') {
// create a qstr for the module name up to this depth
qstr mod_name = qstr_from_strn(mod_str, i);
+ DEBUG_printf("Processing module: %s\n", qstr_str(mod_name));
// find the file corresponding to the module name
mp_import_stat_t stat;
@@ -207,6 +217,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
module_obj = mp_obj_new_module(mod_name);
if (stat == MP_IMPORT_STAT_DIR) {
+ DEBUG_printf("%s is dir\n", vstr_str(&path));
vstr_add_char(&path, PATH_SEP_CHAR);
vstr_add_str(&path, "__init__.py");
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
@@ -217,6 +228,9 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
}
do_load(module_obj, &path);
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
+ // https://docs.python.org/3.3/reference/import.html
+ // "Specifically, any module that contains a __path__ attribute is considered a package."
+ mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str((byte*)vstr_str(&path), vstr_len(&path), false));
} else { // MP_IMPORT_STAT_FILE
do_load(module_obj, &path);
// TODO: We cannot just break here, at the very least, we must execute
diff --git a/py/compile.c b/py/compile.c
index 4738c0ae5..8d9d5fa52 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -52,10 +52,9 @@ typedef struct _compiler_t {
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;
+ uint8_t have_star;
+ uint16_t num_dict_params;
+ uint16_t num_default_params;
scope_t *scope_head;
scope_t *scope_cur;
@@ -666,28 +665,42 @@ cannot_assign:
compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression");
}
-void c_assign_tuple(compiler_t *comp, int n, mp_parse_node_t *nodes) {
- assert(n >= 0);
+// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
+void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
+ uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
+
+ // look for star expression
int have_star_index = -1;
- for (int i = 0; i < n; i++) {
- if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_star_expr)) {
+ if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {
+ EMIT_ARG(unpack_ex, 0, num_tail);
+ have_star_index = 0;
+ }
+ for (int i = 0; i < num_tail; i++) {
+ if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
if (have_star_index < 0) {
- EMIT_ARG(unpack_ex, i, n - i - 1);
- have_star_index = i;
+ EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
+ have_star_index = num_head + i;
} else {
- compile_syntax_error(comp, nodes[i], "two starred expressions in assignment");
+ compile_syntax_error(comp, nodes_tail[i], "two starred expressions in assignment");
return;
}
}
}
if (have_star_index < 0) {
- EMIT_ARG(unpack_sequence, n);
+ EMIT_ARG(unpack_sequence, num_head + num_tail);
}
- for (int i = 0; i < n; i++) {
- if (i == have_star_index) {
- c_assign(comp, ((mp_parse_node_struct_t*)nodes[i])->nodes[0], ASSIGN_STORE);
+ if (num_head != 0) {
+ if (0 == have_star_index) {
+ c_assign(comp, ((mp_parse_node_struct_t*)node_head)->nodes[0], ASSIGN_STORE);
+ } else {
+ c_assign(comp, node_head, ASSIGN_STORE);
+ }
+ }
+ for (int i = 0; i < num_tail; i++) {
+ if (num_head + i == have_star_index) {
+ c_assign(comp, ((mp_parse_node_struct_t*)nodes_tail[i])->nodes[0], ASSIGN_STORE);
} else {
- c_assign(comp, nodes[i], ASSIGN_STORE);
+ c_assign(comp, nodes_tail[i], ASSIGN_STORE);
}
}
}
@@ -727,7 +740,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
if (assign_kind != ASSIGN_STORE) {
goto bad_aug;
}
- c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
+ c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
break;
case PN_atom_paren:
@@ -753,13 +766,13 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
}
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// empty list, assignment allowed
- c_assign_tuple(comp, 0, NULL);
+ c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
pns = (mp_parse_node_struct_t*)pns->nodes[0];
goto testlist_comp;
} else {
// brackets around 1 item
- c_assign_tuple(comp, 1, &pns->nodes[0]);
+ c_assign_tuple(comp, pns->nodes[0], 0, NULL);
}
break;
@@ -776,16 +789,11 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
// sequence of one item, with trailing comma
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
- c_assign_tuple(comp, 1, &pns->nodes[0]);
+ c_assign_tuple(comp, pns->nodes[0], 0, NULL);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
// sequence of many items
- // TODO call c_assign_tuple instead
- int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
- EMIT_ARG(unpack_sequence, 1 + n);
- c_assign(comp, pns->nodes[0], ASSIGN_STORE);
- for (int i = 0; i < n; i++) {
- c_assign(comp, pns2->nodes[i], ASSIGN_STORE);
- }
+ 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?
compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression");
@@ -797,7 +805,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
} else {
// sequence with 2 items
sequence_with_2_items:
- c_assign_tuple(comp, 2, pns->nodes);
+ c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);
}
return;
}
@@ -850,13 +858,18 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d
void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {
+ comp->have_star = true;
+ /* don't need to distinguish bare from named star
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// bare star
- comp->have_bare_star = true;
+ } else {
+ // named star
}
+ */
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_dbl_star)) {
+ // named double star
// TODO do we need to do anything with this?
} else {
@@ -888,7 +901,7 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
// this parameter does not have a default value
// check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid)
- if (!comp->have_bare_star && comp->param_pass_num_default_params != 0) {
+ if (!comp->have_star && comp->num_default_params != 0) {
compile_syntax_error(comp, pn, "non-default argument follows default argument");
return;
}
@@ -897,28 +910,29 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
// this parameter has a default value
// in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why
- if (comp->have_bare_star) {
- comp->param_pass_num_dict_params += 1;
- if (comp->param_pass == 1) {
+ if (comp->have_star) {
+ comp->num_dict_params += 1;
#if !MICROPY_EMIT_CPYTHON
- // in Micro Python we put the default dict parameters into a dictionary using the bytecode
- if (comp->param_pass_num_dict_params == 1) {
- // first default dict param, so make the map
- EMIT_ARG(build_map, 0);
+ // in Micro Python we put the default dict parameters into a dictionary using the bytecode
+ if (comp->num_dict_params == 1) {
+ // in Micro Python we put the default positional parameters into a tuple using the bytecode
+ // we need to do this here before we start building the map for the default keywords
+ if (comp->num_default_params > 0) {
+ EMIT_ARG(build_tuple, comp->num_default_params);
}
+ // first default dict param, so make the map
+ EMIT_ARG(build_map, 0);
+ }
#endif
- EMIT_ARG(load_const_id, MP_PARSE_NODE_LEAF_ARG(pn_id));
- compile_node(comp, pn_equal);
+ EMIT_ARG(load_const_id, MP_PARSE_NODE_LEAF_ARG(pn_id));
+ compile_node(comp, pn_equal);
#if !MICROPY_EMIT_CPYTHON
- // in Micro Python we put the default dict parameters into a dictionary using the bytecode
- EMIT(store_map);
+ // in Micro Python we put the default dict parameters into a dictionary using the bytecode
+ EMIT(store_map);
#endif
- }
} else {
- comp->param_pass_num_default_params += 1;
- if (comp->param_pass == 2) {
- compile_node(comp, pn_equal);
- }
+ comp->num_default_params += 1;
+ compile_node(comp, pn_equal);
}
}
@@ -938,35 +952,25 @@ 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..?)
- 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;
+ uint old_have_star = comp->have_star;
+ uint old_num_dict_params = comp->num_dict_params;
+ uint old_num_default_params = comp->num_default_params;
// compile default parameters
-
- // pass 1 does any default parameters after bare star
- comp->have_bare_star = false;
- comp->param_pass = 1;
- comp->param_pass_num_dict_params = 0;
- comp->param_pass_num_default_params = 0;
+ comp->have_star = false;
+ comp->num_dict_params = 0;
+ comp->num_default_params = 0;
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
if (comp->had_error) {
return MP_QSTR_NULL;
}
- // pass 2 does any default parameters before bare star
- comp->have_bare_star = false;
- comp->param_pass = 2;
- comp->param_pass_num_dict_params = 0;
- comp->param_pass_num_default_params = 0;
- apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
-
#if !MICROPY_EMIT_CPYTHON
// in Micro Python we put the default positional parameters into a tuple using the bytecode
- if (comp->param_pass_num_default_params > 0) {
- EMIT_ARG(build_tuple, comp->param_pass_num_default_params);
+ // the default keywords args may have already made the tuple; if not, do it now
+ if (comp->num_default_params > 0 && comp->num_dict_params == 0) {
+ EMIT_ARG(build_tuple, comp->num_default_params);
}
#endif
@@ -974,13 +978,12 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint
scope_t *fscope = (scope_t*)pns->nodes[4];
// make the function
- close_over_variables_etc(comp, fscope, comp->param_pass_num_default_params, comp->param_pass_num_dict_params);
+ close_over_variables_etc(comp, fscope, comp->num_default_params, comp->num_dict_params);
// restore variables
- comp->have_bare_star = old_have_bare_star;
- comp->param_pass = old_param_pass;
- comp->param_pass_num_dict_params = old_param_pass_num_dict_params;
- comp->param_pass_num_default_params = old_param_pass_num_default_params;
+ comp->have_star = old_have_star;
+ comp->num_dict_params = old_num_dict_params;
+ comp->num_default_params = old_num_default_params;
// return its name (the 'f' in "def f(...):")
return fscope->simple_name;
@@ -2672,7 +2675,7 @@ void compile_argument(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
- if (comp->scope_cur->kind != SCOPE_FUNCTION) {
+ if (comp->scope_cur->kind != SCOPE_FUNCTION && comp->scope_cur->kind != SCOPE_LAMBDA) {
compile_syntax_error(comp, (mp_parse_node_t)pns, "'yield' outside function");
return;
}
@@ -2750,7 +2753,7 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
if (MP_PARSE_NODE_IS_ID(pn)) {
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
- if (comp->have_bare_star) {
+ if (comp->have_star) {
// comes after a bare star, so doesn't count as a parameter
} else {
comp->scope_cur->num_params += 1;
@@ -2771,30 +2774,30 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
/* this is obsolete now that num dict/default params are calculated in compile_funcdef_param
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[node_index])) {
// this parameter has a default value
- if (comp->have_bare_star) {
+ if (comp->have_star) {
comp->scope_cur->num_dict_params += 1;
} else {
comp->scope_cur->num_default_params += 1;
}
}
*/
- if (comp->have_bare_star) {
+ if (comp->have_star) {
// comes after a bare star, so doesn't count as a parameter
} else {
comp->scope_cur->num_params += 1;
}
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_star) {
+ comp->have_star = true;
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// bare star
// TODO see http://www.python.org/dev/peps/pep-3102/
- comp->have_bare_star = true;
//assert(comp->scope_cur->num_dict_params == 0);
} else if (MP_PARSE_NODE_IS_ID(pns->nodes[0])) {
// named star
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
} else if (allow_annotations && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
- // named star with annotation
+ // named star with possible annotation
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
pns = (mp_parse_node_struct_t*)pns->nodes[0];
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
@@ -2959,7 +2962,7 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
// work out number of parameters, keywords and default parameters, and add them to the id_info array
// must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)
if (comp->pass == PASS_1) {
- comp->have_bare_star = false;
+ comp->have_star = false;
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);
}
@@ -2979,11 +2982,17 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
// work out number of parameters, keywords and default parameters, and add them to the id_info array
// must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)
if (comp->pass == PASS_1) {
- comp->have_bare_star = false;
+ comp->have_star = false;
apply_to_single_or_list(comp, pns->nodes[0], PN_varargslist, compile_scope_lambda_param);
}
compile_node(comp, pns->nodes[1]); // 1 is lambda body
+
+ // if the lambda is a generator, then we return None, not the result of the expression of the lambda
+ if (scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
+ EMIT(pop_top);
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
+ }
EMIT(return_value);
} else if (scope->kind == SCOPE_LIST_COMP || scope->kind == SCOPE_DICT_COMP || scope->kind == SCOPE_SET_COMP || scope->kind == SCOPE_GEN_EXPR) {
// a bit of a hack at the moment
@@ -3233,15 +3242,10 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
#if MICROPY_EMIT_CPYTHON
// these flags computed here are for CPython compatibility only
- if (scope->kind == SCOPE_FUNCTION) {
- scope->scope_flags |= MP_SCOPE_FLAG_NEWLOCALS;
- }
if (scope->kind == SCOPE_FUNCTION || scope->kind == SCOPE_LAMBDA || scope->kind == SCOPE_LIST_COMP || scope->kind == SCOPE_DICT_COMP || scope->kind == SCOPE_SET_COMP || scope->kind == SCOPE_GEN_EXPR) {
assert(scope->parent != NULL);
+ scope->scope_flags |= MP_SCOPE_FLAG_NEWLOCALS;
scope->scope_flags |= MP_SCOPE_FLAG_OPTIMISED;
-
- // TODO possibly other ways it can be nested
- // Note that we don't actually use this information at the moment (for CPython compat only)
if ((SCOPE_FUNCTION <= scope->parent->kind && scope->parent->kind <= SCOPE_SET_COMP) || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) {
scope->scope_flags |= MP_SCOPE_FLAG_NESTED;
}
diff --git a/py/emitbc.c b/py/emitbc.c
index fc3e5ed62..a1179a695 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -744,10 +744,10 @@ STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defau
if (n_pos_defaults == 0) {
// load dummy entry for non-existent positional default tuple
emit_bc_load_null(emit);
+ emit_bc_rot_two(emit);
} else if (n_kw_defaults == 0) {
// load dummy entry for non-existent keyword default dict
emit_bc_load_null(emit);
- emit_bc_rot_two(emit);
}
emit_bc_pre(emit, -1);
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->unique_code_id);
@@ -762,11 +762,11 @@ STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaul
if (n_pos_defaults == 0) {
// load dummy entry for non-existent positional default tuple
emit_bc_load_null(emit);
- emit_bc_rot_two(emit);
+ emit_bc_rot_three(emit);
} else if (n_kw_defaults == 0) {
// load dummy entry for non-existent keyword default dict
emit_bc_load_null(emit);
- emit_bc_rot_three(emit);
+ emit_bc_rot_two(emit);
}
emit_bc_pre(emit, -2);
emit_write_byte_code_byte_uint(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->unique_code_id);
diff --git a/py/emitglue.c b/py/emitglue.c
index 48800bbf0..90c9b77cf 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -197,6 +197,9 @@ mp_obj_t mp_make_function_from_id(uint unique_code_id, mp_obj_t def_args, mp_obj
return mp_const_none;
}
+ // def_args must be MP_OBJ_NULL or a tuple
+ assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
+
// TODO implement default kw args
assert(def_kw_args == MP_OBJ_NULL);
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index e60f00044..81b003545 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -26,10 +26,10 @@ def compute_hash(qstr):
def do_work(infiles):
# read the qstrs in from the input files
qstrs = {}
+ cpp_header_blocks = 3
for infile in infiles:
with open(infile, 'rt') as f:
line_number = 0
- conditional = None
for line in f:
line_number += 1
line = line.strip()
@@ -38,17 +38,13 @@ def do_work(infiles):
if len(line) == 0 or line.startswith('//'):
continue
- if line[0] == '#':
- if conditional == "<endif>":
- assert line == "#endif"
- conditional = None
- else:
- assert conditional is None
- conditional = line
+ # We'll have 3 line-number lines for py/qstrdefs.h - initial, leaving it to
+ # go into other headers, and returning to it.
+ if line.startswith('# ') and 'py/qstrdefs.h' in line:
+ cpp_header_blocks -= 1
+ continue
+ if cpp_header_blocks != 0:
continue
-
- if conditional == "<endif>":
- assert False, "#endif expected before '%s'" % line
# verify line is of the correct form
match = re.match(r'Q\((.+)\)$', line)
@@ -65,21 +61,15 @@ def do_work(infiles):
continue
# add the qstr to the list, with order number to retain original order in file
- qstrs[ident] = (len(qstrs), ident, qstr, conditional)
- if conditional is not None:
- conditional = "<endif>"
+ qstrs[ident] = (len(qstrs), ident, qstr)
# process the qstrs, printing out the generated C header file
print('// This file was automatically generated by makeqstrdata.py')
print('')
- for order, ident, qstr, conditional in sorted(qstrs.values(), key=lambda x: x[0]):
+ for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):
qhash = compute_hash(qstr)
qlen = len(qstr)
- if conditional:
- print(conditional)
print('Q({}, (const byte*)"\\x{:02x}\\x{:02x}\\x{:02x}\\x{:02x}" "{}")'.format(ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen & 0xff, (qlen >> 8) & 0xff, qstr))
- if conditional:
- print('#endif')
return True
diff --git a/py/obj.c b/py/obj.c
index 7b8be5889..7666855e5 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -99,11 +99,6 @@ 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;
}
@@ -143,20 +138,35 @@ machine_int_t mp_obj_hash(mp_obj_t o_in) {
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
if (o1 == o2) {
return true;
- } else if (o1 == mp_const_none || o2 == mp_const_none) {
+ }
+ if (o1 == mp_const_none || o2 == mp_const_none) {
return false;
- } else if (MP_OBJ_IS_SMALL_INT(o1) || MP_OBJ_IS_SMALL_INT(o2)) {
- if (MP_OBJ_IS_SMALL_INT(o1) && MP_OBJ_IS_SMALL_INT(o2)) {
+ }
+
+ // fast path for small ints
+ if (MP_OBJ_IS_SMALL_INT(o1)) {
+ if (MP_OBJ_IS_SMALL_INT(o2)) {
+ // both SMALL_INT, and not equal if we get here
return false;
} else {
- if (MP_OBJ_IS_SMALL_INT(o1)) {
- mp_obj_t temp = o2; o2 = o1; o1 = temp;
- }
- // o2 is the SMALL_INT, o1 is not
+ mp_obj_t temp = o2; o2 = o1; o1 = temp;
+ // o2 is now the SMALL_INT, o1 is not
// fall through to generic op
}
- } else if (MP_OBJ_IS_STR(o1) && MP_OBJ_IS_STR(o2)) {
- return mp_obj_str_equal(o1, o2);
+ }
+
+ // fast path for strings
+ if (MP_OBJ_IS_STR(o1)) {
+ if (MP_OBJ_IS_STR(o2)) {
+ // both strings, use special function
+ return mp_obj_str_equal(o1, o2);
+ } else {
+ // a string is never equal to anything else
+ return false;
+ }
+ } else if (MP_OBJ_IS_STR(o2)) {
+ // o1 is not a string (else caught above), so the objects are not equal
+ return false;
}
// generic type, call binary_op(MP_BINARY_OP_EQUAL)
@@ -277,12 +287,10 @@ 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_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 {
+ machine_int_t i;
+ if (MP_OBJ_IS_SMALL_INT(index)) {
+ i = MP_OBJ_SMALL_INT_VALUE(index);
+ } else if (!mp_obj_get_int_maybe(index, &i)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s indices must be integers, not %s", qstr_str(type->name), mp_obj_get_type_str(index)));
}
diff --git a/py/obj.h b/py/obj.h
index af6ef8318..d46fd7595 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -21,7 +21,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
// The NULL object is used to indicate the absence of an object
// It *cannot* be used when an mp_obj_t is expected, except where explicitly allowed
-#define MP_OBJ_NULL ((mp_obj_t)NULL)
+#define MP_OBJ_NULL ((mp_obj_t)0)
// The SENTINEL object is used for various internal purposes where one needs
// an object which is unique from all other objects, including MP_OBJ_NULL.
@@ -37,9 +37,10 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1))
#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN)))
#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
-#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
-#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
-#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0)
+// these macros have now become inline functions; see below
+//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
+//#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
+//#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0)
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking a string, use below macro for that
#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int))
#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str))
@@ -115,7 +116,7 @@ typedef enum _mp_map_lookup_kind_t {
MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2
} mp_map_lookup_kind_t;
-#define MP_MAP_SLOT_IS_FILLED(map, pos) ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL)
+static inline bool MP_MAP_SLOT_IS_FILLED(mp_map_t *map, machine_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
void mp_map_init(mp_map_t *map, int n);
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
@@ -134,7 +135,7 @@ typedef struct _mp_set_t {
mp_obj_t *table;
} mp_set_t;
-#define MP_SET_SLOT_IS_FILLED(set, pos) ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL)
+static inline bool MP_SET_SLOT_IS_FILLED(mp_set_t *set, machine_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
void mp_set_init(mp_set_t *set, int n);
mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
@@ -369,7 +370,16 @@ 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
+
+// TODO make these all lower case when they have proven themselves
+static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 0); }
+static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 1) != 0); }
+//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that
+//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int
+static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int
+static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 2); }
+//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); }
+
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);
@@ -384,10 +394,11 @@ void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items);
void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items);
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice);
-mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return NULL */
+mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return MP_OBJ_NULL */
// bool
-#define MP_BOOL(x) (x ? mp_const_true : mp_const_false)
+// TODO make lower case when it has proven itself
+inline mp_obj_t MP_BOOL(machine_int_t x) { return x ? mp_const_true : mp_const_false; }
// cell
mp_obj_t mp_obj_cell_get(mp_obj_t self_in);
diff --git a/py/objdict.c b/py/objdict.c
index 963e18807..8bdd0026a 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -99,7 +99,6 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return MP_BOOL(elem != NULL);
}
case MP_BINARY_OP_EQUAL: {
- // TODO: Support equality to other object types
if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) {
mp_obj_dict_t *rhs = rhs_in;
if (o->map.used != rhs->map.used) {
@@ -118,6 +117,9 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
}
return mp_const_true;
+ } else {
+ // dict is not equal to instance of any other type
+ return mp_const_false;
}
}
default:
diff --git a/py/objfun.c b/py/objfun.c
index adf05ce40..dd4b7347c 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -361,6 +361,7 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t d
uint n_extra_args = 0;
mp_obj_tuple_t *def_args = def_args_in;
if (def_args != MP_OBJ_NULL) {
+ assert(MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
n_def_args = def_args->len;
n_extra_args = def_args->len;
}
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index 24435415f..7dc0573bc 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -106,8 +106,6 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return MP_BOOL(lhs_val >= rhs_val);
case MP_BINARY_OP_EQUAL:
return MP_BOOL(lhs_val == rhs_val);
- case MP_BINARY_OP_NOT_EQUAL:
- return MP_BOOL(lhs_val != rhs_val);
default:
// op not supported
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 583ce4cb7..2d10ed471 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -205,8 +205,6 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return MP_BOOL(cmp >= 0);
case MP_BINARY_OP_EQUAL:
return MP_BOOL(cmp == 0);
- case MP_BINARY_OP_NOT_EQUAL:
- return MP_BOOL(cmp != 0);
default:
return MP_OBJ_NULL;
diff --git a/py/objlist.c b/py/objlist.c
index a3b7e79ab..531e4b85b 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -138,8 +138,6 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL:
return MP_BOOL(list_cmp_helper(op, lhs, rhs));
- case MP_BINARY_OP_NOT_EQUAL:
- return MP_BOOL(!list_cmp_helper(MP_BINARY_OP_EQUAL, lhs, rhs));
default:
// op not supported
diff --git a/py/objset.c b/py/objset.c
index 448f484d5..05d064a04 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -411,8 +411,6 @@ STATIC mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
return set_issubset(lhs, rhs);
case MP_BINARY_OP_MORE_EQUAL:
return set_issuperset(lhs, rhs);
- case MP_BINARY_OP_NOT_EQUAL:
- return MP_BOOL(set_equal(lhs, rhs) == mp_const_false);
case MP_BINARY_OP_IN:
{
mp_obj_set_t *o = lhs;
diff --git a/py/objstr.c b/py/objstr.c
index 39c24205b..e55a2edd5 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -220,27 +220,24 @@ STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, cons
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:
- 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]);
- } else {
- return mp_obj_new_str(lhs_data + index, 1, true);
- }
+ case MP_BINARY_OP_SUBSCR: {
#if MICROPY_ENABLE_SLICE
- } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_slice)) {
+ if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_slice)) {
machine_uint_t start, stop;
if (!m_seq_get_fast_slice_indexes(lhs_len, rhs_in, &start, &stop)) {
assert(0);
}
return mp_obj_new_str(lhs_data + start, stop - start, false);
+ }
#endif
+ mp_obj_type_t *type = mp_obj_get_type(lhs_in);
+ uint index = mp_get_index(type, lhs_len, rhs_in, false);
+ if (type == &mp_type_bytes) {
+ return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)lhs_data[index]);
} else {
- // Message doesn't match CPython, but we don't have so much bytes as they
- // to spend them on verbose wording
- nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "index must be int"));
+ return mp_obj_new_str(lhs_data + index, 1, true);
}
+ }
case MP_BINARY_OP_ADD:
case MP_BINARY_OP_INPLACE_ADD:
diff --git a/py/objtuple.c b/py/objtuple.c
index 21313f7f9..63866e80d 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -137,8 +137,6 @@ mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL:
return MP_BOOL(tuple_cmp_helper(op, lhs, rhs));
- case MP_BINARY_OP_NOT_EQUAL:
- return MP_BOOL(!tuple_cmp_helper(MP_BINARY_OP_EQUAL, lhs, rhs));
default:
// op not supported
diff --git a/py/py.mk b/py/py.mk
index ecc4a6a0d..23ba9ebe7 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -104,9 +104,10 @@ $(PY_BUILD)/py-version.h: FORCE
# Adding an order only dependency on $(PY_BUILD) causes $(PY_BUILD) to get
# created before we run the script to generate the .h
$(PY_BUILD)/qstrdefs.generated.h: | $(PY_BUILD)/
-$(PY_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(PY_SRC)/makeqstrdata.py
+$(PY_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(PY_SRC)/mpconfig.h
$(ECHO) "makeqstrdata $(PY_QSTR_DEFS) $(QSTR_DEFS)"
- $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(PY_QSTR_DEFS) $(QSTR_DEFS) > $@
+ $(CPP) $(CFLAGS) $(PY_QSTR_DEFS) -o $(PY_BUILD)/qstrdefs.preprocessed.h
+ $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(PY_BUILD)/qstrdefs.preprocessed.h $(QSTR_DEFS) > $@
# We don't know which source files actually need the generated.h (since
# it is #included from str.h). The compiler generated dependencies will cause
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 17948434b..d52b870e6 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -1,6 +1,6 @@
+#include "mpconfig.h"
// All the qstr definitions in this file are available as constants.
// That is, they are in ROM and you can reference them simply as MP_QSTR_xxxx.
-// TODO make it so we can use #defines here to select only those words that will be used
Q(__build_class__)
Q(__class__)
@@ -13,6 +13,7 @@ Q(__module__)
Q(__name__)
Q(__next__)
Q(__qualname__)
+Q(__path__)
Q(__repl_print__)
Q(__bool__)
diff --git a/py/runtime.c b/py/runtime.c
index 499905a0f..4793f054a 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1043,13 +1043,45 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) {
mp_obj_t mp_import_from(mp_obj_t module, qstr name) {
DEBUG_printf("import from %p %s\n", module, qstr_str(name));
- mp_obj_t x = mp_load_attr(module, name);
- /* TODO convert AttributeError to ImportError
- if (fail) {
- (ImportError, "cannot import name %s", qstr_str(name), NULL)
+ mp_obj_t dest[2];
+
+ mp_load_method_maybe(module, name, dest);
+
+ if (dest[1] != MP_OBJ_NULL) {
+ // Hopefully we can't import bound method from an object
+import_error:
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "Cannot import name '%s'", qstr_str(name)));
+ }
+
+ if (dest[0] != MP_OBJ_NULL) {
+ return dest[0];
+ }
+
+ // See if it's a package, then can try FS import
+ mp_load_method_maybe(module, MP_QSTR___path__, dest);
+ if (dest[0] == MP_OBJ_NULL) {
+ goto import_error;
}
- */
- return x;
+
+ mp_load_method_maybe(module, MP_QSTR___name__, dest);
+ uint pkg_name_len;
+ const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len);
+
+ char dot_name[pkg_name_len + 1 + qstr_len(name)];
+ memcpy(dot_name, pkg_name, pkg_name_len);
+ dot_name[pkg_name_len] = '.';
+ memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name));
+ qstr dot_name_q = qstr_from_strn(dot_name, sizeof(dot_name));
+
+ mp_obj_t args[5];
+ args[0] = MP_OBJ_NEW_QSTR(dot_name_q);
+ args[1] = mp_const_none; // TODO should be globals
+ args[2] = mp_const_none; // TODO should be locals
+ args[3] = mp_const_true; // Pass sentinel "non empty" value to force returning of leaf module
+ args[4] = 0;
+
+ // TODO lookup __import__ and call that instead of going straight to builtin implementation
+ return mp_builtin___import__(5, args);
}
void mp_import_all(mp_obj_t module) {
diff --git a/py/showbc.c b/py/showbc.c
index c1e420f43..08dec1e2b 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -101,11 +101,20 @@ void mp_byte_code_print(const byte *ip, int len) {
printf("LOAD_CONST_ID %s", qstr_str(qstr));
break;
+ case MP_BC_LOAD_CONST_BYTES:
+ DECODE_QSTR;
+ printf("LOAD_CONST_BYTES %s", qstr_str(qstr));
+ break;
+
case MP_BC_LOAD_CONST_STRING:
DECODE_QSTR;
printf("LOAD_CONST_STRING %s", qstr_str(qstr));
break;
+ case MP_BC_LOAD_NULL:
+ printf("LOAD_NULL");
+ break;
+
case MP_BC_LOAD_FAST_0:
printf("LOAD_FAST_0");
break;
diff --git a/py/vm.c b/py/vm.c
index 47d6bf8f5..1ea0c5eaa 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -718,9 +718,9 @@ unwind_jump:
case MP_BC_MAKE_FUNCTION_DEFARGS:
DECODE_UINT;
- // Stack layout: def_dict def_tuple <- TOS
+ // Stack layout: def_tuple def_dict <- TOS
obj1 = POP();
- SET_TOP(mp_make_function_from_id(unum, obj1, TOP()));
+ SET_TOP(mp_make_function_from_id(unum, TOP(), obj1));
break;
case MP_BC_MAKE_CLOSURE:
@@ -731,10 +731,10 @@ unwind_jump:
case MP_BC_MAKE_CLOSURE_DEFARGS:
DECODE_UINT;
- // Stack layout: def_dict def_tuple closure_tuple <- TOS
+ // Stack layout: def_tuple def_dict closure_tuple <- TOS
obj1 = POP();
obj2 = POP();
- SET_TOP(mp_make_closure_from_id(unum, obj1, obj2, TOP()));
+ SET_TOP(mp_make_closure_from_id(unum, obj1, TOP(), obj2));
break;
case MP_BC_CALL_FUNCTION:
diff --git a/tests/basics/equal.py b/tests/basics/equal.py
new file mode 100644
index 000000000..665d7fd8c
--- /dev/null
+++ b/tests/basics/equal.py
@@ -0,0 +1,75 @@
+# test equality
+
+print(None == None)
+
+print(False == None)
+print(False == False)
+print(False == True)
+
+print(() == ())
+print(() == [])
+print([] == [])
+print(() == {})
+print({} == ())
+
+print(() == None)
+print(() == False)
+print(() == print)
+
+print([] == None)
+print([] == False)
+print([] == print)
+
+print({} == None)
+print({} == False)
+print({} == print)
+
+print(1 == 1)
+print(1 == 2)
+print(1 == ())
+print(1 == [])
+print(1 == {})
+print(1 == 'a')
+
+print('a' == 'a')
+print('a' == 'ab')
+print('a' == 1)
+print('a' == ())
+
+# same as above but with !=
+
+print(None != None)
+
+print(False != None)
+print(False != False)
+print(False != True)
+
+print(() != ())
+print(() != [])
+print([] != [])
+print(() != {})
+print({} != ())
+
+print(() != None)
+print(() != False)
+print(() != print)
+
+print([] != None)
+print([] != False)
+print([] != print)
+
+print({} != None)
+print({} != False)
+print({} != print)
+
+print(1 != 1)
+print(1 != 2)
+print(1 != ())
+print(1 != [])
+print(1 != {})
+print(1 != 'a')
+
+print('a' != 'a')
+print('a' != 'ab')
+print('a' != 1)
+print('a' != ())
diff --git a/tests/basics/import-pkg3.py b/tests/basics/import-pkg3.py
new file mode 100644
index 000000000..0ee885b22
--- /dev/null
+++ b/tests/basics/import-pkg3.py
@@ -0,0 +1,6 @@
+from pkg import mod
+
+print(mod.foo())
+
+import pkg.mod
+print(mod is pkg.mod)
diff --git a/tests/bytecode/mp-tests/assign2.py b/tests/bytecode/mp-tests/assign2.py
index f55a3221d..cb03593d2 100644
--- a/tests/bytecode/mp-tests/assign2.py
+++ b/tests/bytecode/mp-tests/assign2.py
@@ -6,5 +6,16 @@ a, *b, c = d
[*a] = b
[*a,] = b
[a, *b] = c
-#[a, *b,] = c
-#[a, *b, c] = d
+[a, *b,] = c
+[a, *b, c] = d
+
+(*a,) = x
+(*a, b) = x
+(a, *b) = x
+(*a, b, c) = x
+(a, *b, c) = x
+(a, b, *c) = x
+(*a, b, c, d) = x
+(a, *b, c, d) = x
+(a, b, *c, d) = x
+(a, b, c, *d) = x
diff --git a/tests/bytecode/mp-tests/yield2.py b/tests/bytecode/mp-tests/yield2.py
index 140fe0795..acc0ec8e9 100644
--- a/tests/bytecode/mp-tests/yield2.py
+++ b/tests/bytecode/mp-tests/yield2.py
@@ -2,3 +2,6 @@ def f():
yield from a
yield from (a, b)
yield from f(a)
+
+lambda:(yield)
+lambda:(yield 1) + 2