class SyntaxTree::YARV::Bf

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