Class: KBS::Decompiler

Inherits:
Object
  • Object
show all
Defined in:
lib/kbs/decompiler.rb

Overview

Reconstruct Ruby source from YARV bytecode.

YARV bytecode is a stack machine. We simulate the stack, translating instructions back into Ruby expressions.

Usage:

KBS::Decompiler.new(some_proc).decompile       # => "proc { |x| x + 1 }"
KBS::Decompiler.new(some_lambda).decompile      # => "->(x) { x + 1 }"
KBS::Decompiler.new(some_proc).decompile_block   # => "{ |x| x + 1 }"

Instance Method Summary collapse

Constructor Details

#initialize(proc_obj) ⇒ Decompiler

Returns a new instance of Decompiler.



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/kbs/decompiler.rb', line 15

def initialize(proc_obj)
  @iseq  = RubyVM::InstructionSequence.of(proc_obj)
  @arr   = @iseq.to_a
  @locals = @arr[10]          # [:a, :b, ...]
  @params = @arr[11]          # {lead_num: 2, ...}
  @body   = @arr[13]          # [1, :EVENT, [:instruction, ...], ...]
  @children = []
  @iseq.each_child { |c| @children << c }
  @child_index = 0
  @lambda = proc_obj.lambda?
end

Instance Method Details

#decompileObject



27
28
29
30
31
32
33
34
35
# File 'lib/kbs/decompiler.rb', line 27

def decompile
  expr = decompile_body(@body)
  params = build_params
  if @lambda
    "->(#{params}) { #{expr} }"
  else
    "proc { |#{params}| #{expr} }"
  end
end

#decompile_blockObject

Returns just the block literal: { |params| body } Useful when the surrounding keyword (perform, satisfies, etc.) is supplied by the caller.



40
41
42
43
44
45
46
47
48
# File 'lib/kbs/decompiler.rb', line 40

def decompile_block
  expr = decompile_body(@body)
  params = build_params
  if params.empty?
    "{ #{expr} }"
  else
    "{ |#{params}| #{expr} }"
  end
end