You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Two Bugs ...
2.7: more stringent comparison and comp_if testing 2.6-2.7: fix botched dict constant translation
This commit is contained in:
@@ -214,13 +214,15 @@ class Python27Parser(Python2Parser):
|
|||||||
|
|
||||||
|
|
||||||
super(Python27Parser, self).customize_grammar_rules(tokens, customize)
|
super(Python27Parser, self).customize_grammar_rules(tokens, customize)
|
||||||
self.check_reduce['and'] = 'AST'
|
self.check_reduce["and"] = "AST"
|
||||||
# self.check_reduce['or'] = 'AST'
|
self.check_reduce["conditional"] = "AST"
|
||||||
self.check_reduce['raise_stmt1'] = 'AST'
|
# self.check_reduce["or"] = "AST"
|
||||||
self.check_reduce['list_if_not'] = 'AST'
|
self.check_reduce["raise_stmt1"] = "AST"
|
||||||
self.check_reduce['list_if'] = 'AST'
|
self.check_reduce["list_if_not"] = "AST"
|
||||||
self.check_reduce['if_expr_true'] = 'tokens'
|
self.check_reduce["list_if"] = "AST"
|
||||||
self.check_reduce['whilestmt'] = 'tokens'
|
self.check_reduce["comp_if"] = "AST"
|
||||||
|
self.check_reduce["if_expr_true"] = "tokens"
|
||||||
|
self.check_reduce["whilestmt"] = "tokens"
|
||||||
return
|
return
|
||||||
|
|
||||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||||
@@ -231,10 +233,10 @@ class Python27Parser(Python2Parser):
|
|||||||
if invalid:
|
if invalid:
|
||||||
return invalid
|
return invalid
|
||||||
|
|
||||||
if rule == ('and', ('expr', 'jmp_false', 'expr', '\\e_come_from_opt')):
|
if rule == ("and", ("expr", "jmp_false", "expr", "\\e_come_from_opt")):
|
||||||
# If the instruction after the instructions formin "and" is an "YIELD_VALUE"
|
# If the instruction after the instructions formin "and" is an "YIELD_VALUE"
|
||||||
# then this is probably an "if" inside a comprehension.
|
# then this is probably an "if" inside a comprehension.
|
||||||
if tokens[last] == 'YIELD_VALUE':
|
if tokens[last] == "YIELD_VALUE":
|
||||||
# Note: We might also consider testing last+1 being "POP_TOP"
|
# Note: We might also consider testing last+1 being "POP_TOP"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -244,41 +246,57 @@ class Python27Parser(Python2Parser):
|
|||||||
jmp_target = jmp_false.offset + jmp_false.attr + 3
|
jmp_target = jmp_false.offset + jmp_false.attr + 3
|
||||||
return not (jmp_target == tokens[last].offset or
|
return not (jmp_target == tokens[last].offset or
|
||||||
tokens[last].pattr == jmp_false.pattr)
|
tokens[last].pattr == jmp_false.pattr)
|
||||||
elif rule[0] == ('raise_stmt1'):
|
elif rule == ("comp_if", ("expr", "jmp_false", "comp_iter")):
|
||||||
return ast[0] == 'expr' and ast[0][0] == 'or'
|
jmp_false = ast[1]
|
||||||
elif rule[0] in ('assert', 'assert2'):
|
if jmp_false[0] == "POP_JUMP_IF_FALSE":
|
||||||
|
return tokens[first].offset < jmp_false[0].attr < tokens[last].offset
|
||||||
|
pass
|
||||||
|
elif (rule[0], rule[1][0:5]) == (
|
||||||
|
"conditional",
|
||||||
|
("expr", "jmp_false", "expr", "JUMP_ABSOLUTE", "expr")):
|
||||||
|
jmp_false = ast[1]
|
||||||
|
if jmp_false[0] == "POP_JUMP_IF_FALSE":
|
||||||
|
else_instr = ast[4].first_child()
|
||||||
|
if jmp_false[0].attr != else_instr.offset:
|
||||||
|
return True
|
||||||
|
end_offset = ast[3].attr
|
||||||
|
return end_offset < tokens[last].offset
|
||||||
|
pass
|
||||||
|
elif rule[0] == ("raise_stmt1"):
|
||||||
|
return ast[0] == "expr" and ast[0][0] == "or"
|
||||||
|
elif rule[0] in ("assert", "assert2"):
|
||||||
jump_inst = ast[1][0]
|
jump_inst = ast[1][0]
|
||||||
jump_target = jump_inst.attr
|
jump_target = jump_inst.attr
|
||||||
return not (last >= len(tokens)
|
return not (last >= len(tokens)
|
||||||
or jump_target == tokens[last].offset
|
or jump_target == tokens[last].offset
|
||||||
or jump_target == next_offset(ast[-1].op, ast[-1].opc, ast[-1].offset))
|
or jump_target == next_offset(ast[-1].op, ast[-1].opc, ast[-1].offset))
|
||||||
elif rule == ('list_if_not', ('expr', 'jmp_true', 'list_iter')):
|
elif rule == ("list_if_not", ("expr", "jmp_true", "list_iter")):
|
||||||
jump_inst = ast[1][0]
|
jump_inst = ast[1][0]
|
||||||
jump_offset = jump_inst.attr
|
jump_offset = jump_inst.attr
|
||||||
return jump_offset > jump_inst.offset and jump_offset < tokens[last].offset
|
return jump_offset > jump_inst.offset and jump_offset < tokens[last].offset
|
||||||
elif rule == ('list_if', ('expr', 'jmp_false', 'list_iter')):
|
elif rule == ("list_if", ("expr", "jmp_false", "list_iter")):
|
||||||
jump_inst = ast[1][0]
|
jump_inst = ast[1][0]
|
||||||
jump_offset = jump_inst.attr
|
jump_offset = jump_inst.attr
|
||||||
return jump_offset > jump_inst.offset and jump_offset < tokens[last].offset
|
return jump_offset > jump_inst.offset and jump_offset < tokens[last].offset
|
||||||
elif rule == ('or', ('expr', 'jmp_true', 'expr', '\\e_come_from_opt')):
|
elif rule == ("or", ("expr", "jmp_true", "expr", "\\e_come_from_opt")):
|
||||||
# Test that jmp_true doesn't jump inside the middle the "or"
|
# Test that jmp_true doesn"t jump inside the middle the "or"
|
||||||
# or that it jumps to the same place as the end of "and"
|
# or that it jumps to the same place as the end of "and"
|
||||||
jmp_true = ast[1][0]
|
jmp_true = ast[1][0]
|
||||||
jmp_target = jmp_true.offset + jmp_true.attr + 3
|
jmp_target = jmp_true.offset + jmp_true.attr + 3
|
||||||
return not (jmp_target == tokens[last].offset or
|
return not (jmp_target == tokens[last].offset or
|
||||||
tokens[last].pattr == jmp_true.pattr)
|
tokens[last].pattr == jmp_true.pattr)
|
||||||
|
|
||||||
elif (rule[0] == 'whilestmt' and
|
elif (rule[0] == "whilestmt" and
|
||||||
rule[1][0:-2] ==
|
rule[1][0:-2] ==
|
||||||
('SETUP_LOOP', 'testexpr', 'l_stmts_opt',
|
("SETUP_LOOP", "testexpr", "l_stmts_opt",
|
||||||
'JUMP_BACK', 'JUMP_BACK')):
|
"JUMP_BACK", "JUMP_BACK")):
|
||||||
# Make sure that the jump backs all go to the same place
|
# Make sure that the jump backs all go to the same place
|
||||||
i = last-1
|
i = last-1
|
||||||
while (tokens[i] != 'JUMP_BACK'):
|
while (tokens[i] != "JUMP_BACK"):
|
||||||
i -= 1
|
i -= 1
|
||||||
return tokens[i].attr != tokens[i-1].attr
|
return tokens[i].attr != tokens[i-1].attr
|
||||||
elif rule[0] == 'if_expr_true':
|
elif rule[0] == "if_expr_true":
|
||||||
return (first) > 0 and tokens[first-1] == 'POP_JUMP_IF_FALSE'
|
return (first) > 0 and tokens[first-1] == "POP_JUMP_IF_FALSE"
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -286,7 +304,7 @@ class Python27Parser(Python2Parser):
|
|||||||
class Python27ParserSingle(Python27Parser, PythonParserSingle):
|
class Python27ParserSingle(Python27Parser, PythonParserSingle):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
# Check grammar
|
# Check grammar
|
||||||
p = Python27Parser()
|
p = Python27Parser()
|
||||||
p.check_grammar()
|
p.check_grammar()
|
||||||
@@ -302,9 +320,9 @@ if __name__ == '__main__':
|
|||||||
""".split()))
|
""".split()))
|
||||||
remain_tokens = set(tokens) - opcode_set
|
remain_tokens = set(tokens) - opcode_set
|
||||||
import re
|
import re
|
||||||
remain_tokens = set([re.sub(r'_\d+$', '', t)
|
remain_tokens = set([re.sub(r"_\d+$", "", t)
|
||||||
for t in remain_tokens])
|
for t in remain_tokens])
|
||||||
remain_tokens = set([re.sub('_CONT$', '', t)
|
remain_tokens = set([re.sub("_CONT$", "", t)
|
||||||
for t in remain_tokens])
|
for t in remain_tokens])
|
||||||
remain_tokens = set(remain_tokens) - opcode_set
|
remain_tokens = set(remain_tokens) - opcode_set
|
||||||
print(remain_tokens)
|
print(remain_tokens)
|
||||||
|
@@ -1633,6 +1633,57 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
|
|
||||||
self.write(")")
|
self.write(")")
|
||||||
|
|
||||||
|
def kv_map(self, kv_node, sep, line_number, indent):
|
||||||
|
first_time = True
|
||||||
|
for kv in kv_node:
|
||||||
|
assert kv in ('kv', 'kv2', 'kv3')
|
||||||
|
|
||||||
|
# kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR
|
||||||
|
# kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR
|
||||||
|
# kv3 ::= expr expr STORE_MAP
|
||||||
|
|
||||||
|
# FIXME: DRY this and the above
|
||||||
|
if kv == 'kv':
|
||||||
|
self.write(sep)
|
||||||
|
name = self.traverse(kv[-2], indent='')
|
||||||
|
if first_time:
|
||||||
|
line_number = self.indent_if_source_nl(line_number, indent)
|
||||||
|
first_time = False
|
||||||
|
pass
|
||||||
|
line_number = self.line_number
|
||||||
|
self.write(name, ': ')
|
||||||
|
value = self.traverse(kv[1], indent=self.indent+(len(name)+2)*' ')
|
||||||
|
elif kv == 'kv2':
|
||||||
|
self.write(sep)
|
||||||
|
name = self.traverse(kv[1], indent='')
|
||||||
|
if first_time:
|
||||||
|
line_number = self.indent_if_source_nl(line_number, indent)
|
||||||
|
first_time = False
|
||||||
|
pass
|
||||||
|
line_number = self.line_number
|
||||||
|
self.write(name, ': ')
|
||||||
|
value = self.traverse(kv[-3], indent=self.indent+(len(name)+2)*' ')
|
||||||
|
elif kv == 'kv3':
|
||||||
|
self.write(sep)
|
||||||
|
name = self.traverse(kv[-2], indent='')
|
||||||
|
if first_time:
|
||||||
|
line_number = self.indent_if_source_nl(line_number, indent)
|
||||||
|
first_time = False
|
||||||
|
pass
|
||||||
|
line_number = self.line_number
|
||||||
|
self.write(name, ': ')
|
||||||
|
line_number = self.line_number
|
||||||
|
value = self.traverse(kv[0], indent=self.indent+(len(name)+2)*' ')
|
||||||
|
pass
|
||||||
|
self.write(value)
|
||||||
|
sep = ", "
|
||||||
|
if line_number != self.line_number:
|
||||||
|
sep += "\n" + self.indent + " "
|
||||||
|
line_number = self.line_number
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def n_dict(self, node):
|
def n_dict(self, node):
|
||||||
"""
|
"""
|
||||||
prettyprint a dict
|
prettyprint a dict
|
||||||
@@ -1753,14 +1804,15 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# Python 2 style kvlist. Find beginning of kvlist.
|
# Python 2 style kvlist. Find beginning of kvlist.
|
||||||
|
indent = self.indent + " "
|
||||||
|
line_number = self.line_number
|
||||||
if node[0].kind.startswith("BUILD_MAP"):
|
if node[0].kind.startswith("BUILD_MAP"):
|
||||||
if len(node) > 1 and node[1].kind in ("kvlist", "kvlist_n"):
|
if len(node) > 1 and node[1].kind in ("kvlist", "kvlist_n"):
|
||||||
kv_node = node[1]
|
kv_node = node[1]
|
||||||
else:
|
else:
|
||||||
kv_node = node[1:]
|
kv_node = node[1:]
|
||||||
|
self.kv_map(kv_node, sep, line_number, indent)
|
||||||
else:
|
else:
|
||||||
indent = self.indent + " "
|
|
||||||
line_number = self.line_number
|
|
||||||
sep = ''
|
sep = ''
|
||||||
opname = node[-1].kind
|
opname = node[-1].kind
|
||||||
if self.is_pypy and self.version >= 3.5:
|
if self.is_pypy and self.version >= 3.5:
|
||||||
@@ -1798,54 +1850,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
pass
|
pass
|
||||||
elif opname.startswith('kvlist'):
|
elif opname.startswith('kvlist'):
|
||||||
kv_node = node[-1]
|
kv_node = node[-1]
|
||||||
first_time = True
|
self.kv_map(node[-1], sep, line_number, indent)
|
||||||
for kv in kv_node:
|
|
||||||
assert kv in ('kv', 'kv2', 'kv3')
|
|
||||||
|
|
||||||
# kv ::= DUP_TOP expr ROT_TWO expr STORE_SUBSCR
|
|
||||||
# kv2 ::= DUP_TOP expr expr ROT_THREE STORE_SUBSCR
|
|
||||||
# kv3 ::= expr expr STORE_MAP
|
|
||||||
|
|
||||||
# FIXME: DRY this and the above
|
|
||||||
if kv == 'kv':
|
|
||||||
self.write(sep)
|
|
||||||
name = self.traverse(kv[-2], indent='')
|
|
||||||
if first_time:
|
|
||||||
line_number = self.indent_if_source_nl(line_number, indent)
|
|
||||||
first_time = False
|
|
||||||
pass
|
|
||||||
line_number = self.line_number
|
|
||||||
self.write(name, ': ')
|
|
||||||
value = self.traverse(kv[1], indent=self.indent+(len(name)+2)*' ')
|
|
||||||
elif kv == 'kv2':
|
|
||||||
self.write(sep)
|
|
||||||
name = self.traverse(kv[1], indent='')
|
|
||||||
if first_time:
|
|
||||||
line_number = self.indent_if_source_nl(line_number, indent)
|
|
||||||
first_time = False
|
|
||||||
pass
|
|
||||||
line_number = self.line_number
|
|
||||||
self.write(name, ': ')
|
|
||||||
value = self.traverse(kv[-3], indent=self.indent+(len(name)+2)*' ')
|
|
||||||
elif kv == 'kv3':
|
|
||||||
self.write(sep)
|
|
||||||
name = self.traverse(kv[-2], indent='')
|
|
||||||
if first_time:
|
|
||||||
line_number = self.indent_if_source_nl(line_number, indent)
|
|
||||||
first_time = False
|
|
||||||
pass
|
|
||||||
line_number = self.line_number
|
|
||||||
self.write(name, ': ')
|
|
||||||
line_number = self.line_number
|
|
||||||
value = self.traverse(kv[0], indent=self.indent+(len(name)+2)*' ')
|
|
||||||
pass
|
|
||||||
self.write(value)
|
|
||||||
sep = ", "
|
|
||||||
if line_number != self.line_number:
|
|
||||||
sep += "\n" + self.indent + " "
|
|
||||||
line_number = self.line_number
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
|
|
||||||
pass
|
pass
|
||||||
if sep.startswith(",\n"):
|
if sep.startswith(",\n"):
|
||||||
|
Reference in New Issue
Block a user