class Opal::Rewriters::ThrowerFinder

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

Public Class Methods

new() click to toggle source
# File lib/opal/rewriters/thrower_finder.rb, line 12
def initialize
  @break_stack = []
  @redo_stack = []
  @retry_stack = []
  @rescue_else_stack = []
end

Public Instance Methods

on_break(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 19
def on_break(node)
  tracking(:break, @break_stack)
  super
end
on_defined(node) click to toggle source

ignore throwers inside defined

Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 49
def on_defined(node)
  pushing(
    [@redo_stack, nil],
    [@break_stack, nil],
    [@retry_stack, nil]
  ) { super }
end
on_ensure(node) click to toggle source

In Opal we handle rescue-else either in ensure or in rescue. If ensure is present, we handle it in ensure. Otherwise we handle it in rescue. ensure is always above a rescue. This logic is about tracking if a given ensure node should expect a rescue-else inside a rescue node.

Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 63
def on_ensure(node)
  pushing([@rescue_else_stack, node]) { super }
end
on_for(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 42
def on_for(node);        on_loop(node) { super }; end
on_iter(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 34
def on_iter(node)
  pushing([@break_stack, node]) { super }
end
on_loop(node, &block) click to toggle source
# File lib/opal/rewriters/thrower_finder.rb, line 38
def on_loop(node, &block)
  pushing([@redo_stack, node], [@break_stack, nil], &block)
end
on_redo(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 24
def on_redo(node)
  tracking(:redo, @redo_stack)
  super
end
on_rescue(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 67
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
on_retry(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 29
def on_retry(node)
  tracking(:retry, @retry_stack)
  super
end
on_until(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 45
def on_until(node);      on_loop(node) { super }; end
on_until_post(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 46
def on_until_post(node); on_loop(node) { super }; end
on_while(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 43
def on_while(node);      on_loop(node) { super }; end
on_while_post(node) click to toggle source
Calls superclass method
# File lib/opal/rewriters/thrower_finder.rb, line 44
def on_while_post(node); on_loop(node) { super }; end

Private Instance Methods

pushing(*stacks) { || ... } click to toggle source
# File lib/opal/rewriters/thrower_finder.rb, line 77
def pushing(*stacks)
  stacks.each { |stack, node| stack.push(node) }
  result = yield
  stacks.map(&:first).each(&:pop)
  result
end
tracking(breaker, stack) click to toggle source
# File lib/opal/rewriters/thrower_finder.rb, line 84
def tracking(breaker, stack)
  stack.last.meta[:"has_#{breaker}"] = true if stack.last
end