Merge branch 'python-3.3-to-3.5' into python-2.4

This commit is contained in:
rocky
2022-01-03 22:10:47 -05:00
20 changed files with 92 additions and 92 deletions

View File

@@ -5,7 +5,7 @@
# fully handle Python 3.5's jump optimization
# So in 3.5, for now, we allow:
#
# return_stmt ::= ret_expr RETURN_END_IF
# return_stmt ::= return_expr RETURN_END_IF
# and you see that in the grammar rules for below.
# For other pythons the RETURN_END_IF may be a

View File

@@ -1,9 +1,9 @@
# Tests:
# ret_expr_or_cond ::= ret_expr
# if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF ret_expr_or_cond
# ret_expr_or_cond ::= if_exp_ret
# ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
# return_expr_or_cond ::= return_expr
# if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF return_expr_or_cond
# return_expr_or_cond ::= if_exp_ret
# ret_or ::= expr JUMP_IF_TRUE_OR_POP return_expr_or_cond COME_FROM
# See https://github.com/rocky/python-uncompyle6/issues/5

View File

@@ -1,22 +1,22 @@
# 2.6.9 asynchat.py
# 2.6 added:
# return_stmt ::= ret_expr RETURN_END_IF come_from_pop
def initiate_send(self):
# return_stmt ::= return_expr RETURN_END_IF come_from_pop
def initiate_send(self, x):
while self:
if self:
x = 'a'
else:
del self.producer_fifo[0]
return
return x
# 2.6.9 contextlib.py
# Bug was in return exc, so added:
# return_stmt ::= ret_expr RETURN_VALUE_IF come_from_pop
# return_stmt ::= return_expr RETURN_VALUE_IF come_from_pop
def __exit__(self, type, value, traceback):
try:
raise RuntimeError
except StopIteration:
return exc
return value
except:
raise

View File

@@ -1,6 +1,6 @@
# from 2.6.9 Bastion.py
# Should see in 2.6.9:
# return_if_stmt ::= ret_expr RETURN_END_IF come_from_pop
# return_if_stmt ::= return_expr RETURN_END_IF come_from_pop
def Bastion(object, filter = lambda name: name[:1] != '_'):
def get1(name, attribute, MethodType, object=object, filter=filter):

View File

@@ -359,7 +359,7 @@ class PythonParser(GenericASTBuilder):
stmt ::= return
return ::= ret_expr RETURN_VALUE
return ::= return_expr RETURN_VALUE
# "returns" nonterminal is a sequence of statements that ends in a RETURN statement.
# In later Python versions with jump optimization, this can cause JUMPs
@@ -570,17 +570,17 @@ class PythonParser(GenericASTBuilder):
expr ::= if_exp
ret_expr ::= expr
ret_expr ::= ret_and
ret_expr ::= ret_or
return_expr ::= expr
return_expr ::= ret_and
return_expr ::= ret_or
ret_expr_or_cond ::= ret_expr
ret_expr_or_cond ::= if_exp_ret
return_expr_or_cond ::= return_expr
return_expr_or_cond ::= if_exp_ret
stmt ::= return_expr_lambda
return_expr_lambda ::= ret_expr RETURN_VALUE_LAMBDA LAMBDA_MARKER
return_expr_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_expr_lambda ::= return_expr RETURN_VALUE_LAMBDA LAMBDA_MARKER
return_expr_lambda ::= return_expr RETURN_VALUE_LAMBDA
compare ::= compare_chained
compare ::= compare_single

View File

@@ -70,9 +70,9 @@ class Python2Parser(PythonParser):
return_if_stmts ::= return_if_stmt
return_if_stmts ::= _stmts return_if_stmt
return_if_stmt ::= ret_expr RETURN_END_IF
return_if_stmt ::= return_expr RETURN_END_IF
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_stmt_lambda ::= return_expr RETURN_VALUE_LAMBDA
stmt ::= break
break ::= BREAK_LOOP

View File

