Merge branch 'master' into python-2.4

This commit is contained in:
rocky
2020-01-06 23:32:31 -05:00
7 changed files with 93 additions and 30 deletions

View File

@@ -159,6 +159,17 @@ class Python2Parser(PythonParser):
except_handler ::= jmp_abs COME_FROM except_stmts
END_FINALLY
# except_handler_else is intended to be used only in a
# try_else. The disambiguation comes from reduction rule
# checking where we make sure that the JUMP_FORWARD mismatches
# the JUMP_FORWARD before the END_FINALLY
except_handler_else ::= JUMP_FORWARD COME_FROM except_stmts
END_FINALLY come_froms
except_handler_else ::= jmp_abs COME_FROM except_stmts
END_FINALLY
except_stmts ::= except_stmt+
except_stmt ::= except_cond1 except_suite
@@ -635,6 +646,8 @@ class Python2Parser(PythonParser):
self.addRule(rule, nop_func)
pass
self.check_reduce["except_handler"] = "tokens"
self.check_reduce["except_handler_else"] = "tokens"
self.check_reduce["raise_stmt1"] = "tokens"
self.check_reduce["assert_expr_and"] = "AST"
self.check_reduce["tryelsestmt"] = "AST"
@@ -666,6 +679,31 @@ class Python2Parser(PythonParser):
jmp_false = ast[1]
jump_target = jmp_false[0].attr
return jump_target > tokens[last].off2int()
elif lhs in ("except_handler, except_handler_else"):
# FIXME: expand this to other 2.x version
if self.version != 2.7: return False
if tokens[first] in ("JUMP_FORWARD", "JUMP_ABSOLUTE"):
first_jump_target = tokens[first].pattr
last = min(last, len(tokens)-1)
for i in range(last, first, -1):
if tokens[i] == "END_FINALLY":
i -= 1
second_jump = tokens[i]
if second_jump in ("JUMP_FORWARD", "JUMP_ABSOLUTE"):
second_jump_target = second_jump.pattr
equal_target = second_jump_target == first_jump_target
if equal_target:
return lhs != "except_handler"
else:
return lhs != "except_handler_else"
pass
else:
return False
pass
pass
pass
elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")):
for i in range(last-1, last-4, -1):
t = tokens[i]

View File

@@ -60,13 +60,13 @@ class Python27Parser(Python2Parser):
COME_FROM_FINALLY suite_stmts_opt END_FINALLY
tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
except_handler else_suite COME_FROM
except_handler_else else_suite COME_FROM
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
except_handler else_suitel JUMP_BACK COME_FROM
except_handler_else else_suitel JUMP_BACK COME_FROM
tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
except_handler else_suitel
except_handler_else else_suitel
except_stmt ::= except_cond2 except_suite
@@ -216,6 +216,10 @@ class Python27Parser(Python2Parser):
super(Python27Parser, self).customize_grammar_rules(tokens, customize)
self.check_reduce["and"] = "AST"
self.check_reduce["conditional"] = "AST"
self.check_reduce["except_handler"] = "tokens"
self.check_reduce["except_handler_else"] = "tokens"
# self.check_reduce["or"] = "AST"
self.check_reduce["raise_stmt1"] = "AST"
self.check_reduce["iflaststmtl"] = "AST"

View File

