diff --git a/test/bytecode_3.3_run/08_if_else.pyc b/test/bytecode_3.3_run/08_if_else.pyc new file mode 100644 index 00000000..1a1b60be Binary files /dev/null and b/test/bytecode_3.3_run/08_if_else.pyc differ diff --git a/test/bytecode_3.6_run/08_comp_gen_for.pyc b/test/bytecode_3.6_run/08_comp_gen_for.pyc new file mode 100644 index 00000000..3f0e838b Binary files /dev/null and b/test/bytecode_3.6_run/08_comp_gen_for.pyc differ diff --git a/test/bytecode_3.6_run/08_if_else.pyc b/test/bytecode_3.6_run/08_if_else.pyc new file mode 100644 index 00000000..e7da12b3 Binary files /dev/null and b/test/bytecode_3.6_run/08_if_else.pyc differ diff --git a/test/simple_source/bug33/08_if_else.py b/test/simple_source/bug33/08_if_else.py new file mode 100644 index 00000000..1e60bb94 --- /dev/null +++ b/test/simple_source/bug33/08_if_else.py @@ -0,0 +1,10 @@ +# From python 3.3.7 trace +# Bug was not having not having semantic rule for conditional not + +# RUNNABLE! +def init(modules=None): + mods = set() if not modules else set(modules) + return mods + +assert init() == set() +assert init([1, 2, 3]) == set([1, 2, 3]) diff --git a/test/simple_source/bug36/08_comp_gen_for.py b/test/simple_source/bug36/08_comp_gen_for.py new file mode 100644 index 00000000..20c64bb9 --- /dev/null +++ b/test/simple_source/bug36/08_comp_gen_for.py @@ -0,0 +1,19 @@ +# Bug in 3.3 weakset +# Bug was not having a rule for 3.x "comp_for" + +# RUNNABLE! +class WeakSet: + def __init__(self, data=None): + self.data = set(data) + + def __iter__(self): + for item in self.data: + if item is not None: + yield item + + def union(self, other): + return self.__class__(e for s in (self, other) for e in s) + +a = WeakSet([1, 2, 3]) +b = WeakSet([1, 3, 5]) +assert list(a.union(b)) == [1, 2, 3, 5] diff --git a/test/test_pyenvlib.py b/test/test_pyenvlib.py index 97ff893b..c34eeabd 100755 --- a/test/test_pyenvlib.py +++ b/test/test_pyenvlib.py @@ -36,8 +36,9 @@ python_versions = [v for v in magics.python_versions if # These include Jython, and Python bytecode changes pre release. TEST_VERSIONS = ( - 'pypy-2.4.0', 'pypy-2.6.1', + 'pypy3-2.4.0', 'pypy-2.6.1', 'pypy-5.0.1', 'pypy-5.3.1', 'pypy3.5-5.7.1-beta', + 'pypy3.5-5.9.0', 'native') + tuple(python_versions) @@ -57,19 +58,19 @@ test_options = { } for vers in TEST_VERSIONS: - if vers.startswith('pypy-'): + if vers.startswith('pypy'): short_vers = vers[0:-2] test_options[vers] = (os.path.join(lib_prefix, vers, 'lib_pypy'), PYC, 'python-lib'+short_vers) - if vers == 'native': - short_vers = os.path.basename(sys.path[-1]) - test_options[vers] = (sys.path[-1], - PYC, short_vers) - else: - short_vers = vers[:3] - test_options[vers] = (os.path.join(lib_prefix, vers, 'lib', 'python'+short_vers), - PYC, 'python-lib'+short_vers) + if vers == 'native': + short_vers = os.path.basename(sys.path[-1]) + test_options[vers] = (sys.path[-1], + PYC, short_vers) + else: + short_vers = vers[:3] + test_options[vers] = (os.path.join(lib_prefix, vers, 'lib', 'python'+short_vers), + PYC, 'python-lib'+short_vers) def do_tests(src_dir, patterns, target_dir, start_with=None, do_verify=False, max_files=200): diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index eea6c0b8..0f2f8a16 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -11,8 +11,8 @@ class Python30Parser(Python31Parser): def p_30(self, args): """ - assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 POP_TOP - return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP + assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 COME_FROM POP_TOP + return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM POP_TOP compare_chained2 ::= expr COMPARE_OP RETURN_END_IF_LAMBDA # FIXME: combine with parse3.2 @@ -27,10 +27,10 @@ class Python30Parser(Python31Parser): # instructions _ifstmts_jump ::= c_stmts JUMP_FORWARD _come_froms POP_TOP COME_FROM - _ifstmts_jump ::= c_stmts POP_TOP + _ifstmts_jump ::= c_stmts COME_FROM POP_TOP # Used to keep index order the same in semantic actions - jb_pop_top ::= JUMP_BACK POP_TOP + jb_pop_top ::= JUMP_BACK COME_FROM POP_TOP while1stmt ::= SETUP_LOOP l_stmts COME_FROM_LOOP whileelsestmt ::= SETUP_LOOP testexpr l_stmts @@ -44,7 +44,7 @@ class Python30Parser(Python31Parser): ifelsestmtl ::= testexpr c_stmts_opt jb_pop_top else_suitel iflaststmtl ::= testexpr c_stmts_opt jb_pop_top - iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE POP_TOP + iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE COME_FROM POP_TOP withasstmt ::= expr setupwithas store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_FINALLY @@ -77,17 +77,18 @@ class Python30Parser(Python31Parser): # JUMP_IF_TRUE POP_TOP as a replacement comp_if ::= expr jmp_false comp_iter - comp_if ::= expr jmp_false comp_iter JUMP_BACK POP_TOP - comp_if_not ::= expr jmp_true comp_iter JUMP_BACK POP_TOP + comp_if ::= expr jmp_false comp_iter JUMP_BACK COME_FROM POP_TOP + comp_if_not ::= expr jmp_true comp_iter JUMP_BACK COME_FROM POP_TOP comp_iter ::= expr expr SET_ADD comp_iter ::= expr expr LIST_APPEND - jump_forward_else ::= JUMP_FORWARD POP_TOP - jump_absolute_else ::= JUMP_ABSOLUTE POP_TOP + jump_forward_else ::= JUMP_FORWARD COME_FROM POP_TOP + jump_absolute_else ::= JUMP_ABSOLUTE COME_FROM POP_TOP except_suite ::= c_stmts POP_EXCEPT jump_except POP_TOP except_suite_finalize ::= SETUP_FINALLY c_stmts_opt except_var_finalize END_FINALLY - _jump POP_TOP - jump_except ::= JUMP_FORWARD POP_TOP + _jump COME_FROM POP_TOP + jump_except ::= JUMP_FORWARD COME_FROM POP_TOP + jump_except ::= JUMP_ABSOLUTE COME_FROM POP_TOP or ::= expr jmp_false expr jmp_true expr or ::= expr jmp_true expr @@ -109,7 +110,7 @@ class Python30Parser(Python31Parser): return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP and ::= expr jmp_false expr come_from_opt whilestmt ::= SETUP_LOOP testexpr l_stmts_opt come_from_opt - JUMP_BACK POP_TOP POP_BLOCK COME_FROM_LOOP + JUMP_BACK COME_FROM POP_TOP POP_BLOCK COME_FROM_LOOP whilestmt ::= SETUP_LOOP testexpr returns POP_TOP POP_BLOCK COME_FROM_LOOP diff --git a/uncompyle6/parsers/parse35.py b/uncompyle6/parsers/parse35.py index af558dab..e017484b 100644 --- a/uncompyle6/parsers/parse35.py +++ b/uncompyle6/parsers/parse35.py @@ -166,7 +166,7 @@ class Python35Parser(Python34Parser): async_with_stmt ::= expr BEFORE_ASYNC_WITH GET_AWAITABLE LOAD_CONST YIELD_FROM SETUP_ASYNC_WITH POP_TOP suite_stmts_opt - POP_BLOCK LOAD_CONST + POP_BLOCK LOAD_CONST COME_FROM_ASYNC_WITH WITH_CLEANUP_START GET_AWAITABLE LOAD_CONST YIELD_FROM WITH_CLEANUP_FINISH END_FINALLY @@ -176,7 +176,7 @@ class Python35Parser(Python34Parser): async_with_as_stmt ::= expr BEFORE_ASYNC_WITH GET_AWAITABLE LOAD_CONST YIELD_FROM SETUP_ASYNC_WITH store suite_stmts_opt - POP_BLOCK LOAD_CONST + POP_BLOCK LOAD_CONST COME_FROM_ASYNC_WITH WITH_CLEANUP_START GET_AWAITABLE LOAD_CONST YIELD_FROM WITH_CLEANUP_FINISH END_FINALLY diff --git a/uncompyle6/parsers/parse38.py b/uncompyle6/parsers/parse38.py index 7a8398e0..f6a2c0d5 100644 --- a/uncompyle6/parsers/parse38.py +++ b/uncompyle6/parsers/parse38.py @@ -73,7 +73,7 @@ class Python38Parser(Python37Parser): SETUP_ASYNC_WITH POP_TOP suite_stmts POP_TOP POP_BLOCK - BEGIN_FINALLY + BEGIN_FINALLY COME_FROM_ASYNC_WITH WITH_CLEANUP_START GET_AWAITABLE LOAD_CONST YIELD_FROM WITH_CLEANUP_FINISH END_FINALLY @@ -82,7 +82,7 @@ class Python38Parser(Python37Parser): SETUP_ASYNC_WITH store suite_stmts POP_TOP POP_BLOCK - BEGIN_FINALLY + BEGIN_FINALLY COME_FROM_ASYNC_WITH WITH_CLEANUP_START GET_AWAITABLE LOAD_CONST YIELD_FROM WITH_CLEANUP_FINISH END_FINALLY @@ -124,8 +124,11 @@ class Python38Parser(Python37Parser): try_except_ret38 ::= SETUP_FINALLY expr POP_BLOCK RETURN_VALUE except_ret38a + # Note: there is a suite_stmts_opt which seems + # to be bookkeeping which is not expressed in source code except_ret38 ::= SETUP_FINALLY expr ROT_FOUR POP_BLOCK POP_EXCEPT - CALL_FINALLY RETURN_VALUE COME_FROM_FINALLY + CALL_FINALLY RETURN_VALUE COME_FROM + COME_FROM_FINALLY suite_stmts_opt END_FINALLY except_ret38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP expr ROT_FOUR diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 0e3e8f49..68014e6f 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -510,9 +510,9 @@ class Scanner3(Scanner): next_offset = xdis.next_offset(op, self.opc, offset) if label is None: - if op in op3.hasjrel and op != self.opc.FOR_ITER: + if op in self.opc.hasjrel and op != self.opc.FOR_ITER: label = next_offset + oparg - elif op in op3.hasjabs: + elif op in self.opc.hasjabs: if op in self.jump_if_pop: if oparg > offset: label = oparg diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index d4aed209..3fcf6111 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -186,9 +186,9 @@ TABLE_DIRECT = { 'comp_if': ( ' if %c%c', 0, 2 ), 'comp_if_not': ( ' if not %p%c', (0, 22), 2 ), 'comp_body': ( '', ), # ignore when recusing - 'set_comp_body': ( '%c', 0 ), - 'gen_comp_body': ( '%c', 0 ), - 'dict_comp_body': ( '%c:%c', 1, 0 ), + 'set_comp_body': ( '%c', 0 ), + 'gen_comp_body': ( '%c', 0 ), + 'dict_comp_body': ( '%c:%c', 1, 0 ), 'assign': ( '%|%c = %p\n', -1, (0, 200) ), diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index 5b7e300b..186e278a 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -27,13 +27,17 @@ from uncompyle6.semantics.customize38 import customize_for_version38 def customize_for_version3(self, version): TABLE_DIRECT.update({ - 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), + 'comp_for' : ( ' for %c in %c', + (2, 'store') , (0, 'expr') ), + 'conditionalnot' : ( '%c if not %c else %c', + (2, 'expr') , (0, 'expr'), (4, 'expr') ), + 'except_cond2' : ( '%|except %c as %c:\n', 1, 5 ), 'function_def_annotate': ( '\n\n%|def %c%c\n', -1, 0), - 'importmultiple': ( '%|import %c%c\n', 2, 3 ), - 'import_cont' : ( ', %c', 2 ), - 'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ), - 'withstmt': ( '%|with %c:\n%+%c%-', 0, 3), - 'withasstmt': ( '%|with %c as (%c):\n%+%c%-', 0, 2, 3), + 'importmultiple' : ( '%|import %c%c\n', 2, 3 ), + 'import_cont' : ( ', %c', 2 ), + 'store_locals' : ( '%|# inspect.currentframe().f_locals = __locals__\n', ), + 'withstmt' : ( '%|with %c:\n%+%c%-', 0, 3), + 'withasstmt' : ( '%|with %c as (%c):\n%+%c%-', 0, 2, 3), }) assert version >= 3.0 diff --git a/uncompyle6/semantics/customize38.py b/uncompyle6/semantics/customize38.py index 472851d6..aa46e396 100644 --- a/uncompyle6/semantics/customize38.py +++ b/uncompyle6/semantics/customize38.py @@ -54,7 +54,11 @@ def customize_for_version38(self, version): 'except_ret38a': ( 'return %c', (4, 'expr') ), + + # Note: there is a suite_stmts_opt which seems + # to be bookkeeping which is not expressed in source code 'except_ret38': ( '%|return %c\n', (1, 'expr') ), + 'for38': ( '%|for %c in %c:\n%+%c%-\n\n', (2, 'store'), diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index d7e4102f..4b7abe45 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1081,7 +1081,7 @@ class SourceWalker(GenericASTTraversal, object): n = (k[3], k[1]) pass elif k == 'comp_iter': - n = k[1] + n = k[0] pass pass else: