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)
def on_defined(node) pushing( [@redo_stack, nil], [@break_stack, nil], [@retry_stack, nil] ) { super } end
def on_ensure(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