ret_expr -> return_expr

This matches Python's AST a little more closely
This commit is contained in:
rocky
2022-01-03 21:51:32 -05:00
parent 7f42694c25
commit deea74b6a8
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

@@ -72,9 +72,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
# Python 2.6 uses ROT_TWO instead of the STORE_xxx
# withas is allowed as a "from future" in 2.5
@@ -72,13 +72,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
@@ -1452,7 +1452,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

@@ -180,8 +180,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
@@ -262,11 +262,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

@@ -106,8 +106,8 @@ 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_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
return_if_stmt ::= return_expr RETURN_END_IF POP_BLOCK
return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
jb_else ::= JUMP_BACK ELSE
ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec

View File

@@ -54,9 +54,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

@@ -120,7 +120,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
@@ -192,17 +192,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
@@ -513,7 +513,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
@@ -754,7 +754,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
@@ -934,9 +934,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
@@ -994,7 +994,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
@@ -1097,9 +1097,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

@@ -93,16 +93,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

@@ -123,7 +123,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

@@ -327,7 +327,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())
@@ -355,7 +355,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])
@@ -438,9 +438,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):
@@ -757,7 +757,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

@@ -475,7 +475,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
@@ -486,7 +486,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?
@@ -598,7 +598,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
@@ -606,7 +606,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"""
@@ -1193,7 +1193,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")