@@ -18,7 +18,7 @@ class Python25Parser(Python26Parser):
# If "return_if_stmt" is in a loop, a JUMP_BACK can be emitted. In 2.6 the
# JUMP_BACK doesn't appear
return_if_stmt ::= ret_expr RETURN_END_IF JUMP_BACK
return_if_stmt ::= return_expr RETURN_END_IF JUMP_BACK
# We have no jumps to jumps, so no "come_froms" but a single "COME_FROM"
ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite COME_FROM
@@ -80,13 +80,13 @@ class Python25Parser(Python26Parser):
classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1
classdefdeco2 ::= LOAD_CONST expr mkfunc CALL_FUNCTION_0 BUILD_CLASS
kv3 ::= expr expr STORE_MAP
if_exp_ret ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond
if_exp_ret ::= expr jmp_false_then expr RETURN_END_IF POP_TOP return_expr_or_cond
return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP
return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP
return_if_stmt ::= return_expr RETURN_END_IF POP_TOP
return_if_stmts ::= return_if_stmt
return ::= ret_expr RETURN_END_IF POP_TOP
return ::= ret_expr RETURN_VALUE POP_TOP
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return ::= return_expr RETURN_END_IF POP_TOP
return ::= return_expr RETURN_VALUE POP_TOP
return_stmt_lambda ::= return_expr RETURN_VALUE_LAMBDA
setupwithas ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 setup_finally
stmt ::= classdefdeco
stmt ::= if_exp_lambda

View File

@@ -161,9 +161,9 @@ class Python26Parser(Python2Parser):
else_suitel COME_FROM
while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK else_suitel COME_FROM
return ::= ret_expr RETURN_END_IF POP_TOP
return ::= ret_expr RETURN_VALUE POP_TOP
return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP
return ::= return_expr RETURN_END_IF POP_TOP
return ::= return_expr RETURN_VALUE POP_TOP
return_if_stmt ::= return_expr RETURN_END_IF POP_TOP
iflaststmtl ::= testexpr c_stmts_opt jb_cf_pop
iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE come_from_pop
@@ -269,16 +269,16 @@ class Python26Parser(Python2Parser):
def p_ret26(self, args):
'''
ret_and ::= expr jmp_false ret_expr_or_cond COME_FROM
ret_or ::= expr jmp_true ret_expr_or_cond COME_FROM
if_exp_ret ::= expr jmp_false_then expr RETURN_END_IF POP_TOP ret_expr_or_cond
if_exp_ret ::= expr jmp_false_then expr ret_expr_or_cond
ret_and ::= expr jmp_false return_expr_or_cond COME_FROM
ret_or ::= expr jmp_true return_expr_or_cond COME_FROM
if_exp_ret ::= expr jmp_false_then expr RETURN_END_IF POP_TOP return_expr_or_cond
if_exp_ret ::= expr jmp_false_then expr return_expr_or_cond
return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP
return ::= ret_expr RETURN_VALUE POP_TOP
return_if_stmt ::= return_expr RETURN_END_IF POP_TOP
return ::= return_expr RETURN_VALUE POP_TOP
# FIXME: split into Python 2.5
ret_or ::= expr jmp_true ret_expr_or_cond come_froms
ret_or ::= expr jmp_true return_expr_or_cond come_froms
'''
def p_except26(self, args):

View File

@@ -99,9 +99,9 @@ class Python27Parser(Python2Parser):
jmp_false ::= POP_JUMP_IF_FALSE
jmp_true ::= POP_JUMP_IF_TRUE
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM ret_expr_or_cond
ret_and ::= expr JUMP_IF_FALSE_OR_POP return_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP return_expr_or_cond COME_FROM
if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM return_expr_or_cond
expr_jitop ::= expr JUMP_IF_TRUE_OR_POP
or ::= expr_jitop expr COME_FROM
@@ -223,7 +223,7 @@ class Python27Parser(Python2Parser):
if 'PyPy' in customize:
# PyPy-specific customizations
self.addRule("""
return_if_stmt ::= ret_expr RETURN_END_IF come_froms
return_if_stmt ::= return_expr RETURN_END_IF come_froms
""", nop_func)

View File

