class CodeTools::AST::Ensure

Attributes

body[RW]
ensure[RW]

Public Class Methods

new(line, body, ensr) click to toggle source
# File lib/rubinius/code/ast/exceptions.rb, line 31
def initialize(line, body, ensr)
  @line = line
  @body = body || NilLiteral.new(line)
  @ensure = ensr
end

Public Instance Methods

bytecode(g) click to toggle source
# File lib/rubinius/code/ast/exceptions.rb, line 37
def bytecode(g)
  pos(g)

  ok = g.new_label
  ex = g.new_label
  g.setup_unwind ex, EnsureType

  # TODO: ?
  g.new_label.set!

  g.push_exception_state
  outer_exc_state = g.new_stack_local
  g.set_stack_local outer_exc_state
  g.pop

  old_break = g.break
  new_break = g.new_label
  g.break = new_break

  old_next = g.next
  new_next = g.new_label
  g.next = new_next

  g.state.push_ensure
  @body.bytecode(g)
  g.state.pop_ensure

  g.break = old_break
  g.next = old_next

  g.pop_unwind
  g.goto ok

  check_break = nil

  if new_break.used?
    used_break_local = g.new_stack_local
    check_break = g.new_label

    new_break.set!
    g.pop_unwind

    g.push_true
    g.set_stack_local used_break_local
    g.pop

    g.goto check_break
  end

  check_next = nil

  if new_next.used?
    used_next_local = g.new_stack_local
    check_next = g.new_label

    new_next.set!
    g.pop_unwind

    g.push_true
    g.set_stack_local used_next_local
    g.pop

    g.goto check_next
  end

  ex.set!

  g.push_exception_state

  g.state.push_inside_ensure
  g.state.push_rescue(outer_exc_state)
  @ensure.bytecode(g)
  g.state.pop_rescue
  g.pop

  g.restore_exception_state

  # Re-raise the exception
  g.reraise

  # There is no mapping to the original source here, so
  # reflect that in the lines table to try and make it
  # more accurate.
  g.set_line 0

  ok.set!

  if check_break
    g.push_false
    g.set_stack_local used_break_local
    g.pop

    check_break.set!
  end

  if check_next
    g.push_false
    g.set_stack_local used_next_local
    g.pop

    check_next.set!
  end

  # Now, re-emit the code for the ensure which will run if there was no
  # exception generated.
  @ensure.bytecode(g)
  g.pop

  if check_break
    post = g.new_label

    g.push_stack_local used_break_local
    g.goto_if_false post

    if g.break
      g.goto g.break
    else
      g.raise_break
    end
    post.set!
  end

  if check_next
    post = g.new_label

    g.push_stack_local used_next_local
    g.goto_if_false post

    g.next ? g.goto(g.next) : g.ret
    post.set!
  end
  g.state.pop_inside_ensure
end
to_sexp() click to toggle source
# File lib/rubinius/code/ast/exceptions.rb, line 171
def to_sexp
  [:ensure, @body.to_sexp, @ensure.to_sexp]
end