class Opal::Nodes::EnsureNode

def body_sexp

def body_sexp
  if wrap_in_closure?
    compiler.returns(begn)
  else
    begn
  end
end

def compile

def compile
  push_closure if wrap_in_closure?
  push 'try {'
  in_ensure do
    line stmt(body_sexp)
  end
  line '} finally {'
  indent do
    if has_rescue_else?
      # $no_errors indicates thate there were no error raised
      unshift 'var $no_errors = true; '
      # when there's a begin;rescue;else;ensure;end statement,
      # ruby returns a result of the 'else' branch
      # but invokes it before 'ensure'.
      # so, here we
      # 1. save the result of calling else to $rescue_else_result
      # 2. call ensure
      # 2. return $rescue_else_result
      line 'var $rescue_else_result;'
      line 'if ($no_errors) { '
      indent do
        line '$rescue_else_result = (function() {'
        indent do
          line stmt(rescue_else_code)
        end
        line '})();'
      end
      line '}'
      line compiler.process(ensr_sexp, @level)
      line 'if ($no_errors) { return $rescue_else_result; }'
    else
      line compiler.process(ensr_sexp, @level)
    end
  end
  line '}'
  pop_closure if wrap_in_closure?
  if wrap_in_closure?
    if scope.await_encountered
      wrap '(await (async function() { ', '; })())'
    else
      wrap '(function() { ', '; })()'
    end
  end
end

def ensr_sexp

def ensr_sexp
  ensr || s(:nil)
end

def has_rescue_else?

def has_rescue_else?
  @sexp.meta[:has_rescue_else]
end

def rescue_else_code

def rescue_else_code
  rescue_else_code = scope.rescue_else_sexp
  rescue_else_code = compiler.returns(rescue_else_code) unless stmt?
  rescue_else_code
end

def wrap_in_closure?

def wrap_in_closure?
  recv? || expr? || has_rescue_else?
end