@@ -110,7 +110,7 @@ class Python3Parser(PythonParser):
return_if_stmts ::= return_if_stmt come_from_opt
return_if_stmts ::= _stmts return_if_stmt _come_froms
return_if_stmt ::= ret_expr RETURN_END_IF
return_if_stmt ::= return_expr RETURN_END_IF
returns ::= _stmts return_if_stmt
stmt ::= break
@@ -340,9 +340,9 @@ class Python3Parser(PythonParser):
jmp_true ::= POP_JUMP_IF_TRUE
# FIXME: Common with 2.7
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM ret_expr_or_cond
ret_and ::= expr JUMP_IF_FALSE_OR_POP return_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP return_expr_or_cond COME_FROM
if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM return_expr_or_cond
# compare_chained1 is used exclusively in chained_compare
@@ -362,7 +362,7 @@ class Python3Parser(PythonParser):
if_exp_not_lambda ::= expr jmp_true expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_stmt_lambda ::= return_expr RETURN_VALUE_LAMBDA
return_if_lambda ::= RETURN_END_IF_LAMBDA
stmt ::= return_closure
@@ -1454,7 +1454,7 @@ class Python3Parser(PythonParser):
elif opname == "RETURN_VALUE_LAMBDA":
self.addRule(
"""
return_expr_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_expr_lambda ::= return_expr RETURN_VALUE_LAMBDA
""",
nop_func,
)

View File

@@ -179,8 +179,8 @@ class Python30Parser(Python31Parser):
except_handler ::= jmp_abs COME_FROM_EXCEPT except_stmts
POP_TOP END_FINALLY
return_if_stmt ::= ret_expr RETURN_END_IF come_froms POP_TOP
return_if_stmt ::= ret_expr RETURN_VALUE come_froms POP_TOP
return_if_stmt ::= return_expr RETURN_END_IF come_froms POP_TOP
return_if_stmt ::= return_expr RETURN_VALUE come_froms POP_TOP
and ::= expr jmp_false_then expr come_from_opt
@@ -261,11 +261,11 @@ class Python30Parser(Python31Parser):
compare_chained1 COME_FROM
compare_chained1 ::= expr DUP_TOP ROT_THREE COMPARE_OP JUMP_IF_FALSE_OR_POP
compare_chained2 COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP return_expr_or_cond COME_FROM
ret_and ::= expr JUMP_IF_FALSE_OR_POP return_expr_or_cond COME_FROM
if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF
COME_FROM ret_expr_or_cond
ret_expr_or_cond ::= if_exp_ret
COME_FROM return_expr_or_cond
return_expr_or_cond ::= if_exp_ret
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
and ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM

View File

@@ -105,7 +105,7 @@ class Python35Parser(Python34Parser):
# Python 3.5+ does jump optimization
# In <.3.5 the below is a JUMP_FORWARD to a JUMP_ABSOLUTE.
return_if_stmt ::= ret_expr RETURN_END_IF POP_BLOCK
return_if_stmt ::= return_expr RETURN_END_IF POP_BLOCK
return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
jb_else ::= JUMP_BACK ELSE

View File

@@ -53,9 +53,9 @@ class Python36Parser(Python35Parser):
# 3.6 due to jump optimization, we sometimes add RETURN_END_IF where
# RETURN_VALUE is meant. Specifcally this can happen in
# ifelsestmt -> ...else_suite _. suite_stmts... (last) stmt
return ::= ret_expr RETURN_END_IF
return ::= ret_expr RETURN_VALUE COME_FROM
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA COME_FROM
return ::= return_expr RETURN_END_IF
return ::= return_expr RETURN_VALUE COME_FROM
return_stmt_lambda ::= return_expr RETURN_VALUE_LAMBDA COME_FROM
# A COME_FROM is dropped off because of JUMP-to-JUMP optimization
and ::= expr jmp_false expr

View File

