diff --git a/README b/README index 099caa22..649894d6 100644 --- a/README +++ b/README @@ -27,12 +27,7 @@ Options: --comparable Only for dumping, remove several false differences when comparing dumps. This suppresses attributes that are different even when the code is identical, such as file - modification times. Line numbers are also suppressed unless - the --line-numbers option is used. - --line-numbers Allow line numbers to be compared. When decompiling, this - causes extra lines to be printed to make line numbers - match. When dumping the ast, this causes line numbers to be - printed even when using --comparable. + modification times. --no-pyexpr Only for dumping, disable special handling of PyExpr objects, instead printing them as strings. This is useful when comparing dumps from different versions of Ren'Py. It should only be used diff --git a/decompiler/__init__.py b/decompiler/__init__.py index e9cccf77..11e469d6 100644 --- a/decompiler/__init__.py +++ b/decompiler/__init__.py @@ -38,10 +38,9 @@ # Main API def pprint(out_file, ast, indent_level=0, - decompile_python=False, line_numbers=False, printlock=None): + decompile_python=False, printlock=None): Decompiler(out_file, printlock=printlock, - decompile_python=decompile_python, - match_line_numbers=line_numbers).dump(ast, indent_level) + decompile_python=decompile_python).dump(ast, indent_level) # Implementation @@ -55,8 +54,8 @@ class Decompiler(DecompilerBase): dispatch = Dispatcher() def __init__(self, out_file=None, decompile_python=False, - indentation = ' ', match_line_numbers=False, printlock=None): - super(Decompiler, self).__init__(out_file, indentation, match_line_numbers, printlock) + indentation = ' ', printlock=None): + super(Decompiler, self).__init__(out_file, indentation, printlock) self.decompile_python = decompile_python self.paired_with = False @@ -64,11 +63,9 @@ def __init__(self, out_file=None, decompile_python=False, self.label_inside_menu = None def dump(self, ast, indent_level=0): - if not self.match_line_numbers: - self.write("# Decompiled by unrpyc: https://github.com/CensoredUsername/unrpyc") - # Avoid an initial blank line if we don't write out the above banner - super(Decompiler, self).dump(ast, indent_level, skip_indent_until_write=self.match_line_numbers) - self.write("\n") # end file with a newline + # skip_indent_until_write avoids an initial blank line + super(Decompiler, self).dump(ast, indent_level, skip_indent_until_write=True) + self.write("\n# Decompiled by unrpyc: https://github.com/CensoredUsername/unrpyc\n") def print_node(self, ast): # We special-case line advancement for TranslateString in its print @@ -97,7 +94,7 @@ def print_atl(self, ast): # If a statement ends with a colon but has no block after it, loc will # get set to ('', 0). That isn't supposed to be valid syntax, but it's # the only thing that can generate that. - elif not self.match_line_numbers or ast.loc != ('', 0): + elif ast.loc != ('', 0): self.indent() self.write("pass") self.indent_level -= 1 @@ -476,7 +473,7 @@ def print_pass(self, ast): self.write("pass") def should_come_before(self, first, second): - return self.match_line_numbers and first.linenumber < second.linenumber + return first.linenumber < second.linenumber @dispatch(renpy.ast.Init) def print_init(self, ast): @@ -722,13 +719,13 @@ def print_screen(self, ast): self.linenumber = screendecompiler.pprint(self.out_file, screen, self.indent_level, self.linenumber, self.decompile_python, - self.match_line_numbers, self.skip_indent_until_write) + self.skip_indent_until_write) self.skip_indent_until_write = False elif isinstance(screen, renpy.sl2.slast.SLScreen): self.linenumber = sl2decompiler.pprint(self.out_file, screen, self.indent_level, self.linenumber, - self.match_line_numbers, self.skip_indent_until_write) + self.skip_indent_until_write) self.skip_indent_until_write = False else: self.print_unknown(screen) diff --git a/decompiler/astdump.py b/decompiler/astdump.py index 8b108f90..095e82c9 100644 --- a/decompiler/astdump.py +++ b/decompiler/astdump.py @@ -26,10 +26,10 @@ import ast as py_ast import renpy -def pprint(out_file, ast, decompile_python=False, comparable=False, line_numbers=False, no_pyexpr=False): +def pprint(out_file, ast, decompile_python=False, comparable=False, no_pyexpr=False): # The main function of this module, a wrapper which sets # the config and creates the AstDumper instance - AstDumper(out_file, decompile_python=decompile_python, comparable=comparable, print_line_numbers=line_numbers, no_pyexpr=no_pyexpr).dump(ast) + AstDumper(out_file, decompile_python=decompile_python, comparable=comparable, no_pyexpr=no_pyexpr).dump(ast) class AstDumper(object): """ @@ -41,12 +41,11 @@ class AstDumper(object): MAP_CLOSE = {list: ']', tuple: ')', set: '}', frozenset: '})'} def __init__(self, out_file=None, decompile_python=False, no_pyexpr=False, - comparable=False, print_line_numbers=False, indentation=u' '): + comparable=False, indentation=u' '): self.indentation = indentation self.out_file = out_file or sys.stdout self.decompile_python = decompile_python self.comparable = comparable - self.print_line_numbers = print_line_numbers self.no_pyexpr = no_pyexpr def dump(self, ast): @@ -165,9 +164,7 @@ def should_print_key(self, ast, key): # Old versions of Ren'Py didn't have this attribute, and it's not # controllable from the source. return False - elif key != 'linenumber' and key != 'lineno': - return True - return self.print_line_numbers + return True def print_object(self, ast): # handles the printing of anything unknown which inherts from object. @@ -198,7 +195,7 @@ def print_object(self, ast): self.p('>') def print_pyexpr(self, ast): - if not self.no_pyexpr and (not self.comparable or self.print_line_numbers): + if not self.no_pyexpr: self.print_object(ast) self.p(' = ') self.print_string(ast) diff --git a/decompiler/screendecompiler.py b/decompiler/screendecompiler.py index 55e3fb55..6e1fe11e 100644 --- a/decompiler/screendecompiler.py +++ b/decompiler/screendecompiler.py @@ -35,7 +35,7 @@ def pprint(out_file, ast, indent_level=0, linenumber=1, decompile_python=False, line_numbers=False, skip_indent_until_write=False, printlock=None): return SLDecompiler(out_file, printlock=printlock, - decompile_python=decompile_python, match_line_numbers=line_numbers).dump( + decompile_python=decompile_python).dump( ast, indent_level, linenumber, skip_indent_until_write) # implementation @@ -50,8 +50,8 @@ class SLDecompiler(DecompilerBase): dispatch = Dispatcher() def __init__(self, out_file=None, decompile_python=False, - match_line_numbers=False, indentation=" ", printlock=None): - super(SLDecompiler, self).__init__(out_file, indentation, match_line_numbers, printlock) + indentation=" ", printlock=None): + super(SLDecompiler, self).__init__(out_file, indentation, printlock) self.decompile_python = decompile_python self.should_advance_to_line = True self.is_root = True @@ -79,11 +79,8 @@ def rollback_state(self, state): self.is_root = state[2] super(SLDecompiler, self).rollback_state(state[0]) - def to_source(self, node, correct_line_numbers=False): - return codegen.to_source(node, - self.indentation, - False, - self.match_line_numbers) + def to_source(self, node): + return codegen.to_source(node, self.indentation, False, True) @contextmanager def not_root(self): @@ -290,7 +287,7 @@ def print_buggy_keywords_and_nodes(self, keywords, nodes, needs_colon, has_block if lines_to_go >= self.get_lines_used_by_node(next_node): self.print_node(next_node[0], next_node[1:]) nodes_before_keywords.pop(0) - elif not self.match_line_numbers or not should_advance_to_line or lines_to_go <= 0: + elif not should_advance_to_line or lines_to_go <= 0: self.indent() self.write(remaining_keywords.pop(0)[1]) else: @@ -374,7 +371,7 @@ def print_python(self, header, code): lineno=code[0].lineno, col_offset=0)).rstrip().lstrip('\n') lines = source.splitlines() - if len(split_logical_lines(source)) == 1 and (not self.match_line_numbers or + if len(split_logical_lines(source)) == 1 and ( (not self.is_root and code[0].lineno < self.linenumber + 3) or header.lineno >= code[0].lineno): # This is only one logical line, so it's possible that it was $, diff --git a/decompiler/sl2decompiler.py b/decompiler/sl2decompiler.py index 95c735ba..4892fab4 100644 --- a/decompiler/sl2decompiler.py +++ b/decompiler/sl2decompiler.py @@ -33,8 +33,8 @@ # Main API def pprint(out_file, ast, indent_level=0, linenumber=1, - line_numbers=False, skip_indent_until_write=False, printlock=None): - return SL2Decompiler(out_file, match_line_numbers=line_numbers, printlock=printlock).dump( + skip_indent_until_write=False, printlock=None): + return SL2Decompiler(out_file, printlock=printlock).dump( ast, indent_level, linenumber, skip_indent_until_write) # Implementation diff --git a/decompiler/util.py b/decompiler/util.py index dfe32e14..537f6b92 100644 --- a/decompiler/util.py +++ b/decompiler/util.py @@ -4,10 +4,9 @@ from StringIO import StringIO class DecompilerBase(object): - def __init__(self, out_file=None, indentation=' ', match_line_numbers=False, printlock=None): + def __init__(self, out_file=None, indentation=' ', printlock=None): self.out_file = out_file or sys.stdout self.indentation = indentation - self.match_line_numbers = match_line_numbers self.skip_indent_until_write = False self.printlock = printlock @@ -73,7 +72,7 @@ def rollback_state(self, state): self.block_stack, self.index_stack, self.indent_level) = state def advance_to_line(self, linenumber): - if self.match_line_numbers and self.linenumber < linenumber: + if self.linenumber < linenumber: # Stop one line short, since the call to indent() will advance the last line. # Note that if self.linenumber == linenumber - 1, this will write the empty string. # This is to make sure that skip_indent_until_write is cleared in that case. diff --git a/unrpyc.py b/unrpyc.py index 3f5d8fa5..682db41f 100755 --- a/unrpyc.py +++ b/unrpyc.py @@ -61,7 +61,7 @@ def read_ast_from_file(in_file): return stmts def decompile_rpyc(input_filename, overwrite=False, dump=False, decompile_python=False, - comparable=False, line_numbers=False, no_pyexpr=False): + comparable=False, no_pyexpr=False): # Output filename is input filename but with .rpy extension filepath, ext = path.splitext(input_filename) out_filename = filepath + ('.txt' if dump else '.rpy') @@ -82,16 +82,16 @@ def decompile_rpyc(input_filename, overwrite=False, dump=False, decompile_python with codecs.open(out_filename, 'w', encoding='utf-8') as out_file: if dump: astdump.pprint(out_file, ast, decompile_python=decompile_python, comparable=comparable, - line_numbers=line_numbers, no_pyexpr=no_pyexpr) + no_pyexpr=no_pyexpr) else: - decompiler.pprint(out_file, ast, decompile_python=decompile_python, line_numbers=line_numbers, printlock=printlock) + decompiler.pprint(out_file, ast, decompile_python=decompile_python, printlock=printlock) return True def worker(t): (args, filename, filesize) = t try: return decompile_rpyc(filename, args.clobber, args.dump, decompile_python=args.decompile_python, no_pyexpr=args.no_pyexpr, - comparable=args.comparable, line_numbers=args.line_numbers) + comparable=args.comparable) except Exception as e: printlock.acquire() print traceback.format_exc() @@ -121,13 +121,7 @@ def main(): parser.add_argument('--comparable', dest='comparable', action='store_true', help="Only for dumping, remove several false differences when comparing dumps. " - "This suppresses attributes that are different even when the code is identical, such as file modification times. " - "Line numbers are also suppressed unless the --line-numbers option is used.") - - parser.add_argument('--line-numbers', dest='line_numbers', action='store_true', - help="Allow line numbers to be compared. " - "When decompiling, this causes extra lines to be printed to make line numbers match. " - "When dumping the ast, this causes line numbers to be printed even when using --comparable.") + "This suppresses attributes that are different even when the code is identical, such as file modification times. ") parser.add_argument('--no-pyexpr', dest='no_pyexpr', action='store_true', help="Only for dumping, disable special handling of PyExpr objects, instead printing them as strings. "