require 'continuation'

class GoToProc
  def initialize(&b)
    @proc, @labels, @first_run = b, {}, true
    self.run
    @first_run = false
  end

  def run
    callcc do |k|
      @exit = k
      self.instance_eval &@proc
    end
  end

  def label(x)
    callcc { |cont| @labels[x] = cont }
    yield unless @first_run
  end

  def goto(x)
    @labels[x].call()
  end

  def exit
    @exit.call()
  end
end

factorial = GoToProc.new do
  label(1) { @x, @f = 10, 1 }
  label(2) { goto 5 if @x == 1 }
  label(3) { @f *= @x; @x -= 1 }
  label(4) { goto 2 }
  label(5) { puts "factorial = #{@f}" }
  label(6) { exit }
end

factorial.run