@@ -119,7 +119,7 @@ class Python37Parser(Python37BaseParser):
delete ::= DELETE_GLOBAL
stmt ::= return
return ::= ret_expr RETURN_VALUE
return ::= return_expr RETURN_VALUE
# "returns" nonterminal is a sequence of statements that ends in a RETURN statement.
# In later Python versions with jump optimization, this can cause JUMPs
@@ -191,17 +191,17 @@ class Python37Parser(Python37BaseParser):
expr ::= if_exp
ret_expr ::= expr
ret_expr ::= ret_and
ret_expr ::= ret_or
return_expr ::= expr
return_expr ::= ret_and
return_expr ::= ret_or
ret_expr_or_cond ::= ret_expr
ret_expr_or_cond ::= if_exp_ret
return_expr_or_cond ::= return_expr
return_expr_or_cond ::= if_exp_ret
stmt ::= return_expr_lambda
return_expr_lambda ::= ret_expr RETURN_VALUE_LAMBDA LAMBDA_MARKER
return_expr_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_expr_lambda ::= return_expr RETURN_VALUE_LAMBDA LAMBDA_MARKER
return_expr_lambda ::= return_expr RETURN_VALUE_LAMBDA
compare ::= compare_chained
compare ::= compare_single
@@ -512,7 +512,7 @@ class Python37Parser(Python37BaseParser):
# Python 3.5+ does jump optimization
# In <.3.5 the below is a JUMP_FORWARD to a JUMP_ABSOLUTE.
return_if_stmt ::= ret_expr RETURN_END_IF POP_BLOCK
return_if_stmt ::= return_expr RETURN_END_IF POP_BLOCK
return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
jb_else ::= JUMP_BACK ELSE
@@ -753,7 +753,7 @@ class Python37Parser(Python37BaseParser):
return_if_stmts ::= return_if_stmt come_from_opt
return_if_stmts ::= _stmts return_if_stmt _come_froms
return_if_stmt ::= ret_expr RETURN_END_IF
return_if_stmt ::= return_expr RETURN_END_IF
returns ::= _stmts return_if_stmt
stmt ::= break
@@ -933,9 +933,9 @@ class Python37Parser(Python37BaseParser):
jmp_true ::= POP_JUMP_IF_TRUE
# FIXME: Common with 2.7
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM ret_expr_or_cond
ret_and ::= expr JUMP_IF_FALSE_OR_POP return_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP return_expr_or_cond COME_FROM
if_exp_ret ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM return_expr_or_cond
jitop_come_from_expr ::= JUMP_IF_TRUE_OR_POP come_froms expr
jifop_come_from ::= JUMP_IF_FALSE_OR_POP come_froms
@@ -993,7 +993,7 @@ class Python37Parser(Python37BaseParser):
::= expr jmp_true expr return_if_lambda
return_stmt_lambda LAMBDA_MARKER
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_stmt_lambda ::= return_expr RETURN_VALUE_LAMBDA
return_if_lambda ::= RETURN_END_IF_LAMBDA
stmt ::= return_closure
@@ -1096,9 +1096,9 @@ class Python37Parser(Python37BaseParser):
# 3.6 due to jump optimization, we sometimes add RETURN_END_IF where
# RETURN_VALUE is meant. Specifcally this can happen in
# ifelsestmt -> ...else_suite _. suite_stmts... (last) stmt
return ::= ret_expr RETURN_END_IF
return ::= ret_expr RETURN_VALUE COME_FROM
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA COME_FROM
return ::= return_expr RETURN_END_IF
return ::= return_expr RETURN_VALUE COME_FROM
return_stmt_lambda ::= return_expr RETURN_VALUE_LAMBDA COME_FROM
# A COME_FROM is dropped off because of JUMP-to-JUMP optimization
and ::= expr jmp_false expr

View File

@@ -952,7 +952,7 @@ class Python37BaseParser(PythonParser):
elif opname == "RETURN_VALUE_LAMBDA":
self.addRule(
"""
return_expr_lambda ::= ret_expr RETURN_VALUE_LAMBDA
return_expr_lambda ::= return_expr RETURN_VALUE_LAMBDA
""",
nop_func,
)

View File

@@ -92,16 +92,16 @@ class Python38Parser(Python37Parser):
discard_top ::= ROT_TWO POP_TOP
discard_tops ::= discard_top+
return ::= ret_expr
return ::= return_expr
discard_tops RETURN_VALUE
return ::= popb_return
return ::= pop_return
return ::= pop_ex_return
except_stmt ::= pop_ex_return
pop_return ::= POP_TOP ret_expr RETURN_VALUE
popb_return ::= ret_expr POP_BLOCK RETURN_VALUE
pop_ex_return ::= ret_expr ROT_FOUR POP_EXCEPT RETURN_VALUE
pop_return ::= POP_TOP return_expr RETURN_VALUE
popb_return ::= return_expr POP_BLOCK RETURN_VALUE
pop_ex_return ::= return_expr ROT_FOUR POP_EXCEPT RETURN_VALUE
# 3.8 can push a looping JUMP_BACK into into a JUMP_ from a statement that jumps to it
lastl_stmt ::= ifpoplaststmtl

View File