@@ -18,6 +18,7 @@ All the crazy things we have to do to handle Python functions in Python before 3
The saga of changes continues in 3.0 and above and in other files.
"""
from xdis.code import iscode, code_has_star_arg, code_has_star_star_arg
from xdis.util import CO_GENERATOR
from uncompyle6.scanner import Code
from uncompyle6.parsers.treenode import SyntaxTree
from uncompyle6 import PYTHON3
@@ -178,7 +179,6 @@ def make_function2(self, node, is_lambda, nested=1, code_node=None):
# docstring exists, dump it
print_docstring(self, indent, code.co_consts[0])
code._tokens = None # save memory
if not is_lambda:
assert ast == "stmts"
@@ -199,5 +199,6 @@ def make_function2(self, node, is_lambda, nested=1, code_node=None):
self.gen_source(
ast, code.co_name, code._customize, is_lambda=is_lambda, returnNone=rn
)
code._tokens = None
code._tokens = None # save memory
code._customize = None # save memory

View File

@@ -17,6 +17,7 @@ All the crazy things we have to do to handle Python functions in 3.0-3.5 or so.
The saga of changes before and after is in other files.
"""
from xdis.code import iscode, code_has_star_arg, code_has_star_star_arg
from xdis.util import CO_GENERATOR
from uncompyle6.scanner import Code
from uncompyle6.parsers.treenode import SyntaxTree
from uncompyle6.semantics.parser_error import ParserError
@@ -485,9 +486,8 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
kwargs = list(scanner_code.co_varnames[argc : argc + kwonlyargcount])
# defaults are for last n parameters when not in a lambda, thus reverse
if not is_lambda:
paramnames.reverse()
defparams.reverse()
paramnames.reverse()
defparams.reverse()
try:
ast = self.build_ast(scanner_code._tokens,
@@ -645,7 +645,6 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
# docstring exists, dump it
print_docstring(self, self.indent, code.co_consts[0])
scanner_code._tokens = None # save memory
assert ast == "stmts"
all_globals = find_all_globals(ast, set())
@@ -665,5 +664,21 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
self.gen_source(
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn
)
scanner_code._tokens = None
# In obscure cases, a function may be a generator but the "yield"
# was optimized away. Here, we need to put in unreachable code to
# add in "yield" just so that the compiler will mark
# the GENERATOR bit of the function. See for example
# Python 3.x's test_generator.py test program.
if code.co_flags & CO_GENERATOR:
need_bogus_yield = True
for token in scanner_code._tokens:
if token in ("YIELD_VALUE", "YIELD_FROM"):
need_bogus_yield = False
break
pass
if need_bogus_yield:
self.template_engine(("%|if False:\n%+%|yield None%-",), node)
scanner_code._tokens = None # save memory
scanner_code._customize = None # save memory

View File

@@ -17,6 +17,7 @@ All the crazy things we have to do to handle Python functions in 3.6 and above.
The saga of changes before 3.6 is in other files.
"""
from xdis.code import iscode, code_has_star_arg, code_has_star_star_arg
from xdis.util import CO_GENERATOR, CO_ASYNC_GENERATOR
from uncompyle6.scanner import Code
from uncompyle6.parsers.treenode import SyntaxTree
from uncompyle6.semantics.parser_error import ParserError
@@ -197,10 +198,8 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
paramnames = list(scanner_code.co_varnames[:argc])
kwargs = list(scanner_code.co_varnames[argc : argc + kwonlyargcount])
# defaults are for last n parameters when not in a lambda, thus reverse
if not is_lambda:
paramnames.reverse()
defparams.reverse()
paramnames.reverse()
defparams.reverse()
try:
ast = self.build_ast(
@@ -372,7 +371,6 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
# docstring exists, dump it
self.println(self.traverse(node[-2]))
scanner_code._tokens = None # save memory
assert ast == "stmts"
all_globals = find_all_globals(ast, set())
@@ -393,5 +391,20 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
ast, code.co_name, scanner_code._customize, is_lambda=is_lambda, returnNone=rn
)
scanner_code._tokens = None
# In obscure cases, a function may be a generator but the "yield"
# was optimized away. Here, we need to put in unreachable code to
# add in "yield" just so that the compiler will mark
# the GENERATOR bit of the function. See for example
# Python 3.x's test_generator.py test program.
if code.co_flags & (CO_GENERATOR | CO_ASYNC_GENERATOR):
need_bogus_yield = True
for token in scanner_code._tokens:
if token == "YIELD_VALUE":
need_bogus_yield = False
break
pass
if need_bogus_yield:
self.template_engine(("%|if False:\n%+%|yield None%-",), node)
scanner_code._tokens = None # save memory
scanner_code._customize = None # save memory