diff options
| -rw-r--r-- | py/builtinimport.c | 20 | ||||
| -rw-r--r-- | py/compile.c | 172 | ||||
| -rw-r--r-- | py/emitbc.c | 6 | ||||
| -rw-r--r-- | py/emitglue.c | 3 | ||||
| -rw-r--r-- | py/makeqstrdata.py | 28 | ||||
| -rw-r--r-- | py/obj.c | 48 | ||||
| -rw-r--r-- | py/obj.h | 29 | ||||
| -rw-r--r-- | py/objdict.c | 4 | ||||
| -rw-r--r-- | py/objfun.c | 1 | ||||
| -rw-r--r-- | py/objint_longlong.c | 2 | ||||
| -rw-r--r-- | py/objint_mpz.c | 2 | ||||
| -rw-r--r-- | py/objlist.c | 2 | ||||
| -rw-r--r-- | py/objset.c | 2 | ||||
| -rw-r--r-- | py/objstr.c | 21 | ||||
| -rw-r--r-- | py/objtuple.c | 2 | ||||
| -rw-r--r-- | py/py.mk | 5 | ||||
| -rw-r--r-- | py/qstrdefs.h | 3 | ||||
| -rw-r--r-- | py/runtime.c | 44 | ||||
| -rw-r--r-- | py/showbc.c | 9 | ||||
| -rw-r--r-- | py/vm.c | 8 | ||||
| -rw-r--r-- | tests/basics/equal.py | 75 | ||||
| -rw-r--r-- | tests/basics/import-pkg3.py | 6 | ||||
| -rw-r--r-- | tests/bytecode/mp-tests/assign2.py | 15 | ||||
| -rw-r--r-- | tests/bytecode/mp-tests/yield2.py | 3 |
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 @@ -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))); } @@ -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 @@ -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; @@ -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 |
