module Opal::Nodes::Closure::NodeSupport

def thrower(type, value = nil)

def thrower(type, value = nil)
  case type
  when :return
    thrower_closure = select_closure(DEF, break_after: MODULE | TOP)
    last_closure = select_closure(JS_FUNCTION)
    if !thrower_closure
      iter_closure = select_closure(ITER, break_after: DEF | MODULE | TOP)
      if iter_closure
        generate_thrower_without_catcher(:return, iter_closure, value)
      elsif compiler.eval?
        push 'Opal.t_eval_return.$throw(', expr_or_nil(value), ', false)'
      else
        error 'Invalid return'
      end
    elsif thrower_closure == last_closure
      push 'return ', expr_or_nil(value)
    else
      id = generate_thrower(:return, thrower_closure, value)
      # Additionally, register our thrower on the surrounding iter, if present
      iter_closure = select_closure(ITER, break_after: DEF | MODULE | TOP)
      iter_closure.register_thrower(:return, id) if iter_closure
    end
  when :eval_return
    thrower_closure = select_closure(DEF | LAMBDA, break_after: MODULE | TOP)
    if thrower_closure
      thrower_closure.register_catcher(:eval_return)
    end
  when :next, :redo
    thrower_closure = select_closure(ITER | LOOP_INSIDE, break_after: DEF | MODULE | TOP)
    last_closure = select_closure(JS_FUNCTION | JS_LOOP_INSIDE)
    if !thrower_closure
      error 'Invalid next'
    elsif thrower_closure == last_closure
      if thrower_closure.is? LOOP_INSIDE
        push 'continue'
      elsif thrower_closure.is? ITER | LAMBDA
        push 'return ', expr_or_nil(value)
      end
    else
      generate_thrower(:next, thrower_closure, value)
    end
  when :break
    thrower_closure = select_closure(SEND | LAMBDA | LOOP, break_after: DEF | MODULE | TOP)
    last_closure = select_closure(JS_FUNCTION | JS_LOOP)
    if !thrower_closure
      iter_closure = select_closure(ITER, break_after: DEF | MODULE | TOP)
      if iter_closure
        generate_thrower_without_catcher(:break, iter_closure, value)
      else
        error 'Invalid break'
      end
    elsif thrower_closure == last_closure
      if thrower_closure.is? JS_FUNCTION | LAMBDA
        push 'return ', expr_or_nil(value)
      elsif thrower_closure.is? LOOP
        push 'break'
      end
    else
      generate_thrower(:break, thrower_closure, value)
    end
  when :retry
    thrower_closure = select_closure(RESCUE_RETRIER, break_after: DEF | MODULE | TOP)
    last_closure = select_closure(JS_LOOP_INSIDE)
    if !thrower_closure
      error 'Invalid retry'
    elsif thrower_closure == last_closure
      push 'continue'
    else
      generate_thrower(:retry, thrower_closure, value)
    end
  end
end