def read_closure(settings, interps, heaps, pointer): try: if isinstance(pointer, Argument) or isinstance(pointer, CaseArgument) or isinstance(pointer, Offset) and isinstance(pointer.base, CasePointer): return if settings.opts.verbose: print("Found closure:") print(" Pointer:", show.show_pretty_pointer(settings, pointer)) if isinstance(pointer, StaticValue) and show.name_is_library(show.get_name_for_address(settings, pointer.value)): if settings.opts.verbose: print(" Library defined!") print() return info_pointer = ptrutil.dereference(settings, pointer, heaps, []).untagged assert isinstance(info_pointer, StaticValue) info_address = info_pointer.value info_type = info.read_closure_type(settings, info_address) if info_type[:11] == 'constructor': num_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*4) num_non_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*3) args = [] arg_pointer = ptrutil.make_tagged(settings, pointer)._replace(tag = 0) for i in range(num_ptrs + num_non_ptrs): arg_pointer = ptrutil.pointer_offset(settings, arg_pointer, settings.rt.word.size); args.append(ptrutil.dereference(settings, arg_pointer.untagged, heaps, [])) arg_pattern = 'p' * num_ptrs + 'n' * num_non_ptrs interps[pointer] = Apply(func = Pointer(info_pointer), func_type = 'constructor', args = interp_args(args, arg_pattern), pattern = arg_pattern) if settings.opts.verbose: print() for arg in args[:num_ptrs]: read_closure(settings, interps, arg.untagged) return elif info_type[:8] == 'function': arg_pattern = info.read_arg_pattern(settings, info_address) else: arg_pattern = '' if settings.opts.verbose: print() interps[pointer] = Pointer(info_pointer) read_function_thunk(settings, interps, heaps, info_address, ptrutil.make_tagged(settings, pointer)._replace(tag = len(arg_pattern)), arg_pattern) except: e_type, e_obj, e_tb = sys.exc_info() print("Error when processing closure at", show.show_pretty_pointer(settings, pointer)) print(" Error:", e_obj) print(" Error Location:", e_tb.tb_lineno) print(" No Disassembly Available") print()
def read_case(settings, interps, heaps, pointer, stack, scrutinee): try: if settings.opts.verbose: print("Found case inspection!") info_name = show.get_name_for_address(settings, pointer.value) if settings.opts.verbose: print(" Name:", show.demangle(info_name)) arms, tags, stacks, registers = gather_case_arms(settings, heaps, pointer.value, 1, settings.rt.word.size - 1, stack, { settings.rt.main_register: ptrutil.make_tagged(settings, Offset(base = CasePointer(inspection = pointer, matched_tag = DefaultTag()), index = 0)), settings.rt.stack_register: ptrutil.make_tagged(settings, Offset(base = StackPointer(), index = -len(stack))) }, stack, pointer, []) interp_arms = [] for arm, tag, stack, regs in zip(arms, tags, stacks, registers): if settings.opts.verbose: print() print("Found case arm:") print(" From case:", info_name) print(" Pattern:", tag) interp_arms.append(read_code(settings, interps, heaps, arm, stack, regs)) return Case(scrutinee = scrutinee, bound_ptr = pointer, arms = interp_arms, tags = tags) except: e_type, e_obj, e_tb = sys.exc_info() print("Error in processing case at", show.show_pretty_pointer(settings, pointer)) print(" Error:", e_obj) print(" Error Location:", e_tb.tb_lineno) print(" Disassembly:") for insn in disasm.disasm_from(settings, pointer.value): print(" " + show.show_instruction(insn)) print()
def read_case(settings, worklist, heaps, pointer, stack, scrutinee): try: if settings.opts.verbose: print("Found case inspection!") info_name = show.get_name_for_address(settings, pointer.value) if settings.opts.verbose: print(" Name:", show.demangle(info_name)) arms, tags, stacks, registers = gather_case_arms(settings, heaps, pointer.value, 1, settings.rt.word.size - 1, stack, { settings.rt.main_register: ptrutil.make_tagged(settings, Offset(base = CasePointer(inspection = pointer, matched_tag = DefaultTag()), index = 0)), settings.rt.stack_register: ptrutil.make_tagged(settings, Offset(base = StackPointer(), index = -len(stack))) }, stack, pointer, []) interp_arms = [] for arm, tag, stack, regs in zip(arms, tags, stacks, registers): if settings.opts.verbose: print() print("Found case arm:") print(" From case:", info_name) print(" Pattern:", tag) interp_arms.append(read_code(settings, worklist, heaps, arm, stack, regs)) return Case(scrutinee = scrutinee, bound_ptr = pointer, arms = interp_arms, tags = tags) except: e_type, e_obj, e_tb = sys.exc_info() print("Error in processing case at", show.show_pretty_pointer(settings, pointer)) print(" Error:", e_obj) print(" Error Location:", e_tb.tb_lineno) print(" Disassembly:") for insn in disasm.disasm_from(settings, pointer.value): print(" " + show.show_instruction(insn)) print() return UnknownInterpretation()
def run_worklist(settings, interps, worklist): while len(worklist) > 0: work = worklist.pop() if isinstance(work, ClosureWork): if settings.opts.verbose: print("Found closure:") print(" Pointer:", show.show_pretty_pointer(settings, work.pointer)) if isinstance(work.pointer, Argument) or isinstance( work.pointer, CaseArgument) or isinstance( work.pointer, Offset) and isinstance( work.pointer.base, CasePointer): if settings.opts.verbose: print(" Simple closure!") print() continue if isinstance(work.pointer, StaticValue) and show.name_is_library( show.get_name_for_address(settings, work.pointer.value)): if settings.opts.verbose: print(" Library defined!") print() continue interps[work.pointer] = parse.read_closure(settings, worklist, work.heaps, work.pointer) elif isinstance(work, FunctionThunkWork): if settings.opts.verbose: print("Found function/thunk!") print( " Name:", show.demangle( show.get_name_for_address(settings, work.address))) print(" Arg pattern:", work.arg_pattern) if StaticValue(value=work.address) in interps: if settings.opts.verbose: print(" Seen before!") print() continue if show.name_is_library( show.get_name_for_address(settings, work.address)): if settings.opts.verbose: print(" Library defined!") print() continue interps[StaticValue( value=work.address)] = parse.read_function_thunk( settings, worklist, work.heaps, work.address, work.main_register, work.arg_pattern) else: assert False, "bad work in worklist" if settings.opts.verbose: print()
def run_worklist(settings, interps, worklist): while len(worklist) > 0: work = worklist.pop() if isinstance(work, ClosureWork): if settings.opts.verbose: print("Found closure:") print(" Pointer:", show.show_pretty_pointer(settings, work.pointer)) if ( isinstance(work.pointer, Argument) or isinstance(work.pointer, CaseArgument) or isinstance(work.pointer, Offset) and isinstance(work.pointer.base, CasePointer) ): if settings.opts.verbose: print(" Simple closure!") print() continue if isinstance(work.pointer, StaticValue) and show.name_is_library( show.get_name_for_address(settings, work.pointer.value) ): if settings.opts.verbose: print(" Library defined!") print() continue interps[work.pointer] = parse.read_closure(settings, worklist, work.heaps, work.pointer) elif isinstance(work, FunctionThunkWork): if settings.opts.verbose: print("Found function/thunk!") print(" Name:", show.demangle(show.get_name_for_address(settings, work.address))) print(" Arg pattern:", work.arg_pattern) if StaticValue(value=work.address) in interps: if settings.opts.verbose: print(" Seen before!") print() continue if show.name_is_library(show.get_name_for_address(settings, work.address)): if settings.opts.verbose: print(" Library defined!") print() continue interps[StaticValue(value=work.address)] = parse.read_function_thunk( settings, worklist, work.heaps, work.address, work.main_register, work.arg_pattern ) else: assert False, "bad work in worklist" if settings.opts.verbose: print()
def read_closure(settings, worklist, heaps, pointer): try: info_pointer = ptrutil.dereference(settings, pointer, heaps, []).untagged assert isinstance(info_pointer, StaticValue) info_address = info_pointer.value info_type = info.read_closure_type(settings, info_address) if settings.opts.verbose: print(" Type:", info_type) if info_type[:11] == 'constructor': num_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*4) num_non_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*3) args = [] arg_pointer = ptrutil.make_tagged(settings, pointer)._replace(tag = 0) for i in range(num_ptrs + num_non_ptrs): arg_pointer = ptrutil.pointer_offset(settings, arg_pointer, settings.rt.word.size); args.append(ptrutil.dereference(settings, arg_pointer.untagged, heaps, [])) arg_pattern = 'p' * num_ptrs + 'n' * num_non_ptrs for arg in args[:num_ptrs]: worklist.append(ClosureWork(heaps = heaps, pointer = arg.untagged)) return Apply(func = Pointer(info_pointer), func_type = 'constructor', args = interp_args(args, arg_pattern), pattern = arg_pattern) elif info_type[:11] == 'indirection': tagged = ptrutil.make_tagged(settings, pointer)._replace(tag = 0) offset = ptrutil.pointer_offset(settings, tagged, settings.rt.word.size) new_ptr = ptrutil.dereference(settings, offset.untagged, heaps, []) if settings.opts.verbose: print() worklist.append(ClosureWork(heaps = heaps, pointer = new_ptr.untagged)) return Pointer(new_ptr.untagged) elif info_type[:8] == 'function': arg_pattern = info.read_arg_pattern(settings, info_address) else: arg_pattern = '' worklist.append(FunctionThunkWork(heaps = heaps, address = info_address, main_register = ptrutil.make_tagged(settings, pointer)._replace(tag = len(arg_pattern)), arg_pattern = arg_pattern)) return Pointer(info_pointer) except: e_type, e_obj, e_tb = sys.exc_info() print("Error when processing closure at", show.show_pretty_pointer(settings, pointer)) print(" Error:", e_obj) print(" Error Location:", e_tb.tb_lineno) print(" No Disassembly Available") print() return UnknownInterpretation()
def read_code(settings, interps, heaps, address, extra_stack, registers): try: instructions = disasm.disasm_from(settings, address) registers[settings.rt.heap_register] = ptrutil.make_tagged(settings, Offset(base = HeapPointer(id = len(heaps), owner = address), index = -1)) registers[settings.rt.stack_register] = ptrutil.make_tagged(settings, Offset(base = StackPointer(), index = -len(extra_stack))) mach = machine.Machine(settings, heaps, extra_stack, registers) mach.simulate(instructions) registers = mach.registers stack = mach.stack[registers[settings.rt.stack_register].untagged.index+len(mach.stack):] new_heaps = heaps + [mach.heap] if settings.opts.verbose: print(" Heap:", list(map(lambda h: show.show_pretty_value(settings, h), mach.heap))) print(" Stack:", list(map(lambda s: show.show_pretty_value(settings, s), stack))) if instructions[-1].operands[0].type == capstone.x86.X86_OP_MEM and machine.base_register(instructions[-1].operands[0].mem.base) == settings.rt.stack_register: if settings.opts.verbose: print(" Interpretation: return", show.show_pretty_value(settings, registers[settings.rt.main_register])) print() returned = registers[settings.rt.main_register].untagged interpretation = Pointer(returned) read_closure(settings, interps, new_heaps, returned) else: worklist = [] uses = [] if instructions[-1].operands[0].type == capstone.x86.X86_OP_MEM: assert machine.base_register(instructions[-1].operands[0].mem.base) == settings.rt.main_register assert instructions[-1].operands[0].mem.disp == 0 if settings.opts.verbose: print(" Interpretation: evaluate", show.show_pretty_value(settings, registers[settings.rt.main_register])) evaled = registers[settings.rt.main_register].untagged stack_index = 0 interpretation = Pointer(evaled) worklist.append({'type': 'closure', 'pointer': evaled}) elif instructions[-1].operands[0].type == capstone.x86.X86_OP_IMM: jmp_address = instructions[-1].operands[0].imm if jmp_address in settings.address_to_name and settings.address_to_name[jmp_address][:7] == 'stg_ap_': func = settings.address_to_name[jmp_address] if func.split('_')[2] == '0': arg_pattern = '' else: arg_pattern = func.split('_')[2] called = registers[settings.rt.main_register].untagged worklist.append({'type': 'closure', 'pointer': called}) func_type = 'closure' else: arg_pattern = info.read_arg_pattern(settings, jmp_address) called = StaticValue(value = jmp_address) worklist.append({'type': 'function/thunk', 'address': jmp_address, 'main-register': registers[settings.rt.main_register], 'arg-pattern': arg_pattern}) func_type = 'info' num_args = sum(1 for e in filter(lambda pat: pat != 'v', arg_pattern)) if settings.opts.verbose: print(" Number of non-void args:", num_args) print(" Called:", show.show_pretty_pointer(settings, called)) print(" Arg pattern:", arg_pattern) args = [] stack_index = num_args for reg, i in zip(settings.rt.arg_registers, range(num_args)): args.append(registers[reg]) stack_index -= 1 args += stack[:stack_index] if settings.opts.verbose: print(" Interpretation: call", show.show_pretty_pointer(settings, called), "on", list(map(lambda s: show.show_pretty_value(settings, s), args))) interpretation = Apply(func_type = func_type, func = Pointer(called), args = interp_args(args, arg_pattern), pattern = arg_pattern) for arg, pat in zip(args, arg_pattern): if pat == 'p': worklist.append({'type': 'closure', 'pointer': arg.untagged}) while stack_index < len(stack): assert isinstance(stack[stack_index].untagged, StaticValue) cont_name = show.get_name_for_address(settings, stack[stack_index].untagged.value) if cont_name[:7] == 'stg_ap_': assert cont_name[-5:] == '_info' arg_pattern = cont_name.split('_')[2] num_extra_args = sum(1 for e in filter(lambda pat: pat != 'v', arg_pattern)) if settings.opts.verbose: print(" then apply the result to", list(map(lambda s: show.show_pretty_value(settings, s), stack[stack_index+1:][:num_extra_args]))) interpretation = Apply(func_type = 'closure', func = interpretation, args = interp_args(stack[stack_index+1:][:num_extra_args], arg_pattern), pattern = arg_pattern) for arg in stack[stack_index+1:][:num_extra_args]: worklist.append({'type': 'closure', 'pointer': arg.untagged}) stack_index += 1 + num_extra_args elif cont_name == 'stg_upd_frame_info' or cont_name == 'stg_bh_upd_frame_info': if settings.opts.verbose: print(" then update the thunk at", show.show_pretty_value(settings, stack[stack_index + 1])) stack_index += 2 else: if settings.opts.verbose: print(" then inspect using", show.show_pretty_value(settings, stack[stack_index])) print() interpretation = read_case(settings, interps, new_heaps, stack[stack_index].untagged, stack[stack_index:], interpretation) stack_index = len(stack) if settings.opts.verbose: print() for work in worklist: if work['type'] == 'closure': read_closure(settings, interps, new_heaps, work['pointer']) elif work['type'] == 'function/thunk': read_function_thunk(settings, interps, new_heaps, work['address'], work['main-register'], work['arg-pattern']) else: assert False,"bad work in worklist" return interpretation except: e_type, e_obj, e_tb = sys.exc_info() print("Error in processing code at", show.show_pretty_address(settings, address)) print(" Error:", e_obj) print(" Error Location:", e_tb.tb_lineno) print(" Disassembly:") for insn in disasm.disasm_from(settings, address): print(" " + show.show_instruction(insn)) print()
def read_code(settings, worklist, heaps, address, extra_stack, registers): try: instructions = list(disasm.disasm_from(settings, address)) registers[settings.rt.heap_register] = ptrutil.make_tagged( settings, Offset(base=HeapPointer(id=len(heaps), owner=address), index=-1)) registers[settings.rt.stack_register] = ptrutil.make_tagged( settings, Offset(base=StackPointer(), index=-len(extra_stack))) mach = machine.Machine(settings, heaps, extra_stack, registers) mach.simulate(instructions) registers = mach.registers stack = mach.stack[registers[settings.rt.stack_register].untagged. index + len(mach.stack):] new_heaps = heaps + [mach.heap] if settings.opts.verbose: print( " Heap:", list( map(lambda h: show.show_pretty_value(settings, h), mach.heap))) print( " Stack:", list(map(lambda s: show.show_pretty_value(settings, s), stack))) if instructions[-1].operands[ 0].type == capstone.x86.X86_OP_MEM and machine.base_register( instructions[-1].operands[0].mem.base ) == settings.rt.stack_register: if settings.opts.verbose: print( " Interpretation: return", show.show_pretty_value( settings, registers[settings.rt.main_register])) returned = registers[settings.rt.main_register].untagged interpretation = Pointer(returned) worklist.append(ClosureWork(heaps=new_heaps, pointer=returned)) else: uses = [] if instructions[-1].operands[0].type == capstone.x86.X86_OP_MEM: assert machine.base_register(instructions[-1].operands[0].mem. base) == settings.rt.main_register assert instructions[-1].operands[0].mem.disp == 0 if settings.opts.verbose: print( " Interpretation: evaluate", show.show_pretty_value( settings, registers[settings.rt.main_register])) evaled = registers[settings.rt.main_register].untagged stack_index = 0 interpretation = Pointer(evaled) worklist.append(ClosureWork(heaps=new_heaps, pointer=evaled)) elif instructions[-1].operands[0].type == capstone.x86.X86_OP_IMM: jmp_address = instructions[-1].operands[0].imm if jmp_address in settings.address_to_name and settings.address_to_name[ jmp_address][:7] == 'stg_ap_': func = settings.address_to_name[jmp_address] if func.split('_')[2] == '0': arg_pattern = '' else: arg_pattern = func.split('_')[2] called = registers[settings.rt.main_register].untagged worklist.append( ClosureWork(heaps=new_heaps, pointer=called)) func_type = 'closure' else: arg_pattern = info.read_arg_pattern(settings, jmp_address) called = StaticValue(value=jmp_address) worklist.append( FunctionThunkWork( heaps=new_heaps, address=jmp_address, main_register=registers[settings.rt.main_register], arg_pattern=arg_pattern)) func_type = 'info' num_args = sum( 1 for e in filter(lambda pat: pat != 'v', arg_pattern)) if settings.opts.verbose: print(" Number of non-void args:", num_args) print(" Called:", show.show_pretty_pointer(settings, called)) print(" Arg pattern:", arg_pattern) args = [] stack_index = num_args for reg, i in zip(settings.rt.arg_registers, range(num_args)): args.append(registers[reg]) stack_index -= 1 args += stack[:stack_index] if settings.opts.verbose: print( " Interpretation: call", show.show_pretty_pointer(settings, called), "on", list( map(lambda s: show.show_pretty_value(settings, s), args))) interpretation = Apply(func_type=func_type, func=Pointer(called), args=interp_args(args, arg_pattern), pattern=arg_pattern) for arg, pat in zip(args, arg_pattern): if pat == 'p': worklist.append( ClosureWork(heaps=new_heaps, pointer=arg.untagged)) while stack_index < len(stack): assert isinstance(stack[stack_index].untagged, StaticValue) cont_name = show.get_name_for_address( settings, stack[stack_index].untagged.value) if cont_name[:7] == 'stg_ap_': assert cont_name[-5:] == '_info' arg_pattern = cont_name.split('_')[2] num_extra_args = sum( 1 for e in filter(lambda pat: pat != 'v', arg_pattern)) if settings.opts.verbose: print( " then apply the result to", list( map( lambda s: show.show_pretty_value( settings, s), stack[stack_index + 1:][:num_extra_args]))) interpretation = Apply(func_type='closure', func=interpretation, args=interp_args( stack[stack_index + 1:][:num_extra_args], arg_pattern), pattern=arg_pattern) for arg in stack[stack_index + 1:][:num_extra_args]: worklist.append( ClosureWork(heaps=new_heaps, pointer=arg.untagged)) stack_index += 1 + num_extra_args elif cont_name == 'stg_upd_frame_info' or cont_name == 'stg_bh_upd_frame_info': if settings.opts.verbose: print( " then update the thunk at", show.show_pretty_value(settings, stack[stack_index + 1])) stack_index += 2 else: if settings.opts.verbose: print( " then inspect using", show.show_pretty_value(settings, stack[stack_index])) print() interpretation = read_case(settings, worklist, new_heaps, stack[stack_index].untagged, stack[stack_index:], interpretation) stack_index = len(stack) if settings.opts.verbose: print() return interpretation except: e_type, e_obj, e_tb = sys.exc_info() print("Error in processing code at", show.show_pretty_address(settings, address)) print(" Error:", e_obj) print(" Error Location:", e_tb.tb_lineno) print(" Disassembly:") for insn in disasm.disasm_from(settings, address): print(" " + show.show_instruction(insn)) print() return UnknownInterpretation()
def main(): arg_parser = argparse.ArgumentParser( description='Decompile a GHC-compiled Haskell program.') arg_parser.add_argument('file') arg_parser.add_argument('entry', default='Main_main_closure', nargs='?') arg_parser.add_argument('--ignore-strictness', action='store_true', dest='ignore_strictness') arg_parser.add_argument('--apply-functions', action='store_true', dest='apply_functions') arg_parser.add_argument('--no-inline-once', action='store_false', dest='inline_once') arg_parser.add_argument('--inline-constructors', action='store_true', dest='inline_constructors') arg_parser.add_argument('--show-types', action='store_true', dest='show_types') arg_parser.add_argument('--no-abbreviate-library-names', action='store_false', dest='abbreviate_library_names') arg_parser.add_argument('--verbose', action='store_true', dest='verbose') opts = arg_parser.parse_args() settings = metadata.read_settings(opts) # Parse the binary entry_pointer = StaticValue(value=settings.name_to_address[opts.entry]) interpretations = {} run_worklist(settings, interpretations, [ClosureWork(heaps=[], pointer=entry_pointer)]) # Analyze the inferred code for type information to make case statements clearer types = {} for ptr in interpretations: infer.infer_type_for(settings, interpretations, types, ptr) infer.run_rename_tags(settings, interpretations, types) # Clean things up for human consumption optimize.run_destroy_empty_apply(interpretations) if opts.ignore_strictness: optimize.run_destroy_strictness(interpretations) interpretations = optimize.run_delete_unused(interpretations, entry_pointer) optimize.run_inline_cheap(interpretations) if opts.inline_once: optimize.run_inline_once(interpretations) if opts.inline_constructors: optimize.run_inline_constructors(interpretations) if opts.apply_functions: optimize.run_apply_functions(interpretations) # Display our parsed file function_worklist = [entry_pointer] seen = {} while len(function_worklist) > 0: worklist = [function_worklist.pop()] started = False while len(worklist) > 0: pointer = worklist.pop() if pointer in seen or not pointer in interpretations: continue else: if len(seen) > 0 and not started: print() seen[pointer] = None started = True pretty = show.show_pretty_pointer(settings, pointer) lhs = pretty if settings.opts.show_types and pointer in types: sys.stdout.write(pretty) sys.stdout.write("::") sys.stdout.write( show.show_pretty_type(settings, types[pointer], False)) print("") sys.stdout.write(lhs) sys.stdout.write("=") sys.stdout.write( show.show_pretty_interpretation(settings, interpretations[pointer])) print("") optimize.foreach_use( interpretations[pointer], lambda ptr: (function_worklist if ptr in interpretations and isinstance( interpretations[ptr], Lambda) else worklist).append(ptr))
def main(): arg_parser = argparse.ArgumentParser(description="Decompile a GHC-compiled Haskell program.") arg_parser.add_argument("file") arg_parser.add_argument("entry", default="Main_main_closure", nargs="?") arg_parser.add_argument("--ignore-strictness", action="store_true", dest="ignore_strictness") arg_parser.add_argument("--apply-functions", action="store_true", dest="apply_functions") arg_parser.add_argument("--no-inline-once", action="store_false", dest="inline_once") arg_parser.add_argument("--inline-constructors", action="store_true", dest="inline_constructors") arg_parser.add_argument("--show-types", action="store_true", dest="show_types") arg_parser.add_argument("--no-abbreviate-library-names", action="store_false", dest="abbreviate_library_names") arg_parser.add_argument("--verbose", action="store_true", dest="verbose") opts = arg_parser.parse_args() settings = metadata.read_settings(opts) # Parse the binary entry_pointer = StaticValue(value=settings.name_to_address[opts.entry]) interpretations = {} run_worklist(settings, interpretations, [ClosureWork(heaps=[], pointer=entry_pointer)]) # Analyze the inferred code for type information to make case statements clearer types = {} for ptr in interpretations: infer.infer_type_for(settings, interpretations, types, ptr) infer.run_rename_tags(settings, interpretations, types) # Clean things up for human consumption optimize.run_destroy_empty_apply(interpretations) if opts.ignore_strictness: optimize.run_destroy_strictness(interpretations) interpretations = optimize.run_delete_unused(interpretations, entry_pointer) optimize.run_inline_cheap(interpretations) if opts.inline_once: optimize.run_inline_once(interpretations) if opts.inline_constructors: optimize.run_inline_constructors(interpretations) if opts.apply_functions: optimize.run_apply_functions(interpretations) # Display our parsed file function_worklist = [entry_pointer] seen = {} while len(function_worklist) > 0: worklist = [function_worklist.pop()] started = False while len(worklist) > 0: pointer = worklist.pop() if pointer in seen or not pointer in interpretations: continue else: if len(seen) > 0 and not started: print() seen[pointer] = None started = True pretty = show.show_pretty_pointer(settings, pointer) lhs = pretty if settings.opts.show_types and pointer in types: print(pretty, "::", show.show_pretty_type(settings, types[pointer], False)) print(lhs, "=", show.show_pretty_interpretation(settings, interpretations[pointer])) optimize.foreach_use( interpretations[pointer], lambda ptr: ( function_worklist if ptr in interpretations and isinstance(interpretations[ptr], Lambda) else worklist ).append(ptr), )