<commit_before>##
# reversal.rb: Reverser dispatcher for different types of decompilable code.
# 
#
# Copyright 2010 <NAME>, <EMAIL>
#
# MIT License, see LICENSE file in gem package

module Reversal
  class Reverser
    OPERATOR_LOOKUP = {:opt_plus => "+", :opt_minus => "-", :opt_mult => "*", :opt_div => "/",
                       :opt_mod => "%", :opt_eq => "==", :opt_neq => "!=", :opt_lt => "<",
                       :opt_le => "<=", :opt_gt => ">", :opt_ge => ">=", :opt_ltlt => "<<",
                       :opt_regexpmatch2 => "=~"}
                       
    # Instructions module depends on OPERATOR_LOOKUP
    include Instructions
    
    TAB_SIZE = 2          
    ALL_INFIX = OPERATOR_LOOKUP.values + ["<=>"]
    attr_accessor :locals, :parent, :indent
    
    def initialize(iseq, parent=nil)
      @iseq = ISeq.new(iseq)
      @iseq.validate!
      
      @parent = parent
      @locals = (@iseq.locals + [:self]).reverse
      reset!
    end
    
    def reset!
      @output = []
      @indent ||= 0
      
      @current_line = 0
      @stack = []
      @else_stack = []
      @end_stack  = []
    end
    
    def indent!
      @indent += TAB_SIZE
    end
    
    def outdent!
      @indent = [0, @indent - TAB_SIZE].max
    end

    def indent_size
      TAB_SIZE
    end
    
    ##
    # Gets a local variable at the given bytecode-style index
    def get_local(idx)
      get_dynamic(idx, 0)
    end
    
    ##
    # Gets a dynamic variable, based on the bytecode-style index and
    # the depth
    def get_dynamic(idx, depth)
      if depth == 0
        @locals[idx - 1]
      elsif @parent
        @parent.get_dynamic(idx, depth - 1)
      else
        raise "Invalid dynamic variable requested: #{idx} #{depth} from #{self.iseq}"
      end
    end 
    
    ##
    # Pushes a node onto the stack, as a decompiled string
    def push(str)
      @stack.push str
    end
    
    ##
    # Pops a node from the stack, as a decompiled string
    def pop(n = 1)
      if @stack.empty?
        raise "Popped an empty stack"
      elsif n == 1
        @stack.pop
      else
        popn(n)
      end
    end
    
    def popn(n = 1)
      (1..n).to_a.map {pop}.reverse
    end
    
    def string_wrap(string, left, right = left)
      "#{left}#{string}#{right}"
    end
    
    # include specific modules for different reversal techniques
    def decompile
      reset!
      # dispatch on the iseq type

      result = self.__send__("decompile_#{@iseq.type}".to_sym, @iseq) do
        decompile_body @iseq
      end
      @output.join("\n")
      result.map {|x| x.to_s}.join("\n")
    end
    
    def indented
      indent!
      yield
      outdent!
    end

    def indent_array(arr)
      arr.map {|x| (" " * indent) + x.to_s}
    end
    
    def decompile_block(iseq)
      args = iseq.argstring
      args = string_wrap(args, "|") if iseq.stats[:arg_size] > 0
      result = [" do #{args}"]
      indented do
        result.concat indent_array(yield iseq)
      end
      result << "end"
    end
    
    def decompile_method(iseq)
      args = iseq.argstring
      args = string_wrap(args, "(", ")") if iseq.stats[:arg_size] > 0
      result = ["def #{iseq.name}#{args}"]
      indented do
        result.concat((yield iseq).map {|x| (" "*@indent) + x.to_s})
      end
      result << "end"
    end
    
    ##
    # If it's just top-level code, then there are no args - just decompile
    # the body straight away
    def decompile_top(iseq)
      yield iseq
    end<commit_msg>Fixed indentation errors, back down to 1 test failure.<commit_after>##
