From d4f6cec3d0ca3fc9baa2c71d8b741b05fc55ee10 Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 5 Oct 2017 11:17:49 -0400 Subject: [PATCH] Sync with master --- .gitignore | 3 ++- pytest/test_grammar.py | 5 +++-- uncompyle6/parser.py | 7 ++++++- uncompyle6/parsers/parse26.py | 4 +++- uncompyle6/parsers/parse27.py | 4 ++++ uncompyle6/parsers/parse3.py | 7 +++++++ uncompyle6/semantics/consts.py | 11 +++++++++-- uncompyle6/semantics/pysource.py | 8 +++++++- 8 files changed, 41 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index d4e5cf9c..856518e3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ __pycache__ build /.venv* -/.idea \ No newline at end of file +/.idea +/.hypothesis diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index adccec02..241d064d 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -39,13 +39,14 @@ def test_grammar(): s = get_scanner(PYTHON_VERSION, IS_PYPY) ignore_set = set( """ - JUMP_BACK CONTINUE RETURN_END_IF + JUMP_BACK CONTINUE COME_FROM COME_FROM_EXCEPT COME_FROM_EXCEPT_CLAUSE COME_FROM_LOOP COME_FROM_WITH COME_FROM_FINALLY ELSE LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP - LAMBDA_MARKER RETURN_LAST + LAMBDA_MARKER + RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST """.split()) if 2.6 <= PYTHON_VERSION <= 2.7: opcode_set = set(s.opc.opname).union(ignore_set) diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 83391a32..93b181ae 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -254,8 +254,11 @@ class PythonParser(GenericASTBuilder): stmt ::= return_stmt return_stmt ::= ret_expr RETURN_VALUE + return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA + return_stmts ::= return_stmt return_stmts ::= _stmts return_stmt + """ pass @@ -530,7 +533,9 @@ class PythonParser(GenericASTBuilder): stmt ::= return_lambda stmt ::= conditional_lambda - return_lambda ::= ret_expr RETURN_VALUE LAMBDA_MARKER + return_lambda ::= ret_expr RETURN_VALUE_LAMBDA LAMBDA_MARKER + return_lambda ::= ret_expr RETURN_VALUE_LAMBDA + conditional_lambda ::= expr jmp_false return_if_stmt return_stmt LAMBDA_MARKER cmp ::= cmp_list diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index df7cc42c..79ae264d 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -247,7 +247,9 @@ class Python26Parser(Python2Parser): and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP cmp_list ::= expr cmp_list1 ROT_TWO COME_FROM POP_TOP _come_from - conditional_lambda ::= expr jmp_false_then return_if_stmt return_stmt LAMBDA_MARKER + return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP + conditional_lambda ::= expr jmp_false_then expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER """ def add_custom_rules(self, tokens, customize): diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index d7392810..614b30da 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -94,6 +94,10 @@ class Python27Parser(Python2Parser): WITH_CLEANUP END_FINALLY # Common with 2.6 + return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM + conditional_lambda ::= expr jmp_false expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER + while1stmt ::= SETUP_LOOP return_stmts bp_come_from while1stmt ::= SETUP_LOOP return_stmts COME_FROM """ diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a78defe0..ed5e6c34 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -416,6 +416,13 @@ class Python3Parser(PythonParser): # a JUMP_ABSOLUTE with no COME_FROM conditional ::= expr jmp_false expr jump_absolute_else expr + return_if_lambda ::= RETURN_END_IF_LAMBDA + conditional_lambda ::= expr jmp_false return_stmt_lambda + return_stmt_lambda LAMBDA_MARKER + conditional_lambda ::= expr jmp_false expr return_if_lambda + return_stmt_lambda LAMBDA_MARKER + + expr ::= LOAD_CLASSNAME # Python 3.4+ diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index b5d49644..db0390f1 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -173,8 +173,13 @@ TABLE_DIRECT = { 'ret_cond': ( '%p if %p else %p', (2, 27), (0, 27), (-1, 27) ), 'conditionalnot': ( '%p if not %p else %p', (2, 27), (0, 22), (4, 27) ), 'ret_cond_not': ( '%p if not %p else %p', (2, 27), (0, 22), (-1, 27) ), - 'conditional_lambda': ( '(%c if %c else %c)', 2, 0, 3), - 'return_lambda': ('%c', 0), + 'conditional_lambda': ( '%c if %c else %c', 2, 0, 4), + + # The semicolon is because Python 3.x can have be dead code as a result of its + # optimization. We don't Python's remove dead code (yet) anymore than Python does. + # So without that we would have "return 2return3" rather than "return 2;return 3" + 'return_lambda': ('return %c;', 0), + 'compare': ( '%p %[-1]{pattr.replace("-", " ")} %p', (0, 19), (1, 19) ), 'cmp_list': ( '%p %p', (0, 29), (1, 30)), 'cmp_list1': ( '%[3]{pattr} %p %p', (0, 19), (-2, 19)), @@ -209,6 +214,7 @@ TABLE_DIRECT = { 'raise_stmt3': ( '%|raise %c, %c, %c\n', 0, 1, 2), # 'yield': ( 'yield %c', 0), # 'return_stmt': ( '%|return %c\n', 0), + 'return_if_stmt': ( 'return %c\n', 0), 'ifstmt': ( '%|if %c:\n%+%c%-', 0, 1 ), 'iflaststmt': ( '%|if %c:\n%+%c%-', 0, 1 ), @@ -331,6 +337,7 @@ PRECEDENCE = { 'ret_or': 26, 'conditional': 28, + 'conditional_lamdba': 28, 'conditionalnot': 28, 'ret_cond': 28, 'ret_cond_not': 28, diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 3b1df2c8..b72596d0 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -658,6 +658,7 @@ class SourceWalker(GenericASTTraversal, object): def n_return_if_stmt(self, node): if self.params['isLambda']: + self.write(' return ') self.preorder(node[0]) self.prune() else: @@ -2149,6 +2150,11 @@ class SourceWalker(GenericASTTraversal, object): # assert isinstance(tokens[0], Token) if isLambda: + for t in tokens: + if t.type == 'RETURN_END_IF': + t.type = 'RETURN_END_IF_LAMBDA' + elif t.type == 'RETURN_VALUE': + t.type = 'RETURN_VALUE_LAMBDA' tokens.append(Token('LAMBDA_MARKER')) try: ast = python_parser.parse(self.p, tokens, customize) @@ -2165,7 +2171,7 @@ class SourceWalker(GenericASTTraversal, object): # than fight (with the grammar to not emit "return None"). if self.hide_internal: if len(tokens) >= 2 and not noneInNames: - if tokens[-1].type == 'RETURN_VALUE': + if tokens[-1].type in ('RETURN_VALUE', 'RETURN_VALUE_LAMBDA'): # Python 3.4's classes can add a "return None" which is # invalid syntax. if tokens[-2].type == 'LOAD_CONST':