@@ -122,7 +122,7 @@ LINE_LENGTH = 80
RETURN_LOCALS = SyntaxTree(
"return",
[
SyntaxTree("ret_expr", [SyntaxTree("expr", [Token("LOAD_LOCALS")])]),
SyntaxTree("return_expr", [SyntaxTree("expr", [Token("LOAD_LOCALS")])]),
Token("RETURN_VALUE"),
],
)

View File

@@ -96,7 +96,7 @@ def customize_for_version3(self, version):
ast = self.build_ast(code._tokens, code._customize, code)
self.customize(code._customize)
# skip over: sstmt, stmt, return, ret_expr
# skip over: sstmt, stmt, return, return_expr
# and other singleton derivations
while len(ast) == 1 or (
ast in ("sstmt", "return") and ast[-1] in ("RETURN_LAST", "RETURN_VALUE")

View File

@@ -329,7 +329,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
start = len(self.f.getvalue()) + len(self.indent)
self.write(self.indent, "return")
if self.return_none or node != SyntaxTree(
"return", [SyntaxTree("ret_expr", [NONE]), Token("RETURN_VALUE")]
"return", [SyntaxTree("return_expr", [NONE]), Token("RETURN_VALUE")]
):
self.write(" ")
self.last_finish = len(self.f.getvalue())
@@ -357,7 +357,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
start = len(self.f.getvalue()) + len(self.indent)
self.write(self.indent, "return")
if self.return_none or node != SyntaxTree(
"return", [SyntaxTree("ret_expr", [NONE]), Token("RETURN_END_IF")]
"return", [SyntaxTree("return_expr", [NONE]), Token("RETURN_END_IF")]
):
self.write(" ")
self.preorder(node[0])
@@ -440,9 +440,9 @@ class FragmentsWalker(pysource.SourceWalker, object):
self.set_pos_info(node, start, len(self.f.getvalue()))
self.prune()
def n_ret_expr(self, node):
def n_return_expr(self, node):
start = len(self.f.getvalue())
super(FragmentsWalker, self).n_ret_expr(node)
super(FragmentsWalker, self).n_return_expr(node)
self.set_pos_info(node, start, len(self.f.getvalue()))
def n_bin_op(self, node):
@@ -759,7 +759,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
if ast[0] == "sstmt":
ast = ast[0]
# skip over stmt return ret_expr
# skip over stmt return return_expr
ast = ast[0][0][0]
store = None
if ast in ["set_comp_func", "dict_comp_func"]:

View File

@@ -473,7 +473,7 @@ class SourceWalker(GenericASTTraversal, object):
def is_return_none(self, node):
# Is there a better way?
ret = (
node[0] == "ret_expr"
node[0] == "return_expr"
and node[0][0] == "expr"
and node[0][0][0] == "LOAD_CONST"
and node[0][0][0].pattr is None
@@ -484,7 +484,7 @@ class SourceWalker(GenericASTTraversal, object):
# FIXME: should the SyntaxTree expression be folded into
# the global RETURN_NONE constant?
return ret or node == SyntaxTree(
"return", [SyntaxTree("ret_expr", [NONE]), Token("RETURN_VALUE")]
"return", [SyntaxTree("return_expr", [NONE]), Token("RETURN_VALUE")]
)
# Python 3.x can have be dead code as a result of its optimization?
@@ -596,7 +596,7 @@ class SourceWalker(GenericASTTraversal, object):
self.prec = p
self.prune()
def n_ret_expr(self, node):
def n_return_expr(self, node):
if len(node) == 1 and node[0] == "expr":
# If expr is yield we want parens.
self.prec = PRECEDENCE["yield"] - 1
@@ -604,7 +604,7 @@ class SourceWalker(GenericASTTraversal, object):
else:
self.n_expr(node)
n_ret_expr_or_cond = n_expr
n_return_expr_or_cond = n_expr
def n_bin_op(self, node):
"""bin_op (formerly "binary_expr") is the Python AST BinOp"""
@@ -1191,7 +1191,7 @@ class SourceWalker(GenericASTTraversal, object):
ast = self.build_ast(code._tokens, code._customize, code)
self.customize(code._customize)
# skip over: sstmt, stmt, return, ret_expr
# skip over: sstmt, stmt, return, return_expr
# and other singleton derivations
while len(ast) == 1 or (
ast in ("sstmt", "return") and ast[-1] in ("RETURN_LAST", "RETURN_VALUE")