diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index f2af9b98..ab035d61 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -653,10 +653,10 @@ class Python2Parser(PythonParser): pass self.reduce_check_table = { - # "and": and_check, + # "and": and_invalid, "except_handler_else": except_handler_else, "ifelsestmt": ifelsestmt, - # "or": or_check, + # "or": or_invalid, "tryelsestmt": tryelsestmt, "tryelsestmtl": tryelsestmt, } diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index febfd8fa..b2765eef 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -9,6 +9,7 @@ from uncompyle6.parsers.parse2 import Python2Parser from uncompyle6.parsers.reducecheck import ( aug_assign1_check, ifelsestmt, + for_block_check, or_check, tryelsestmt, except_handler, @@ -87,6 +88,11 @@ class Python27Parser(Python2Parser): for_block ::= l_stmts_opt JUMP_BACK + # In 2.7 there is occasionally a for_block has an unusual + # form: there is a JUMP_ABSOLUTE which jumps to the second JUMP_BACK + # listed below. Both JUMP_BACKS go to the same position so the + # the JUMP_ABSOLUTE and JUMP_BACK not necessary + for_block ::= l_stmts_opt JUMP_ABSOLUTE JUMP_BACK JUMP_BACK """ def p_jump27(self, args): @@ -234,6 +240,7 @@ class Python27Parser(Python2Parser): self.reduce_check_table = { "aug_assign1": aug_assign1_check, "except_handler": except_handler, + "for_block": for_block_check.for_block_invalid, "ifelsestmt": ifelsestmt, "or": or_check, "tryelsestmt": tryelsestmt, @@ -247,6 +254,8 @@ class Python27Parser(Python2Parser): self.check_reduce["except_handler"] = "tokens" self.check_reduce["except_handler_else"] = "tokens" + self.check_reduce["for_block"] = "tokens" + self.check_reduce["or"] = "AST" self.check_reduce["raise_stmt1"] = "AST" self.check_reduce["iflaststmtl"] = "AST" diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a655045a..63c8e49e 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -30,7 +30,7 @@ import re from uncompyle6.scanners.tok import Token from uncompyle6.parser import PythonParser, PythonParserSingle, nop_func from uncompyle6.parsers.reducecheck import ( - and_check, + and_invalid, except_handler_else, ifelsestmt, ifstmt, @@ -1581,7 +1581,7 @@ class Python3Parser(PythonParser): } if self.version == (3, 6): - self.reduce_check_table["and"] = and_check + self.reduce_check_table["and"] = and_invalid self.check_reduce["and"] = "AST" self.check_reduce["annotate_tuple"] = "noAST" diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index d1825eb2..58286b00 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -8,7 +8,7 @@ from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from spark_parser.spark import rule2str from uncompyle6.parsers.reducecheck import ( - and_check, + and_invalid, ifelsestmt, iflaststmt, ifstmt, @@ -1128,7 +1128,7 @@ class Python37BaseParser(PythonParser): self.reduce_check_table = { "_ifstmts_jump": ifstmts_jump, - "and": and_check, + "and": and_invalid, "ifelsestmt": ifelsestmt, "ifelsestmtl": ifelsestmt, "iflaststmt": iflaststmt, diff --git a/uncompyle6/parsers/parse38.py b/uncompyle6/parsers/parse38.py index 3c7789d7..69c2f4c6 100644 --- a/uncompyle6/parsers/parse38.py +++ b/uncompyle6/parsers/parse38.py @@ -20,7 +20,6 @@ from __future__ import print_function from uncompyle6.parser import PythonParserSingle, nop_func from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG from uncompyle6.parsers.parse37 import Python37Parser -from uncompyle6.parsers.reducecheck import joined_str_check class Python38Parser(Python37Parser): def p_38_stmt(self, args): diff --git a/uncompyle6/parsers/reducecheck/__init__.py b/uncompyle6/parsers/reducecheck/__init__.py index c91bd332..4f99ab2f 100644 --- a/uncompyle6/parsers/reducecheck/__init__.py +++ b/uncompyle6/parsers/reducecheck/__init__.py @@ -1,17 +1,18 @@ -from uncompyle6.parsers.reducecheck.and_check import * -from uncompyle6.parsers.reducecheck.aug_assign import * -from uncompyle6.parsers.reducecheck.except_handler import * -from uncompyle6.parsers.reducecheck.except_handler_else import * -from uncompyle6.parsers.reducecheck.ifelsestmt import * -from uncompyle6.parsers.reducecheck.ifelsestmt2 import * -from uncompyle6.parsers.reducecheck.iflaststmt import * -from uncompyle6.parsers.reducecheck.ifstmt import * -from uncompyle6.parsers.reducecheck.ifstmt2 import * -from uncompyle6.parsers.reducecheck.ifstmts_jump import * -from uncompyle6.parsers.reducecheck.or_check import * -from uncompyle6.parsers.reducecheck.testtrue import * -from uncompyle6.parsers.reducecheck.tryelsestmt import * -from uncompyle6.parsers.reducecheck.tryexcept import * -from uncompyle6.parsers.reducecheck.tryelsestmtl3 import * -from uncompyle6.parsers.reducecheck.while1elsestmt import * -from uncompyle6.parsers.reducecheck.while1stmt import * +from uncompyle6.parsers.reducecheck.and_check import * # noqa +from uncompyle6.parsers.reducecheck.aug_assign import * # noqa +from uncompyle6.parsers.reducecheck.except_handler import * # noqa +from uncompyle6.parsers.reducecheck.except_handler_else import * # noqa +from uncompyle6.parsers.reducecheck.ifelsestmt import * # noqa +from uncompyle6.parsers.reducecheck.ifelsestmt2 import * # noqa +from uncompyle6.parsers.reducecheck.iflaststmt import * # noqa +from uncompyle6.parsers.reducecheck.ifstmt import * # noqa +from uncompyle6.parsers.reducecheck.ifstmt2 import * # noqa +from uncompyle6.parsers.reducecheck.ifstmts_jump import * # noqa +from uncompyle6.parsers.reducecheck.for_block_check import * # noqa +from uncompyle6.parsers.reducecheck.or_check import * # noqa +from uncompyle6.parsers.reducecheck.testtrue import * # noqa +from uncompyle6.parsers.reducecheck.tryelsestmt import * # noqa +from uncompyle6.parsers.reducecheck.tryexcept import * # noqa +from uncompyle6.parsers.reducecheck.tryelsestmtl3 import * # noqa +from uncompyle6.parsers.reducecheck.while1elsestmt import * # noqa +from uncompyle6.parsers.reducecheck.while1stmt import * # noqa diff --git a/uncompyle6/parsers/reducecheck/and_check.py b/uncompyle6/parsers/reducecheck/and_check.py index 5e590821..afffbcb3 100644 --- a/uncompyle6/parsers/reducecheck/and_check.py +++ b/uncompyle6/parsers/reducecheck/and_check.py @@ -1,7 +1,13 @@ -# Copyright (c) 2020 Rocky Bernstein +# Copyright (c) 2020, 2022 Rocky Bernstein +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or -def and_check(self, lhs, n, rule, ast, tokens, first, last): + +def and_invalid( + self, lhs: str, n: int, rule, ast, tokens: list, first: int, last: int + ) -> bool: jmp = ast[1] if jmp.kind.startswith("jmp_"): if last == n: diff --git a/uncompyle6/parsers/reducecheck/for_block_check.py b/uncompyle6/parsers/reducecheck/for_block_check.py new file mode 100644 index 00000000..cf9a22a5 --- /dev/null +++ b/uncompyle6/parsers/reducecheck/for_block_check.py @@ -0,0 +1,73 @@ +# Copyright (c) 2022 Rocky Bernstein + +from uncompyle6.scanners.tok import Token + + +def for_block_invalid(self, lhs, n, rule, tree, tokens, first: int, last: int) -> bool: + + # print("XXX", first, last) + # for t in range(first, last): + # print(tokens[t]) + # print("=" * 30) + + if rule == ( + "for_block", + ("l_stmts_opt", "JUMP_ABSOLUTE", "JUMP_BACK", "JUMP_BACK"), + ): + # Check that the two JUMP_BACK's go to the same place. + jump_back1 = tokens[last - 2] + jump_back2 = tokens[last - 1] + if jump_back1.attr != jump_back2.attr: + return True + + # Also check that JUMP_ABSOLUTE jumps to the JUMP_BACK. + # In this situation the JUMP_ABSOLUTE and a JUMP_BACK + # is not needed, but it seems to be there anyway. + + jump_absolute = tokens[last - 3] + if jump_absolute.attr != jump_back2.offset: + return True + + # Right now all of this is known to happen only in Python 2.7. + if self.version[:2] == (2, 7): + return False + + if len(rule[1]) <= 1 or not tree: + return False + + come_froms = tree[-1] + # This is complicated, but note that the JUMP_IF instruction comes immediately + # *before* _ifstmts_jump so that's what we have to test + # the COME_FROM against. This can be complicated by intervening + # POP_TOP, and pseudo COME_FROM, ELSE instructions + # + pop_jump_index = first - 1 + while pop_jump_index > 0 and tokens[pop_jump_index] in ( + "ELSE", + "POP_TOP", + "JUMP_FORWARD", + "COME_FROM", + ): + pop_jump_index -= 1 + + # FIXME: something is fishy when and EXTENDED ARG is needed before the + # pop_jump_index instruction to get the argment. In this case, the + # _ifsmtst_jump can jump to a spot beyond the come_froms. + # That is going on in the non-EXTENDED_ARG case is that the POP_JUMP_IF + # jumps to a JUMP_(FORWARD) which is changed into an EXTENDED_ARG POP_JUMP_IF + # to the jumped forwarded address + if tokens[pop_jump_index].attr > 256: + return False + + pop_jump_offset = tokens[pop_jump_index].off2int(prefer_last=False) + if isinstance(come_froms, Token): + if tokens[pop_jump_index].attr < pop_jump_offset and tree[0] != "pass": + # This is a jump backwards to a loop. All bets are off here when there the + # unless statement is "pass" which has no instructions associated with it. + return False + return come_froms.attr is not None and pop_jump_offset > come_froms.attr + + elif len(come_froms) == 0: + return False + else: + return pop_jump_offset > come_froms[-1].attr diff --git a/uncompyle6/parsers/reducecheck/joined_str_check.py b/uncompyle6/parsers/reducecheck/joined_str_check.py index 96ddc7b9..c6f67441 100644 --- a/uncompyle6/parsers/reducecheck/joined_str_check.py +++ b/uncompyle6/parsers/reducecheck/joined_str_check.py @@ -13,7 +13,7 @@ # along with this program. If not, see . -def joined_str_ok( +def joined_str_invalid( self, lhs: str, n: int, rule, tree, tokens: list, first: int, last: int ) -> bool: # In Python 3.8, there is a new "=" specifier. diff --git a/uncompyle6/semantics/customize37.py b/uncompyle6/semantics/customize37.py index fd6f0952..d5ac3bc4 100644 --- a/uncompyle6/semantics/customize37.py +++ b/uncompyle6/semantics/customize37.py @@ -221,12 +221,12 @@ def customize_for_version37(self, version): def n_async_call(node): self.f.write("async ") - node.kind == "call" + node.kind = "call" p = self.prec self.prec = 80 self.template_engine(("%c(%P)", 0, (1, -4, ", ", 100)), node) self.prec = p - node.kind == "async_call" + node.kind = "async_call" self.prune() self.n_async_call = n_async_call