You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Merging in recent 3.7 and 3.8 improvements from decompyle6
This rebases 3.7, 3.8 ...decompilation off of 3.7ish rather than a 3.4 base. Add more 3.7 and 3.8 tests
This commit is contained in:
@@ -20,8 +20,12 @@ def test_grammar():
|
|||||||
(lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets()
|
(lhs, rhs, tokens, right_recursive, dup_rhs) = p.check_sets()
|
||||||
|
|
||||||
# We have custom rules that create the below
|
# We have custom rules that create the below
|
||||||
expect_lhs = set(["pos_arg", "attribute"])
|
expect_lhs = set(["pos_arg"])
|
||||||
|
|
||||||
if PYTHON_VERSION < 3.8:
|
if PYTHON_VERSION < 3.8:
|
||||||
|
if PYTHON_VERSION < 3.7:
|
||||||
|
expect_lhs.add("attribute")
|
||||||
|
|
||||||
expect_lhs.add("get_iter")
|
expect_lhs.add("get_iter")
|
||||||
else:
|
else:
|
||||||
expect_lhs.add("async_with_as_stmt")
|
expect_lhs.add("async_with_as_stmt")
|
||||||
@@ -31,7 +35,7 @@ def test_grammar():
|
|||||||
|
|
||||||
expect_right_recursive = set([("designList", ("store", "DUP_TOP", "designList"))])
|
expect_right_recursive = set([("designList", ("store", "DUP_TOP", "designList"))])
|
||||||
|
|
||||||
if PYTHON_VERSION < 3.7:
|
if PYTHON_VERSION <= 3.7:
|
||||||
unused_rhs.add("call")
|
unused_rhs.add("call")
|
||||||
|
|
||||||
if PYTHON_VERSION > 2.6:
|
if PYTHON_VERSION > 2.6:
|
||||||
@@ -50,9 +54,11 @@ def test_grammar():
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
if PYTHON_VERSION >= 3.0:
|
if PYTHON_VERSION >= 3.0:
|
||||||
expect_lhs.add("annotate_arg")
|
if PYTHON_VERSION < 3.7:
|
||||||
expect_lhs.add("annotate_tuple")
|
expect_lhs.add("annotate_arg")
|
||||||
unused_rhs.add("mkfunc_annotate")
|
expect_lhs.add("annotate_tuple")
|
||||||
|
unused_rhs.add("mkfunc_annotate")
|
||||||
|
|
||||||
unused_rhs.add("dict_comp")
|
unused_rhs.add("dict_comp")
|
||||||
unused_rhs.add("classdefdeco1")
|
unused_rhs.add("classdefdeco1")
|
||||||
unused_rhs.add("tryelsestmtl")
|
unused_rhs.add("tryelsestmtl")
|
||||||
|
BIN
test/bytecode_3.7_run/00_chained-compare.pyc
Normal file
BIN
test/bytecode_3.7_run/00_chained-compare.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/03_ifelse_chained_for.pyc
Normal file
BIN
test/bytecode_3.7_run/03_ifelse_chained_for.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/06_while_return.pyc
Normal file
BIN
test/bytecode_3.7_run/06_while_return.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/14_mixed_expressions.pyc
Normal file
BIN
test/bytecode_3.7_run/14_mixed_expressions.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.8_run/00_docstring.pyc
Normal file
BIN
test/bytecode_3.8_run/00_docstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/01_chained_compare.pyc
Normal file
BIN
test/bytecode_3.8_run/01_chained_compare.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/01_extra_iter.pyc
Normal file
BIN
test/bytecode_3.8_run/01_extra_iter.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/01_fstring.pyc
Normal file
BIN
test/bytecode_3.8_run/01_fstring.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/04_def_annotate.pyc
Normal file
BIN
test/bytecode_3.8_run/04_def_annotate.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/04_for_no_jump_back.pyc
Normal file
BIN
test/bytecode_3.8_run/04_for_no_jump_back.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.8_run/14_mixed_expressions.pyc
Normal file
BIN
test/bytecode_3.8_run/14_mixed_expressions.pyc
Normal file
Binary file not shown.
24
test/simple_source/bug37/03_ifelse_chained_for.py
Normal file
24
test/simple_source/bug37/03_ifelse_chained_for.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# From decompyle3/semantics/customize3.py
|
||||||
|
# The bug is handling "for" loop inside the
|
||||||
|
# chained compare ifelse
|
||||||
|
def n_classdef3(a, b, c, l):
|
||||||
|
r = 1
|
||||||
|
if 3.0 <= a <= 3.2:
|
||||||
|
for n in l:
|
||||||
|
if b:
|
||||||
|
break
|
||||||
|
elif c:
|
||||||
|
r = 2
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
r = 3
|
||||||
|
pass
|
||||||
|
return r
|
||||||
|
|
||||||
|
assert n_classdef3(10, True, True, []) == 3
|
||||||
|
assert n_classdef3(0, False, True, []) == 3
|
||||||
|
assert n_classdef3(3.1, True, True, []) == 1
|
||||||
|
assert n_classdef3(3.1, True, False, [1]) == 1
|
||||||
|
assert n_classdef3(3.1, True, True, [2]) == 1
|
||||||
|
assert n_classdef3(3.1, False, True, [3]) == 2
|
5
test/simple_source/bug38/01_named_expr.py
Normal file
5
test/simple_source/bug38/01_named_expr.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
(x, y) = "foo", 0
|
||||||
|
if x := __name__:
|
||||||
|
y = 1
|
||||||
|
assert x == "__main__", "Walrus operator changes value"
|
||||||
|
assert y == 1, "Walrus operator branch taken"
|
17
test/simple_source/bug38/04_for_no_jump_back.py
Normal file
17
test/simple_source/bug38/04_for_no_jump_back.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# from mult_by_const/instruction.py
|
||||||
|
# Bug in 3.8 was handling no JUMP_BACK in "for" loop. It is
|
||||||
|
# in the "if" instead
|
||||||
|
def instruction_sequence_value(instrs, a, b):
|
||||||
|
for instr in instrs:
|
||||||
|
if a:
|
||||||
|
a = 6
|
||||||
|
elif b:
|
||||||
|
return 0
|
||||||
|
pass
|
||||||
|
|
||||||
|
return a
|
||||||
|
|
||||||
|
assert instruction_sequence_value([], True, True) == 1
|
||||||
|
assert instruction_sequence_value([1], True, True) == 6
|
||||||
|
assert instruction_sequence_value([1], False, True) == 0
|
||||||
|
assert instruction_sequence_value([1], False, False) == False
|
53
test/simple_source/expression/14_mixed_expressions.py
Normal file
53
test/simple_source/expression/14_mixed_expressions.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Covers a large number of operators
|
||||||
|
#
|
||||||
|
# This code is RUNNABLE!
|
||||||
|
|
||||||
|
import sys
|
||||||
|
PYTHON_VERSION = sys.version_info[0] + (sys.version_info[1] / 10.0)
|
||||||
|
|
||||||
|
assert PYTHON_VERSION >= 3.7
|
||||||
|
|
||||||
|
# some floats (from 01_float.py)
|
||||||
|
|
||||||
|
x = 1e300
|
||||||
|
assert 0.0 == x * 0
|
||||||
|
assert x * 1e300 == float("inf")
|
||||||
|
assert str(float("inf") * 0.0) == "nan"
|
||||||
|
assert str(float("-inf") * 0.0) == "nan"
|
||||||
|
assert -1e300 * 1e300 == float("-inf")
|
||||||
|
|
||||||
|
# Complex (adapted from 02_complex.py)
|
||||||
|
y = 5j
|
||||||
|
assert y ** 2 == -25
|
||||||
|
y **= 3
|
||||||
|
assert y == (-0-125j)
|
||||||
|
|
||||||
|
|
||||||
|
# Tests BINARY_TRUE_DIVIDE and INPLACE_TRUE_DIVIDE (from 02_try_divide.py)
|
||||||
|
x = 2
|
||||||
|
assert 4 / x == 2
|
||||||
|
|
||||||
|
x = 5
|
||||||
|
assert x / 2 == 2.5
|
||||||
|
x = 3
|
||||||
|
x /= 2
|
||||||
|
assert x == 1.5
|
||||||
|
|
||||||
|
x = 2
|
||||||
|
assert 4 // x == 2
|
||||||
|
x = 7
|
||||||
|
x //= 2
|
||||||
|
assert x == 3
|
||||||
|
|
||||||
|
x = 3
|
||||||
|
assert x % 2 == 1
|
||||||
|
x %= 2
|
||||||
|
assert x == 1
|
||||||
|
|
||||||
|
assert x << 2 == 4
|
||||||
|
x <<= 3
|
||||||
|
assert x == 8
|
||||||
|
|
||||||
|
assert x >> 1 == 4
|
||||||
|
x >>= 1
|
||||||
|
assert x == 4
|
File diff suppressed because it is too large
Load Diff
1304
uncompyle6/parsers/parse37base.py
Normal file
1304
uncompyle6/parsers/parse37base.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,12 @@ from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
|
|||||||
from uncompyle6.parsers.parse37 import Python37Parser
|
from uncompyle6.parsers.parse37 import Python37Parser
|
||||||
|
|
||||||
class Python38Parser(Python37Parser):
|
class Python38Parser(Python37Parser):
|
||||||
|
def p_38walrus(self, args):
|
||||||
|
"""
|
||||||
|
# named_expr is also known as the "walrus op" :=
|
||||||
|
expr ::= named_expr
|
||||||
|
named_expr ::= expr DUP_TOP store
|
||||||
|
"""
|
||||||
|
|
||||||
def p_38misc(self, args):
|
def p_38misc(self, args):
|
||||||
"""
|
"""
|
||||||
@@ -38,6 +44,12 @@ class Python38Parser(Python37Parser):
|
|||||||
stmt ::= whilestmt38
|
stmt ::= whilestmt38
|
||||||
stmt ::= whileTruestmt38
|
stmt ::= whileTruestmt38
|
||||||
stmt ::= call
|
stmt ::= call
|
||||||
|
stmt ::= ifstmtl
|
||||||
|
|
||||||
|
break ::= POP_BLOCK BREAK_LOOP
|
||||||
|
break ::= POP_BLOCK POP_TOP BREAK_LOOP
|
||||||
|
break ::= POP_TOP BREAK_LOOP
|
||||||
|
break ::= POP_EXCEPT BREAK_LOOP
|
||||||
|
|
||||||
# FIXME: this should be restricted to being inside a try block
|
# FIXME: this should be restricted to being inside a try block
|
||||||
stmt ::= except_ret38
|
stmt ::= except_ret38
|
||||||
@@ -89,27 +101,39 @@ class Python38Parser(Python37Parser):
|
|||||||
|
|
||||||
return ::= ret_expr ROT_TWO POP_TOP RETURN_VALUE
|
return ::= ret_expr ROT_TWO POP_TOP RETURN_VALUE
|
||||||
|
|
||||||
|
# 3.8 can push a looping JUMP_BACK into into a JUMP_ from a statement that jumps to it
|
||||||
|
lastl_stmt ::= ifpoplaststmtl
|
||||||
|
ifpoplaststmtl ::= testexpr POP_TOP c_stmts_opt JUMP_BACK
|
||||||
|
ifelsestmtl ::= testexpr c_stmts_opt jb_cfs else_suitel JUMP_BACK come_froms
|
||||||
|
|
||||||
|
_ifstmts_jumpl ::= c_stmts JUMP_BACK
|
||||||
|
_ifstmts_jumpl ::= _ifstmts_jump
|
||||||
|
ifstmtl ::= testexpr _ifstmts_jumpl
|
||||||
|
|
||||||
for38 ::= expr get_iter store for_block JUMP_BACK
|
for38 ::= expr get_iter store for_block JUMP_BACK
|
||||||
for38 ::= expr for_iter store for_block JUMP_BACK
|
for38 ::= expr get_for_iter store for_block JUMP_BACK
|
||||||
for38 ::= expr for_iter store for_block JUMP_BACK POP_BLOCK
|
for38 ::= expr get_for_iter store for_block JUMP_BACK POP_BLOCK
|
||||||
for38 ::= expr for_iter store for_block
|
for38 ::= expr get_for_iter store for_block
|
||||||
|
|
||||||
forelsestmt38 ::= expr for_iter store for_block POP_BLOCK else_suite
|
forelsestmt38 ::= expr get_for_iter store for_block POP_BLOCK else_suite
|
||||||
forelselaststmt38 ::= expr for_iter store for_block POP_BLOCK else_suitec
|
forelselaststmt38 ::= expr get_for_iter store for_block POP_BLOCK else_suitec
|
||||||
forelselaststmtl38 ::= expr for_iter store for_block POP_BLOCK else_suitel
|
forelselaststmtl38 ::= expr get_for_iter store for_block POP_BLOCK else_suitel
|
||||||
|
|
||||||
whilestmt38 ::= testexpr l_stmts_opt COME_FROM JUMP_BACK POP_BLOCK
|
whilestmt38 ::= _come_froms testexpr l_stmts_opt COME_FROM JUMP_BACK POP_BLOCK
|
||||||
whilestmt38 ::= testexpr l_stmts_opt JUMP_BACK POP_BLOCK
|
whilestmt38 ::= _come_froms testexpr l_stmts_opt JUMP_BACK POP_BLOCK
|
||||||
whilestmt38 ::= testexpr returns POP_BLOCK
|
whilestmt38 ::= _come_froms testexpr l_stmts_opt JUMP_BACK come_froms
|
||||||
whilestmt38 ::= testexpr l_stmts JUMP_BACK
|
whilestmt38 ::= _come_froms testexpr returns POP_BLOCK
|
||||||
|
whilestmt38 ::= _come_froms testexpr l_stmts JUMP_BACK
|
||||||
|
whilestmt38 ::= _come_froms testexpr l_stmts come_froms
|
||||||
|
|
||||||
# while1elsestmt ::= l_stmts JUMP_BACK
|
# while1elsestmt ::= l_stmts JUMP_BACK
|
||||||
whileTruestmt ::= l_stmts JUMP_BACK POP_BLOCK
|
whileTruestmt ::= _come_froms l_stmts JUMP_BACK POP_BLOCK
|
||||||
while1stmt ::= l_stmts COME_FROM_LOOP
|
while1stmt ::= _come_froms l_stmts COME_FROM_LOOP
|
||||||
while1stmt ::= l_stmts COME_FROM JUMP_BACK COME_FROM_LOOP
|
while1stmt ::= _come_froms l_stmts COME_FROM JUMP_BACK COME_FROM_LOOP
|
||||||
whileTruestmt38 ::= l_stmts JUMP_BACK
|
whileTruestmt38 ::= _come_froms l_stmts JUMP_BACK
|
||||||
|
whileTruestmt38 ::= _come_froms l_stmts JUMP_BACK COME_FROM_EXCEPT_CLAUSE
|
||||||
|
|
||||||
for_block ::= l_stmts_opt _come_from_loops JUMP_BACK
|
for_block ::= _come_froms l_stmts_opt _come_from_loops JUMP_BACK
|
||||||
|
|
||||||
except_cond1 ::= DUP_TOP expr COMPARE_OP jmp_false
|
except_cond1 ::= DUP_TOP expr COMPARE_OP jmp_false
|
||||||
POP_TOP POP_TOP POP_TOP
|
POP_TOP POP_TOP POP_TOP
|
||||||
@@ -134,7 +158,8 @@ class Python38Parser(Python37Parser):
|
|||||||
except_ret38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
|
except_ret38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
|
||||||
expr ROT_FOUR
|
expr ROT_FOUR
|
||||||
POP_EXCEPT RETURN_VALUE END_FINALLY
|
POP_EXCEPT RETURN_VALUE END_FINALLY
|
||||||
except_handler38 ::= JUMP_FORWARD COME_FROM_FINALLY
|
|
||||||
|
except_handler38 ::= _jump COME_FROM_FINALLY
|
||||||
except_stmts END_FINALLY opt_come_from_except
|
except_stmts END_FINALLY opt_come_from_except
|
||||||
except_handler38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
|
except_handler38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
|
||||||
POP_EXCEPT POP_TOP stmts END_FINALLY
|
POP_EXCEPT POP_TOP stmts END_FINALLY
|
||||||
@@ -160,13 +185,15 @@ class Python38Parser(Python37Parser):
|
|||||||
self.customized = {}
|
self.customized = {}
|
||||||
|
|
||||||
def remove_rules_38(self):
|
def remove_rules_38(self):
|
||||||
self.remove_rules("""
|
self.remove_rules(
|
||||||
|
"""
|
||||||
stmt ::= async_for_stmt37
|
stmt ::= async_for_stmt37
|
||||||
stmt ::= for
|
stmt ::= for
|
||||||
stmt ::= forelsestmt
|
stmt ::= forelsestmt
|
||||||
stmt ::= try_except36
|
stmt ::= try_except36
|
||||||
|
stmt ::= async_forelse_stmt
|
||||||
|
|
||||||
async_for_stmt ::= SETUP_LOOP expr
|
async_for_stmt ::= setup_loop expr
|
||||||
GET_AITER
|
GET_AITER
|
||||||
SETUP_EXCEPT GET_ANEXT LOAD_CONST
|
SETUP_EXCEPT GET_ANEXT LOAD_CONST
|
||||||
YIELD_FROM
|
YIELD_FROM
|
||||||
@@ -178,7 +205,7 @@ class Python38Parser(Python37Parser):
|
|||||||
COME_FROM
|
COME_FROM
|
||||||
POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
|
POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
|
||||||
COME_FROM_LOOP
|
COME_FROM_LOOP
|
||||||
async_for_stmt37 ::= SETUP_LOOP expr
|
async_for_stmt37 ::= setup_loop expr
|
||||||
GET_AITER
|
GET_AITER
|
||||||
SETUP_EXCEPT GET_ANEXT
|
SETUP_EXCEPT GET_ANEXT
|
||||||
LOAD_CONST YIELD_FROM
|
LOAD_CONST YIELD_FROM
|
||||||
@@ -190,7 +217,7 @@ class Python38Parser(Python37Parser):
|
|||||||
POP_TOP POP_BLOCK
|
POP_TOP POP_BLOCK
|
||||||
COME_FROM_LOOP
|
COME_FROM_LOOP
|
||||||
|
|
||||||
async_forelse_stmt ::= SETUP_LOOP expr
|
async_forelse_stmt ::= setup_loop expr
|
||||||
GET_AITER
|
GET_AITER
|
||||||
SETUP_EXCEPT GET_ANEXT LOAD_CONST
|
SETUP_EXCEPT GET_ANEXT LOAD_CONST
|
||||||
YIELD_FROM
|
YIELD_FROM
|
||||||
@@ -203,13 +230,13 @@ class Python38Parser(Python37Parser):
|
|||||||
POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
|
POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP POP_BLOCK
|
||||||
else_suite COME_FROM_LOOP
|
else_suite COME_FROM_LOOP
|
||||||
|
|
||||||
for ::= SETUP_LOOP expr for_iter store for_block POP_BLOCK
|
for ::= setup_loop expr get_for_iter store for_block POP_BLOCK
|
||||||
for ::= SETUP_LOOP expr for_iter store for_block POP_BLOCK NOP
|
for ::= setup_loop expr get_for_iter store for_block POP_BLOCK NOP
|
||||||
|
|
||||||
for_block ::= l_stmts_opt COME_FROM_LOOP JUMP_BACK
|
for_block ::= l_stmts_opt COME_FROM_LOOP JUMP_BACK
|
||||||
forelsestmt ::= SETUP_LOOP expr for_iter store for_block POP_BLOCK else_suite
|
forelsestmt ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suite
|
||||||
forelselaststmt ::= SETUP_LOOP expr for_iter store for_block POP_BLOCK else_suitec
|
forelselaststmt ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suitec
|
||||||
forelselaststmtl ::= SETUP_LOOP expr for_iter store for_block POP_BLOCK else_suitel
|
forelselaststmtl ::= setup_loop expr get_for_iter store for_block POP_BLOCK else_suitel
|
||||||
|
|
||||||
tryelsestmtl3 ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
tryelsestmtl3 ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
|
||||||
except_handler COME_FROM else_suitel
|
except_handler COME_FROM else_suitel
|
||||||
@@ -223,15 +250,16 @@ class Python38Parser(Python37Parser):
|
|||||||
COME_FROM_FINALLY suite_stmts_opt END_FINALLY
|
COME_FROM_FINALLY suite_stmts_opt END_FINALLY
|
||||||
tryfinally_return_stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
|
tryfinally_return_stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
|
||||||
LOAD_CONST COME_FROM_FINALLY
|
LOAD_CONST COME_FROM_FINALLY
|
||||||
|
"""
|
||||||
|
)
|
||||||
""")
|
|
||||||
|
|
||||||
def customize_grammar_rules(self, tokens, customize):
|
def customize_grammar_rules(self, tokens, customize):
|
||||||
super(Python37Parser, self).customize_grammar_rules(tokens, customize)
|
super(Python37Parser, self).customize_grammar_rules(tokens, customize)
|
||||||
self.remove_rules_38()
|
self.remove_rules_38()
|
||||||
self.check_reduce['ifstmt'] = 'tokens'
|
self.check_reduce["ifstmt"] = "tokens"
|
||||||
self.check_reduce['whileTruestmt38'] = 'tokens'
|
self.check_reduce["whileTruestmt38"] = "tokens"
|
||||||
|
self.check_reduce["whilestmt38"] = "tokens"
|
||||||
|
self.check_reduce["ifstmtl"] = "tokens"
|
||||||
|
|
||||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||||
invalid = super(Python38Parser,
|
invalid = super(Python38Parser,
|
||||||
@@ -240,34 +268,47 @@ class Python38Parser(Python37Parser):
|
|||||||
self.remove_rules_38()
|
self.remove_rules_38()
|
||||||
if invalid:
|
if invalid:
|
||||||
return invalid
|
return invalid
|
||||||
if rule[0] == 'ifstmt':
|
lhs = rule[0]
|
||||||
|
if lhs == "ifstmt":
|
||||||
# Make sure jumps don't extend beyond the end of the if statement.
|
# Make sure jumps don't extend beyond the end of the if statement.
|
||||||
l = last
|
l = last
|
||||||
if l == len(tokens):
|
if l == len(tokens):
|
||||||
l -= 1
|
l -= 1
|
||||||
if isinstance(tokens[l].offset, str):
|
if isinstance(tokens[l].offset, str):
|
||||||
last_offset = int(tokens[l].offset.split('_')[0], 10)
|
last_offset = int(tokens[l].offset.split("_")[0], 10)
|
||||||
else:
|
else:
|
||||||
last_offset = tokens[l].offset
|
last_offset = tokens[l].offset
|
||||||
for i in range(first, l):
|
for i in range(first, l):
|
||||||
t = tokens[i]
|
t = tokens[i]
|
||||||
if t.kind == 'POP_JUMP_IF_FALSE':
|
if t.kind == "POP_JUMP_IF_FALSE":
|
||||||
if t.attr > last_offset:
|
if t.attr > last_offset:
|
||||||
return True
|
return True
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
elif rule[0] == 'whileTruestmt38':
|
elif lhs == "ifstmtl":
|
||||||
t = tokens[last-1]
|
if last == len(tokens):
|
||||||
if t.kind == 'JUMP_BACK':
|
last -= 1
|
||||||
return t.attr != tokens[first].offset
|
if (tokens[last].attr and isinstance(tokens[last].attr, int)):
|
||||||
|
return tokens[first].offset < tokens[last].attr
|
||||||
|
pass
|
||||||
|
elif lhs in ("whileTruestmt38", "whilestmt38"):
|
||||||
|
jb_index = last - 1
|
||||||
|
while jb_index > 0 and tokens[jb_index].kind.startswith("COME_FROM"):
|
||||||
|
jb_index -= 1
|
||||||
|
t = tokens[jb_index]
|
||||||
|
if t.kind != "JUMP_BACK":
|
||||||
|
return True
|
||||||
|
return t.attr != tokens[first].off2int()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Python38ParserSingle(Python38Parser, PythonParserSingle):
|
class Python38ParserSingle(Python38Parser, PythonParserSingle):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Check grammar
|
# Check grammar
|
||||||
# FIXME: DRY this with other parseXX.py routines
|
# FIXME: DRY this with other parseXX.py routines
|
||||||
@@ -284,9 +325,11 @@ if __name__ == "__main__":
|
|||||||
opcode_set = set(s.opc.opname).union(
|
opcode_set = set(s.opc.opname).union(
|
||||||
set(
|
set(
|
||||||
"""JUMP_BACK CONTINUE RETURN_END_IF COME_FROM
|
"""JUMP_BACK CONTINUE RETURN_END_IF COME_FROM
|
||||||
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_CLASSNAME
|
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_CLASSNAME
|
||||||
LAMBDA_MARKER RETURN_LAST
|
LAMBDA_MARKER RETURN_LAST
|
||||||
""".split()))
|
""".split()
|
||||||
|
)
|
||||||
|
)
|
||||||
remain_tokens = set(tokens) - opcode_set
|
remain_tokens = set(tokens) - opcode_set
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@@ -22,24 +22,50 @@ This sets up opcodes Python's 3.7 and calls a generalized
|
|||||||
scanner routine for Python 3.
|
scanner routine for Python 3.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from uncompyle6.scanners.scanner36 import Scanner36
|
from uncompyle6.scanners.scanner37base import Scanner37Base
|
||||||
from uncompyle6.scanners.scanner3 import Scanner3
|
|
||||||
|
|
||||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||||
from xdis.opcodes import opcode_37 as opc
|
from xdis.opcodes import opcode_37 as opc
|
||||||
|
|
||||||
|
# bytecode verification, verify(), uses JUMP_OPS from here
|
||||||
JUMP_OPs = opc.JUMP_OPS
|
JUMP_OPs = opc.JUMP_OPS
|
||||||
|
|
||||||
class Scanner37(Scanner36):
|
|
||||||
|
|
||||||
|
class Scanner37(Scanner37Base):
|
||||||
def __init__(self, show_asm=None):
|
def __init__(self, show_asm=None):
|
||||||
Scanner3.__init__(self, 3.7, show_asm)
|
Scanner37Base.__init__(self, 3.7, show_asm)
|
||||||
return
|
return
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||||
|
tokens, customize = Scanner37Base.ingest(self, co, classname, code_objects, show_asm)
|
||||||
|
for t in tokens:
|
||||||
|
# The lowest bit of flags indicates whether the
|
||||||
|
# var-keyword argument is placed at the top of the stack
|
||||||
|
if t.op == self.opc.CALL_FUNCTION_EX and t.attr & 1:
|
||||||
|
t.kind = "CALL_FUNCTION_EX_KW"
|
||||||
|
pass
|
||||||
|
elif t.op == self.opc.BUILD_STRING:
|
||||||
|
t.kind = "BUILD_STRING_%s" % t.attr
|
||||||
|
elif t.op == self.opc.CALL_FUNCTION_KW:
|
||||||
|
t.kind = "CALL_FUNCTION_KW_%s" % t.attr
|
||||||
|
elif t.op == self.opc.FORMAT_VALUE:
|
||||||
|
if t.attr & 0x4:
|
||||||
|
t.kind = "FORMAT_VALUE_ATTR"
|
||||||
|
pass
|
||||||
|
elif t.op == self.opc.BUILD_MAP_UNPACK_WITH_CALL:
|
||||||
|
t.kind = "BUILD_MAP_UNPACK_WITH_CALL_%d" % t.attr
|
||||||
|
elif t.op == self.opc.BUILD_TUPLE_UNPACK_WITH_CALL:
|
||||||
|
t.kind = "BUILD_TUPLE_UNPACK_WITH_CALL_%d" % t.attr
|
||||||
|
pass
|
||||||
|
return tokens, customize
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from uncompyle6 import PYTHON_VERSION
|
from uncompyle6 import PYTHON_VERSION
|
||||||
if PYTHON_VERSION == 3.7:
|
if PYTHON_VERSION == 3.7:
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
co = inspect.currentframe().f_code
|
co = inspect.currentframe().f_code
|
||||||
tokens, customize = Scanner37().ingest(co)
|
tokens, customize = Scanner37().ingest(co)
|
||||||
for t in tokens:
|
for t in tokens:
|
||||||
|
1110
uncompyle6/scanners/scanner37base.py
Normal file
1110
uncompyle6/scanners/scanner37base.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,23 +23,63 @@ scanner routine for Python 3.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from uncompyle6.scanners.scanner37 import Scanner37
|
from uncompyle6.scanners.scanner37 import Scanner37
|
||||||
from uncompyle6.scanners.scanner3 import Scanner3
|
from uncompyle6.scanners.scanner37base import Scanner37Base
|
||||||
|
|
||||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
# bytecode verification, verify(), uses JUMP_OPs from here
|
||||||
from xdis.opcodes import opcode_38 as opc
|
from xdis.opcodes import opcode_38 as opc
|
||||||
|
|
||||||
|
# bytecode verification, verify(), uses JUMP_OPS from here
|
||||||
JUMP_OPs = opc.JUMP_OPS
|
JUMP_OPs = opc.JUMP_OPS
|
||||||
|
|
||||||
class Scanner38(Scanner37):
|
|
||||||
|
|
||||||
|
class Scanner38(Scanner37):
|
||||||
def __init__(self, show_asm=None):
|
def __init__(self, show_asm=None):
|
||||||
Scanner3.__init__(self, 3.8, show_asm)
|
Scanner37Base.__init__(self, 3.8, show_asm)
|
||||||
return
|
return
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def ingest(self, co, classname=None, code_objects={}, show_asm=None):
|
||||||
|
tokens, customize = super(Scanner38, self).ingest(
|
||||||
|
co, classname, code_objects, show_asm
|
||||||
|
)
|
||||||
|
for i, token in enumerate(tokens):
|
||||||
|
opname = token.kind
|
||||||
|
if opname in ("JUMP_FORWARD", "JUMP_ABSOLUTE"):
|
||||||
|
# Turn JUMPs into BREAK_LOOP
|
||||||
|
jump_target = token.attr
|
||||||
|
|
||||||
|
if opname == "JUMP_ABSOLUTE" and token.offset >= jump_target:
|
||||||
|
# Not a forward jump, so continue
|
||||||
|
# FIXME: Do we need "continue" detection?
|
||||||
|
continue
|
||||||
|
if i + 1 < len(tokens) and tokens[i + 1] == "JUMP_BACK":
|
||||||
|
# Sometimes the jump back is *after* the break...
|
||||||
|
jump_back_index = i + 1
|
||||||
|
else:
|
||||||
|
# and sometimes it is *before* where we jumped to.
|
||||||
|
jump_back_index = self.offset2tok_index[jump_target] - 1
|
||||||
|
while tokens[jump_back_index].kind.startswith("COME_FROM_"):
|
||||||
|
jump_back_index -= 1
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
jump_back_token = tokens[jump_back_index]
|
||||||
|
if (
|
||||||
|
jump_back_token == "JUMP_BACK"
|
||||||
|
and jump_back_token.attr < token.offset
|
||||||
|
):
|
||||||
|
token.kind = "BREAK_LOOP"
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
return tokens, customize
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from uncompyle6 import PYTHON_VERSION
|
from decompyle3 import PYTHON_VERSION
|
||||||
|
|
||||||
if PYTHON_VERSION == 3.8:
|
if PYTHON_VERSION == 3.8:
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
co = inspect.currentframe().f_code
|
co = inspect.currentframe().f_code
|
||||||
tokens, customize = Scanner38().ingest(co)
|
tokens, customize = Scanner38().ingest(co)
|
||||||
for t in tokens:
|
for t in tokens:
|
||||||
|
@@ -159,5 +159,12 @@ class Token:
|
|||||||
def __getitem__(self, i):
|
def __getitem__(self, i):
|
||||||
raise IndexError
|
raise IndexError
|
||||||
|
|
||||||
|
def off2int(self):
|
||||||
|
if isinstance(self.offset, int):
|
||||||
|
return self.offset
|
||||||
|
else:
|
||||||
|
assert isinstance(self.offset, str)
|
||||||
|
return(int(self.offset.split("_")[0]))
|
||||||
|
|
||||||
|
|
||||||
NoneToken = Token("LOAD_CONST", offset=-1, attr=None, pattr=None)
|
NoneToken = Token("LOAD_CONST", offset=-1, attr=None, pattr=None)
|
||||||
|
@@ -344,8 +344,12 @@ TABLE_DIRECT = {
|
|||||||
# 'return': ( '%|return %c\n', 0),
|
# 'return': ( '%|return %c\n', 0),
|
||||||
'return_if_stmt': ( 'return %c\n', 0),
|
'return_if_stmt': ( 'return %c\n', 0),
|
||||||
|
|
||||||
'ifstmt': ( '%|if %c:\n%+%c%-', 0, 1 ),
|
'ifstmt': ( '%|if %c:\n%+%c%-',
|
||||||
'iflaststmt': ( '%|if %c:\n%+%c%-', 0, 1 ),
|
0, # "testexpr" or "testexpr_then"
|
||||||
|
1, # "_ifstmts_jump" or "return_stmts"
|
||||||
|
),
|
||||||
|
|
||||||
|
'iflaststmt': ( '%|if %c:\n%+%c%-', 0, 1 ),
|
||||||
'iflaststmtl': ( '%|if %c:\n%+%c%-', 0, 1 ),
|
'iflaststmtl': ( '%|if %c:\n%+%c%-', 0, 1 ),
|
||||||
'testtrue': ( 'not %p',
|
'testtrue': ( 'not %p',
|
||||||
(0, PRECEDENCE['unary_not']) ),
|
(0, PRECEDENCE['unary_not']) ),
|
||||||
@@ -359,18 +363,18 @@ TABLE_DIRECT = {
|
|||||||
'ifelsestmt': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
'ifelsestmt': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
||||||
'ifelsestmtc': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
'ifelsestmtc': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
||||||
'ifelsestmtl': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
'ifelsestmtl': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
||||||
'ifelsestmtr': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 2 ),
|
|
||||||
'ifelsestmtr2': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-\n\n', 0, 1, 3 ), # has COME_FROM in position 2
|
|
||||||
|
|
||||||
|
# These are created only via transformation
|
||||||
# "elif" forms are not generated by the parser but are created through tree
|
'ifelifstmt': ( '%|if %c:\n%+%c%-%c',
|
||||||
# transformations. See "n_ifelsestmt".
|
0, # "testexpr" or "testexpr_then"
|
||||||
'ifelifstmt': ( '%|if %c:\n%+%c%-%c', 0, 1, 3 ),
|
1, 3 ),
|
||||||
'elifelifstmt': ( '%|elif %c:\n%+%c%-%c', 0, 1, 3 ),
|
'elifelifstmt': ( '%|elif %c:\n%+%c%-%c', 0, 1, 3 ),
|
||||||
'elifstmt': ( '%|elif %c:\n%+%c%-', 0, 1 ),
|
'elifstmt': ( '%|elif %c:\n%+%c%-', 0, 1 ),
|
||||||
'elifelsestmt': ( '%|elif %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
'elifelsestmt': ( '%|elif %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 3 ),
|
||||||
|
'ifelsestmtr': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-', 0, 1, 2 ),
|
||||||
|
'ifelsestmtr2': ( '%|if %c:\n%+%c%-%|else:\n%+%c%-\n\n', 0, 1, 3 ), # has COME_FROM
|
||||||
'elifelsestmtr': ( '%|elif %c:\n%+%c%-%|else:\n%+%c%-\n\n', 0, 1, 2 ),
|
'elifelsestmtr': ( '%|elif %c:\n%+%c%-%|else:\n%+%c%-\n\n', 0, 1, 2 ),
|
||||||
'elifelsestmtr2': ( '%|elif %c:\n%+%c%-%|else:\n%+%c%-\n\n', 0, 1, 3 ), # has COME_FROM in position 2
|
'elifelsestmtr2': ( '%|elif %c:\n%+%c%-%|else:\n%+%c%-\n\n', 0, 1, 3 ), # has COME_FROM
|
||||||
|
|
||||||
'whileTruestmt': ( '%|while True:\n%+%c%-\n\n', 1 ),
|
'whileTruestmt': ( '%|while True:\n%+%c%-\n\n', 1 ),
|
||||||
'whilestmt': ( '%|while %c:\n%+%c%-\n\n', 1, 2 ),
|
'whilestmt': ( '%|while %c:\n%+%c%-\n\n', 1, 2 ),
|
||||||
@@ -414,10 +418,11 @@ TABLE_DIRECT = {
|
|||||||
(1, 'expr'), (5, 'store') ),
|
(1, 'expr'), (5, 'store') ),
|
||||||
'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ),
|
'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ),
|
||||||
|
|
||||||
# In Python 3.6, this is more complicated in the presence of "returns"
|
# In Python 3.6+, this is more complicated in the presence of "returns"
|
||||||
'except_suite_finalize': ( '%+%c%-%C', 1, (3, maxint, '') ),
|
'except_suite_finalize': ( '%+%c%-%C', 1, (3, maxint, '') ),
|
||||||
|
|
||||||
'pass': ( '%|pass\n', ),
|
'pass': ( '%|pass\n', ),
|
||||||
|
'STORE_FAST': ( '%{pattr}', ),
|
||||||
'kv': ( '%c: %c', 3, 1 ),
|
'kv': ( '%c: %c', 3, 1 ),
|
||||||
'kv2': ( '%c: %c', 1, 2 ),
|
'kv2': ( '%c: %c', 1, 2 ),
|
||||||
'import': ( '%|import %c\n', 2),
|
'import': ( '%|import %c\n', 2),
|
||||||
|
@@ -37,6 +37,7 @@ def customize_for_version3(self, version):
|
|||||||
(0, "expr"),
|
(0, "expr"),
|
||||||
(4, "expr"),
|
(4, "expr"),
|
||||||
),
|
),
|
||||||
|
"except_cond2": ("%|except %c as %c:\n", (1, "expr"), (5, "store")),
|
||||||
"function_def_annotate": ("\n\n%|def %c%c\n", -1, 0),
|
"function_def_annotate": ("\n\n%|def %c%c\n", -1, 0),
|
||||||
# When a generator is a single parameter of a function,
|
# When a generator is a single parameter of a function,
|
||||||
# it doesn't need the surrounding parenethesis.
|
# it doesn't need the surrounding parenethesis.
|
||||||
@@ -331,7 +332,8 @@ def customize_for_version3(self, version):
|
|||||||
(1, "suite_stmts_opt"),
|
(1, "suite_stmts_opt"),
|
||||||
(3, "except_handler"),
|
(3, "except_handler"),
|
||||||
(5, "else_suitel"),
|
(5, "else_suitel"),
|
||||||
)
|
),
|
||||||
|
"LOAD_CLASSDEREF": ("%{pattr}",),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if version >= 3.4:
|
if version >= 3.4:
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""Isolate Python 3.6 version-specific semantic actions here.
|
"""Isolate Python 3.8 version-specific semantic actions here.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
########################
|
########################
|
||||||
@@ -80,10 +80,18 @@ def customize_for_version38(self, version):
|
|||||||
(0, 'expr'),
|
(0, 'expr'),
|
||||||
(3, 'for_block'), -2 ),
|
(3, 'for_block'), -2 ),
|
||||||
|
|
||||||
|
'ifpoplaststmtl': ( '%|if %c:\n%+%c%-',
|
||||||
|
(0, "testexpr"),
|
||||||
|
(2, "c_stmts" ) ),
|
||||||
|
|
||||||
|
'ifstmtl': ( '%|if %c:\n%+%c%-',
|
||||||
|
(0, "testexpr"),
|
||||||
|
(1, "_ifstmts_jumpl") ),
|
||||||
|
|
||||||
'whilestmt38': ( '%|while %c:\n%+%c%-\n\n',
|
'whilestmt38': ( '%|while %c:\n%+%c%-\n\n',
|
||||||
(0, 'testexpr'), (1, 'l_stmts') ),
|
(1, 'testexpr'), (2, 'l_stmts') ),
|
||||||
'whileTruestmt38': ( '%|while True:\n%+%c%-\n\n',
|
'whileTruestmt38': ( '%|while True:\n%+%c%-\n\n',
|
||||||
(0, 'l_stmts') ),
|
(1, 'l_stmts') ),
|
||||||
'try_elsestmtl38': (
|
'try_elsestmtl38': (
|
||||||
'%|try:\n%+%c%-%c%|else:\n%+%c%-',
|
'%|try:\n%+%c%-%c%|else:\n%+%c%-',
|
||||||
(1, 'suite_stmts_opt'),
|
(1, 'suite_stmts_opt'),
|
||||||
@@ -98,4 +106,7 @@ def customize_for_version38(self, version):
|
|||||||
'tryfinally38': (
|
'tryfinally38': (
|
||||||
'%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
|
'%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
|
||||||
(3, 'returns'), 6 ),
|
(3, 'returns'), 6 ),
|
||||||
|
"named_expr": ( # AKA "walrus operatotr"
|
||||||
|
"%c := %c", (2, "store"), (0, "expr")
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
@@ -1130,11 +1130,15 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
def n_generator_exp(self, node):
|
def n_generator_exp(self, node):
|
||||||
self.write("(")
|
self.write("(")
|
||||||
|
iter_index = 3
|
||||||
if self.version > 3.2:
|
if self.version > 3.2:
|
||||||
code_index = -6
|
code_index = -6
|
||||||
|
if self.version > 3.6:
|
||||||
|
# Python 3.7+ adds optional "come_froms" at node[0]
|
||||||
|
iter_index = 4
|
||||||
else:
|
else:
|
||||||
code_index = -5
|
code_index = -5
|
||||||
self.comprehension_walk(node, iter_index=3, code_index=code_index)
|
self.comprehension_walk(node, iter_index=iter_index, code_index=code_index)
|
||||||
self.write(")")
|
self.write(")")
|
||||||
self.prune()
|
self.prune()
|
||||||
|
|
||||||
@@ -2015,8 +2019,13 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
self.default(node)
|
self.default(node)
|
||||||
|
|
||||||
def n_except_cond2(self, node):
|
def n_except_cond2(self, node):
|
||||||
if node[-2][0] == "unpack":
|
if node[-1] == "come_from_opt":
|
||||||
node[-2][0].kind = "unpack_w_parens"
|
unpack_node = -3
|
||||||
|
else:
|
||||||
|
unpack_node = -2
|
||||||
|
|
||||||
|
if node[unpack_node][0] == "unpack":
|
||||||
|
node[unpack_node][0].kind = "unpack_w_parens"
|
||||||
self.default(node)
|
self.default(node)
|
||||||
|
|
||||||
def template_engine(self, entry, startnode):
|
def template_engine(self, entry, startnode):
|
||||||
|
@@ -181,6 +181,7 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
|
|
||||||
n = else_suite[0]
|
n = else_suite[0]
|
||||||
old_stmts = None
|
old_stmts = None
|
||||||
|
else_suite_index = 1
|
||||||
|
|
||||||
if len(n) == 1 == len(n[0]) and n[0] == "stmt":
|
if len(n) == 1 == len(n[0]) and n[0] == "stmt":
|
||||||
n = n[0][0]
|
n = n[0][0]
|
||||||
@@ -192,9 +193,12 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
"iflaststmtl",
|
"iflaststmtl",
|
||||||
"ifelsestmtl",
|
"ifelsestmtl",
|
||||||
"ifelsestmtc",
|
"ifelsestmtc",
|
||||||
|
"ifpoplaststmtl",
|
||||||
):
|
):
|
||||||
# This seems needed for Python 2.5-2.7
|
|
||||||
n = n[0]
|
n = n[0]
|
||||||
|
if n.kind == "ifpoplaststmtl":
|
||||||
|
old_stmts = n[2]
|
||||||
|
else_suite_index = 2
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
elif len(n) > 1 and 1 == len(n[0]) and n[0] == "stmt" and n[1].kind == "stmt":
|
elif len(n) > 1 and 1 == len(n[0]) and n[0] == "stmt" and n[1].kind == "stmt":
|
||||||
@@ -206,7 +210,7 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
else:
|
else:
|
||||||
return node
|
return node
|
||||||
|
|
||||||
if n.kind in ("ifstmt", "iflaststmt", "iflaststmtl"):
|
if n.kind in ("ifstmt", "iflaststmt", "iflaststmtl", "ifpoplaststmtl"):
|
||||||
node.kind = "ifelifstmt"
|
node.kind = "ifelifstmt"
|
||||||
n.kind = "elifstmt"
|
n.kind = "elifstmt"
|
||||||
elif n.kind in ("ifelsestmtr",):
|
elif n.kind in ("ifelsestmtr",):
|
||||||
@@ -223,17 +227,24 @@ class TreeTransform(GenericASTTraversal, object):
|
|||||||
if old_stmts:
|
if old_stmts:
|
||||||
if n.kind == "elifstmt":
|
if n.kind == "elifstmt":
|
||||||
trailing_else = SyntaxTree("stmts", old_stmts[1:])
|
trailing_else = SyntaxTree("stmts", old_stmts[1:])
|
||||||
# We use elifelsestmtr because it has 3 nodes
|
if len(trailing_else):
|
||||||
elifelse_stmt = SyntaxTree(
|
# We use elifelsestmtr because it has 3 nodes
|
||||||
"elifelsestmtr", [n[0], n[1], trailing_else]
|
elifelse_stmt = SyntaxTree(
|
||||||
)
|
"elifelsestmtr", [n[0], n[else_suite_index], trailing_else]
|
||||||
node[3] = elifelse_stmt
|
)
|
||||||
|
node[3] = elifelse_stmt
|
||||||
|
else:
|
||||||
|
elif_stmt = SyntaxTree(
|
||||||
|
"elifstmt", [n[0], n[else_suite_index]]
|
||||||
|
)
|
||||||
|
node[3] = elif_stmt
|
||||||
|
|
||||||
|
node.transformed_by = "n_ifelsestmt"
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# Other cases for n.kind may happen here
|
# Other cases for n.kind may happen here
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
node.transformed_by = "n_ifelsestmt"
|
|
||||||
return node
|
return node
|
||||||
|
|
||||||
n_ifelsestmtc = n_ifelsestmtl = n_ifelsestmt
|
n_ifelsestmtc = n_ifelsestmtl = n_ifelsestmt
|
||||||
|
Reference in New Issue
Block a user