class SyntaxTree::YARV::Bf

into YARV bytecode.
Parses the given source code into a syntax tree, compiles that syntax tree

def change_by(iseq, value)

$tape[$cursor] += value
def change_by(iseq, value)
  iseq.getglobal(:$tape)
  iseq.getglobal(:$cursor)
  iseq.getglobal(:$tape)
  iseq.getglobal(:$cursor)
  iseq.send(YARV.calldata(:[], 1))
  if value < 0
    iseq.putobject(-value)
    iseq.send(YARV.calldata(:-, 1))
  else
    iseq.putobject(value)
    iseq.send(YARV.calldata(:+, 1))
  end
  iseq.send(YARV.calldata(:[]=, 2))
  iseq.pop
end

def compile

def compile
  # Set up the top-level instruction sequence that will be returned.
  iseq = InstructionSequence.new("<compiled>", "<compiled>", 1, :top)
  # Set up the $tape global variable that will hold our state.
  iseq.duphash({ 0 => 0 })
  iseq.setglobal(:$tape)
  iseq.getglobal(:$tape)
  iseq.putobject(0)
  iseq.send(YARV.calldata(:default=, 1))
  # Set up the $cursor global variable that will hold the current position
  # in the tape.
  iseq.putobject(0)
  iseq.setglobal(:$cursor)
  stack = []
  source
    .each_char
    .chunk do |char|
      # For each character, we're going to assign a type to it. This
      # allows a couple of optimizations to be made by combining multiple
      # instructions into single instructions, e.g., +++ becomes a single
      # change_by(3) instruction.
      case char
      when "+", "-"
        :change
      when ">", "<"
        :shift
      when "."
        :output
      when ","
        :input
      when "[", "]"
        :loop
      else
        :ignored
      end
    end
    .each do |type, chunk|
      # For each chunk, we're going to emit the appropriate instruction.
      case type
      when :change
        change_by(iseq, chunk.count("+") - chunk.count("-"))
      when :shift
        shift_by(iseq, chunk.count(">") - chunk.count("<"))
      when :output
        chunk.length.times { output_char(iseq) }
      when :input
        chunk.length.times { input_char(iseq) }
      when :loop
        chunk.each do |char|
          case char
          when "["
            stack << loop_start(iseq)
          when "]"
            loop_end(iseq, *stack.pop)
          end
        end
      end
    end
  iseq.leave
  iseq.compile!
  iseq
end

def initialize(source)

def initialize(source)
  @source = source
end

def input_char(iseq)

$tape[$cursor] = $stdin.getc.ord
def input_char(iseq)
  iseq.getglobal(:$tape)
  iseq.getglobal(:$cursor)
  iseq.getglobal(:$stdin)
  iseq.send(YARV.calldata(:getc))
  iseq.send(YARV.calldata(:ord))
  iseq.send(YARV.calldata(:[]=, 2))
  iseq.pop
end

def loop_end(iseq, start_label, end_label)

Jump back to the start of the loop.
def loop_end(iseq, start_label, end_label)
  iseq.getglobal(:$tape)
  iseq.getglobal(:$cursor)
  iseq.send(YARV.calldata(:[], 1))
  iseq.putobject(0)
  iseq.send(YARV.calldata(:==, 1))
  iseq.branchunless(start_label)
  iseq.push(end_label)
end

def loop_start(iseq)

unless $tape[$cursor] == 0
def loop_start(iseq)
  start_label = iseq.label
  end_label = iseq.label
  iseq.push(start_label)
  iseq.getglobal(:$tape)
  iseq.getglobal(:$cursor)
  iseq.send(YARV.calldata(:[], 1))
  iseq.putobject(0)
  iseq.send(YARV.calldata(:==, 1))
  iseq.branchif(end_label)
  [start_label, end_label]
end

def output_char(iseq)

$stdout.putc($tape[$cursor].chr)
def output_char(iseq)
  iseq.getglobal(:$stdout)
  iseq.getglobal(:$tape)
  iseq.getglobal(:$cursor)
  iseq.send(YARV.calldata(:[], 1))
  iseq.send(YARV.calldata(:chr))
  iseq.send(YARV.calldata(:putc, 1))
  iseq.pop
end

def shift_by(iseq, value)

$cursor += value
def shift_by(iseq, value)
  iseq.getglobal(:$cursor)
  if value < 0
    iseq.putobject(-value)
    iseq.send(YARV.calldata(:-, 1))
  else
    iseq.putobject(value)
    iseq.send(YARV.calldata(:+, 1))
  end
  iseq.setglobal(:$cursor)
end