You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Misc changes
scanner26.py: make scanner2.py and scanner26.py more alike scanner2.py: check that return stmt is last in list. (May change) main.py: show filename on verify error test/*: add more
This commit is contained in:
Binary file not shown.
BIN
test/bytecode_2.6/03_elif_vs_continue.pyc
Normal file
BIN
test/bytecode_2.6/03_elif_vs_continue.pyc
Normal file
Binary file not shown.
18
test/simple_source/bug26/03_elif_vs_continue.py
Normal file
18
test/simple_source/bug26/03_elif_vs_continue.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Bug was using continue fouling up 1st elif, by confusing
|
||||||
|
# the "pass" for "continue" by not recognizing the if jump
|
||||||
|
# around it. We fixed by ignoring what's done in Python 2.7
|
||||||
|
# Better is better detection of control structures
|
||||||
|
|
||||||
|
def _compile_charset(charset, flags, code, fixup=None):
|
||||||
|
# compile charset subprogram
|
||||||
|
emit = code.append
|
||||||
|
if fixup is None:
|
||||||
|
fixup = 1
|
||||||
|
for op, av in charset:
|
||||||
|
if op is flags:
|
||||||
|
pass
|
||||||
|
elif op is code:
|
||||||
|
emit(fixup(av))
|
||||||
|
else:
|
||||||
|
raise RuntimeError
|
||||||
|
emit(5)
|
@@ -189,17 +189,16 @@ def main(in_base, out_base, files, codes, outfile=None,
|
|||||||
print(e)
|
print(e)
|
||||||
verify_failed_files += 1
|
verify_failed_files += 1
|
||||||
os.rename(outfile, outfile + '_unverified')
|
os.rename(outfile, outfile + '_unverified')
|
||||||
|
sys.stderr.write("### Error Verifying %s\n" % filename)
|
||||||
|
sys.stderr.write(str(e) + "\n")
|
||||||
if not outfile:
|
if not outfile:
|
||||||
print("### Error Verifiying %s" % filename, file=sys.stderr)
|
|
||||||
print(e, file=sys.stderr)
|
|
||||||
if raise_on_error:
|
if raise_on_error:
|
||||||
raise
|
raise
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
elif do_verify:
|
elif do_verify:
|
||||||
print("\n### uncompile successful, but no file to compare against",
|
sys.stderr.write("\n### uncompile successful, but no file to compare against\n")
|
||||||
file=sys.stderr)
|
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
okay_files += 1
|
okay_files += 1
|
||||||
|
@@ -81,7 +81,7 @@ class PythonParser(GenericASTBuilder):
|
|||||||
else:
|
else:
|
||||||
prefix = ' '
|
prefix = ' '
|
||||||
if hasattr(p_token, 'offset'):
|
if hasattr(p_token, 'offset'):
|
||||||
prefix += "%3d " % p_token.offset
|
prefix += "%3s " % str(p_token.offset)
|
||||||
prefix += " "
|
prefix += " "
|
||||||
else:
|
else:
|
||||||
prefix = ' '
|
prefix = ' '
|
||||||
@@ -485,6 +485,8 @@ class PythonParser(GenericASTBuilder):
|
|||||||
_mklambda ::= load_closure mklambda
|
_mklambda ::= load_closure mklambda
|
||||||
_mklambda ::= mklambda
|
_mklambda ::= mklambda
|
||||||
|
|
||||||
|
# "and" where the first part of the and is true,
|
||||||
|
# so there is only the 2nd part to evaluate
|
||||||
and2 ::= _jump jmp_false COME_FROM expr COME_FROM
|
and2 ::= _jump jmp_false COME_FROM expr COME_FROM
|
||||||
|
|
||||||
expr ::= conditional
|
expr ::= conditional
|
||||||
|
@@ -392,13 +392,22 @@ class Python2Parser(PythonParser):
|
|||||||
pass
|
pass
|
||||||
self.check_reduce['augassign1'] = 'AST'
|
self.check_reduce['augassign1'] = 'AST'
|
||||||
self.check_reduce['augassign2'] = 'AST'
|
self.check_reduce['augassign2'] = 'AST'
|
||||||
|
self.check_reduce['_stmts'] = 'AST'
|
||||||
return
|
return
|
||||||
|
|
||||||
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
def reduce_is_invalid(self, rule, ast, tokens, first, last):
|
||||||
lhs = rule[0]
|
lhs = rule[0]
|
||||||
if lhs in ('augassign1', 'augassign2') and ast[0][0] == 'and':
|
if lhs in ('augassign1', 'augassign2') and ast[0][0] == 'and':
|
||||||
return True
|
return True
|
||||||
# Add more stuff, like COME_FROM checking
|
elif lhs == '_stmts':
|
||||||
|
for i, stmt in enumerate(ast):
|
||||||
|
if stmt == '_stmts':
|
||||||
|
stmt = stmt[0]
|
||||||
|
assert stmt == 'stmt'
|
||||||
|
if stmt[0] == 'return_stmt':
|
||||||
|
return i+1 != len(ast)
|
||||||
|
pass
|
||||||
|
return False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class Python2ParserSingle(Python2Parser, PythonParserSingle):
|
class Python2ParserSingle(Python2Parser, PythonParserSingle):
|
||||||
|
@@ -166,9 +166,9 @@ class Scanner2(scan.Scanner):
|
|||||||
# continue
|
# continue
|
||||||
# last_offset = jump_offset
|
# last_offset = jump_offset
|
||||||
come_from_name = 'COME_FROM'
|
come_from_name = 'COME_FROM'
|
||||||
opname = self.opc.opname[self.code[jump_offset]]
|
op_name = self.opc.opname[self.code[jump_offset]]
|
||||||
if opname.startswith('SETUP_') and self.version == 2.7:
|
if op_name.startswith('SETUP_') and self.version == 2.7:
|
||||||
come_from_type = opname[len('SETUP_'):]
|
come_from_type = op_name[len('SETUP_'):]
|
||||||
if come_from_type not in ('LOOP', 'EXCEPT'):
|
if come_from_type not in ('LOOP', 'EXCEPT'):
|
||||||
come_from_name = 'COME_FROM_%s' % come_from_type
|
come_from_name = 'COME_FROM_%s' % come_from_type
|
||||||
pass
|
pass
|
||||||
@@ -179,7 +179,7 @@ class Scanner2(scan.Scanner):
|
|||||||
jump_idx += 1
|
jump_idx += 1
|
||||||
|
|
||||||
op = self.code[offset]
|
op = self.code[offset]
|
||||||
opname = self.opc.opname[op]
|
op_name = self.opc.opname[op]
|
||||||
|
|
||||||
oparg = None; pattr = None
|
oparg = None; pattr = None
|
||||||
has_arg = op_has_argument(op, self.opc)
|
has_arg = op_has_argument(op, self.opc)
|
||||||
@@ -194,14 +194,14 @@ class Scanner2(scan.Scanner):
|
|||||||
if iscode(const):
|
if iscode(const):
|
||||||
oparg = const
|
oparg = const
|
||||||
if const.co_name == '<lambda>':
|
if const.co_name == '<lambda>':
|
||||||
assert opname == 'LOAD_CONST'
|
assert op_name == 'LOAD_CONST'
|
||||||
opname = 'LOAD_LAMBDA'
|
op_name = 'LOAD_LAMBDA'
|
||||||
elif const.co_name == '<genexpr>':
|
elif const.co_name == '<genexpr>':
|
||||||
opname = 'LOAD_GENEXPR'
|
op_name = 'LOAD_GENEXPR'
|
||||||
elif const.co_name == '<dictcomp>':
|
elif const.co_name == '<dictcomp>':
|
||||||
opname = 'LOAD_DICTCOMP'
|
op_name = 'LOAD_DICTCOMP'
|
||||||
elif const.co_name == '<setcomp>':
|
elif const.co_name == '<setcomp>':
|
||||||
opname = 'LOAD_SETCOMP'
|
op_name = 'LOAD_SETCOMP'
|
||||||
# verify() uses 'pattr' for comparison, since 'attr'
|
# verify() uses 'pattr' for comparison, since 'attr'
|
||||||
# now holds Code(const) and thus can not be used
|
# now holds Code(const) and thus can not be used
|
||||||
# for comparison (todo: think about changing this)
|
# for comparison (todo: think about changing this)
|
||||||
@@ -237,20 +237,20 @@ class Scanner2(scan.Scanner):
|
|||||||
self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE:
|
self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if self.is_pypy and not oparg and opname == 'BUILD_MAP':
|
if self.is_pypy and not oparg and op_name == 'BUILD_MAP':
|
||||||
opname = 'BUILD_MAP_n'
|
op_name = 'BUILD_MAP_n'
|
||||||
else:
|
else:
|
||||||
opname = '%s_%d' % (opname, oparg)
|
op_name = '%s_%d' % (op_name, oparg)
|
||||||
if op != self.opc.BUILD_SLICE:
|
if op != self.opc.BUILD_SLICE:
|
||||||
customize[opname] = oparg
|
customize[op_name] = oparg
|
||||||
elif self.is_pypy and opname in ('LOOKUP_METHOD',
|
elif self.is_pypy and op_name in ('LOOKUP_METHOD',
|
||||||
'JUMP_IF_NOT_DEBUG',
|
'JUMP_IF_NOT_DEBUG',
|
||||||
'SETUP_EXCEPT',
|
'SETUP_EXCEPT',
|
||||||
'SETUP_FINALLY'):
|
'SETUP_FINALLY'):
|
||||||
# The value in the dict is in special cases in semantic actions, such
|
# The value in the dict is in special cases in semantic actions, such
|
||||||
# as CALL_FUNCTION. The value is not used in these cases, so we put
|
# as CALL_FUNCTION. The value is not used in these cases, so we put
|
||||||
# in arbitrary value 0.
|
# in arbitrary value 0.
|
||||||
customize[opname] = 0
|
customize[op_name] = 0
|
||||||
elif op == self.opc.JUMP_ABSOLUTE:
|
elif op == self.opc.JUMP_ABSOLUTE:
|
||||||
# Further classify JUMP_ABSOLUTE into backward jumps
|
# Further classify JUMP_ABSOLUTE into backward jumps
|
||||||
# which are used in loops, and "CONTINUE" jumps which
|
# which are used in loops, and "CONTINUE" jumps which
|
||||||
@@ -269,16 +269,16 @@ class Scanner2(scan.Scanner):
|
|||||||
and self.code[offset+3] not in (self.opc.END_FINALLY,
|
and self.code[offset+3] not in (self.opc.END_FINALLY,
|
||||||
self.opc.POP_BLOCK)
|
self.opc.POP_BLOCK)
|
||||||
and offset not in self.not_continue):
|
and offset not in self.not_continue):
|
||||||
opname = 'CONTINUE'
|
op_name = 'CONTINUE'
|
||||||
else:
|
else:
|
||||||
opname = 'JUMP_BACK'
|
op_name = 'JUMP_BACK'
|
||||||
|
|
||||||
elif op == self.opc.LOAD_GLOBAL:
|
elif op == self.opc.LOAD_GLOBAL:
|
||||||
if offset in self.load_asserts:
|
if offset in self.load_asserts:
|
||||||
opname = 'LOAD_ASSERT'
|
op_name = 'LOAD_ASSERT'
|
||||||
elif op == self.opc.RETURN_VALUE:
|
elif op == self.opc.RETURN_VALUE:
|
||||||
if offset in self.return_end_ifs:
|
if offset in self.return_end_ifs:
|
||||||
opname = 'RETURN_END_IF'
|
op_name = 'RETURN_END_IF'
|
||||||
|
|
||||||
if offset in self.linestartoffsets:
|
if offset in self.linestartoffsets:
|
||||||
linestart = self.linestartoffsets[offset]
|
linestart = self.linestartoffsets[offset]
|
||||||
@@ -287,7 +287,7 @@ class Scanner2(scan.Scanner):
|
|||||||
|
|
||||||
if offset not in replace:
|
if offset not in replace:
|
||||||
tokens.append(Token(
|
tokens.append(Token(
|
||||||
opname, oparg, pattr, offset, linestart, op,
|
op_name, oparg, pattr, offset, linestart, op,
|
||||||
has_arg, self.opc))
|
has_arg, self.opc))
|
||||||
else:
|
else:
|
||||||
tokens.append(Token(
|
tokens.append(Token(
|
||||||
@@ -782,21 +782,23 @@ class Scanner2(scan.Scanner):
|
|||||||
if offset in self.ignore_if:
|
if offset in self.ignore_if:
|
||||||
return
|
return
|
||||||
|
|
||||||
if code[pre[rtarget]] == self.opc.JUMP_ABSOLUTE and pre[rtarget] in self.stmts \
|
if self.version == 2.7:
|
||||||
and pre[rtarget] != offset and pre[pre[rtarget]] != offset:
|
if code[pre[rtarget]] == self.opc.JUMP_ABSOLUTE and pre[rtarget] in self.stmts \
|
||||||
if code[rtarget] == self.opc.JUMP_ABSOLUTE and code[rtarget+3] == self.opc.POP_BLOCK:
|
and pre[rtarget] != offset and pre[pre[rtarget]] != offset:
|
||||||
if code[pre[pre[rtarget]]] != self.opc.JUMP_ABSOLUTE:
|
if code[rtarget] == self.opc.JUMP_ABSOLUTE and code[rtarget+3] == self.opc.POP_BLOCK:
|
||||||
pass
|
if code[pre[pre[rtarget]]] != self.opc.JUMP_ABSOLUTE:
|
||||||
elif self.get_target(pre[pre[rtarget]]) != target:
|
pass
|
||||||
pass
|
elif self.get_target(pre[pre[rtarget]]) != target:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
rtarget = pre[rtarget]
|
||||||
else:
|
else:
|
||||||
rtarget = pre[rtarget]
|
rtarget = pre[rtarget]
|
||||||
else:
|
|
||||||
rtarget = pre[rtarget]
|
|
||||||
|
|
||||||
# Does the "if" jump just beyond a jump op, then this is probably an if statement
|
# Does the "if" jump just beyond a jump op, then this is probably an if statement
|
||||||
pre_rtarget = pre[rtarget]
|
pre_rtarget = pre[rtarget]
|
||||||
code_pre_rtarget = code[pre_rtarget]
|
code_pre_rtarget = code[pre_rtarget]
|
||||||
|
|
||||||
if code_pre_rtarget in self.jump_forward:
|
if code_pre_rtarget in self.jump_forward:
|
||||||
if_end = self.get_target(pre_rtarget)
|
if_end = self.get_target(pre_rtarget)
|
||||||
|
|
||||||
@@ -824,6 +826,7 @@ class Scanner2(scan.Scanner):
|
|||||||
self.structs.append({'type': 'if-then',
|
self.structs.append({'type': 'if-then',
|
||||||
'start': start-3,
|
'start': start-3,
|
||||||
'end': pre_rtarget})
|
'end': pre_rtarget})
|
||||||
|
|
||||||
self.not_continue.add(pre_rtarget)
|
self.not_continue.add(pre_rtarget)
|
||||||
|
|
||||||
if rtarget < end:
|
if rtarget < end:
|
||||||
|
@@ -233,7 +233,7 @@ class Scanner26(scan.Scanner2):
|
|||||||
if op != self.opc.BUILD_SLICE:
|
if op != self.opc.BUILD_SLICE:
|
||||||
customize[op_name] = oparg
|
customize[op_name] = oparg
|
||||||
elif op == self.opc.JUMP_ABSOLUTE:
|
elif op == self.opc.JUMP_ABSOLUTE:
|
||||||
# Further classifhy JUMP_ABSOLUTE into backward jumps
|
# Further classify JUMP_ABSOLUTE into backward jumps
|
||||||
# which are used in loops, and "CONTINUE" jumps which
|
# which are used in loops, and "CONTINUE" jumps which
|
||||||
# may appear in a "continue" statement. The loop-type
|
# may appear in a "continue" statement. The loop-type
|
||||||
# and continue-type jumps will help us classify loop
|
# and continue-type jumps will help us classify loop
|
||||||
@@ -254,6 +254,9 @@ class Scanner26(scan.Scanner2):
|
|||||||
# if x: continue
|
# if x: continue
|
||||||
# the "continue" is not on a new line.
|
# the "continue" is not on a new line.
|
||||||
if tokens[-1].type == 'JUMP_BACK':
|
if tokens[-1].type == 'JUMP_BACK':
|
||||||
|
# We need 'intern' since we have
|
||||||
|
# already have processed the previous
|
||||||
|
# token.
|
||||||
tokens[-1].type = intern('CONTINUE')
|
tokens[-1].type = intern('CONTINUE')
|
||||||
|
|
||||||
elif op == self.opc.LOAD_GLOBAL:
|
elif op == self.opc.LOAD_GLOBAL:
|
||||||
|
Reference in New Issue
Block a user