# reversal.rb: Reverser dispatcher for different types of decompilable code.
# 
#
# Copyright 2010 <NAME>, <EMAIL>
#
# MIT License, see LICENSE file in gem package

module Reversal
  class Reverser
    OPERATOR_LOOKUP = {:opt_plus => "+", :opt_minus => "-", :opt_mult => "*", :opt_div => "/",
                       :opt_mod => "%", :opt_eq => "==", :opt_neq => "!=", :opt_lt => "<",
                       :opt_le => "<=", :opt_gt => ">", :opt_ge => ">=", :opt_ltlt => "<<",
                       :opt_regexpmatch2 => "=~"}
                       
    # Instructions module depends on OPERATOR_LOOKUP
    include Instructions
    
    TAB_SIZE = 2          
    ALL_INFIX = OPERATOR_LOOKUP.values + ["<=>"]
    attr_accessor :locals, :parent, :indent
    
    def initialize(iseq, parent=nil)
      @iseq = ISeq.new(iseq)
      @iseq.validate!
      
      @parent = parent
      @locals = [:self] + @iseq.locals.reverse
      reset!
    end
    
    def reset!
      @indent ||= 0
      
      @stack = []
      @else_stack = []
      @end_stack  = []
    end
    
    def indent!
      @indent += TAB_SIZE
    end
    
    def outdent!
      @indent = [0, @indent - TAB_SIZE].max
    end

    def indent_size
      TAB_SIZE
    end
    
    ##
    # Gets a local variable at the given bytecode-style index
    def get_local(idx)
      get_dynamic(idx, 0)
    end
    
    ##
    # Gets a dynamic variable, based on the bytecode-style index and
    # the depth
    def get_dynamic(idx, depth)
      if depth == 0
        @locals[idx - 1]
      elsif @parent
        @parent.get_dynamic(idx, depth - 1)
      else
        raise "Invalid dynamic variable requested: #{idx} #{depth} from #{self.iseq}"
      end
    end 
    
    ##
    # Pushes a node onto the stack, as a decompiled string
    def push(str)
      @stack.push str
    end
    
    ##
    # Pops a node from the stack, as a decompiled string
    def pop(n = 1)
      if @stack.empty?
        raise "Popped an empty stack"
      elsif n == 1
        @stack.pop
      else
        popn(n)
      end
    end
    
    def popn(n = 1)
      (1..n).to_a.map {pop}.reverse
    end
    
    def string_wrap(string, left, right = left)
      "#{left}#{string}#{right}"
    end
    
    # include specific modules for different reversal techniques
    def decompile
      reset!
      # dispatch on the iseq type

      result = self.__send__("decompile_#{@iseq.type}".to_sym, @iseq) do
        decompile_body @iseq
      end
      result.map {|x| x.to_s}.join("\n")
    end
    
    def indented
      indent!
      yield
      outdent!
    end

    def indent(str)
      (" " * @indent) + str.to_s
    end

    def indent_array(arr)
      arr.map {|x| indent x}
    end
    
    def decompile_block(iseq)
      args = iseq.argstring
      args = "|#{args}|" if iseq.stats[:arg_size] > 0
      result = [" do #{args}"]
      indented do
        result.concat indent_array(yield iseq)
      end
      result << indent("end")
    end
    
    def decompile_method(iseq)
      args = iseq.argstring
      args = "(#{args})" if iseq.stats[:arg_size] > 0
      result = ["def #{iseq.name}#{args}"]
      indented do
        result.concat indent_array(yield iseq)
      end
      result << indent("end")
    end
    
    ##
    # If it's just top-level code, then there are no args - just decompile
    # the body straight away
    def decompile_top(iseq)
      yield iseq
    end
{'fraction_non_alphanumeric': 0.1232018231021222, 'fraction_numerical': 0.005412334425295542, 'mean_word_length': 1.8498376623376624, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5490766', 'n_tokens_mistral': 2407, 'n_tokens_neox': 2337, 'n_words': 620}