class Opal::Rewriters::ThrowerFinder

step, so we want to get that knowledge earlier.
want to track a closure. Tracking a closure is often a deoptimizing
compilation phase before traversing other nodes whether we
break, redo, so we can make an informed guess in the early
ThrowerFinder attempts to track the presence of throwers, like

def initialize

def initialize
  @break_stack = []
  @redo_stack = []
  @retry_stack = []
  @rescue_else_stack = []
end

def on_break(node)

def on_break(node)
  tracking(:break, @break_stack)
  super
end

def on_defined(node)

ignore throwers inside defined
def on_defined(node)
  pushing(
    [@redo_stack, nil],
    [@break_stack, nil],
    [@retry_stack, nil]
  ) { super }
end

def on_ensure(node)

rescue node.
ensure node should expect a rescue-else inside a
above a rescue. This logic is about tracking if a given
Otherwise we handle it in rescue. ensure is always
rescue. If ensure is present, we handle it in ensure.
In Opal we handle rescue-else either in ensure or in
def on_ensure(node)
  pushing([@rescue_else_stack, node]) { super }
end

def on_for(node); on_loop(node) { super }; end

def on_for(node);        on_loop(node) { super }; end

def on_iter(node)

def on_iter(node)
  pushing([@break_stack, node]) { super }
end

def on_loop(node, &block)

def on_loop(node, &block)
  pushing([@redo_stack, node], [@break_stack, nil], &block)
end

def on_redo(node)

def on_redo(node)
  tracking(:redo, @redo_stack)
  super
end

def on_rescue(node)

def on_rescue(node)
  if node.children[1..-1].detect { |sexp| sexp && sexp.type != :resbody }
    tracking(:rescue_else, @rescue_else_stack)
  end
  pushing([@rescue_else_stack, nil], [@retry_stack, node]) { super }
end

def on_retry(node)

def on_retry(node)
  tracking(:retry, @retry_stack)
  super
end

def on_until(node); on_loop(node) { super }; end

def on_until(node);      on_loop(node) { super }; end

def on_until_post(node); on_loop(node) { super }; end

def on_until_post(node); on_loop(node) { super }; end

def on_while(node); on_loop(node) { super }; end

def on_while(node);      on_loop(node) { super }; end

def on_while_post(node); on_loop(node) { super }; end

def on_while_post(node); on_loop(node) { super }; end

def pushing(*stacks)

def pushing(*stacks)
  stacks.each { |stack, node| stack.push(node) }
  result = yield
  stacks.map(&:first).each(&:pop)
  result
end

def tracking(breaker, stack)

def tracking(breaker, stack)
  stack.last.meta[:"has_#{breaker}"] = true if stack.last
end