class Opal::Nodes::CallNode

def self.add_special(name, options = {}, &handler)

def self.add_special(name, options = {}, &handler)
  SPECIALS[name] = options
  define_method("handle_#{name}", &handler)
end

def auto_await?

def auto_await?
  awaited_set = compiler.async_await
  awaited_set && awaited_set != true && awaited_set.match?(meth.to_s)
end

def compile

def compile
  # handle some methods specially
  # some special methods need to skip compilation, so we pass the default as a block
  handle_special do
    compiler.method_calls << meth.to_sym if record_method?
    # if trying to access an lvar in eval or irb mode
    return compile_eval_var if using_eval?
    # if trying to access an lvar in irb mode
    return compile_irb_var if using_irb?
    default_compile
  end
end

def compile_arguments

def compile_arguments
  push ', '
  if splat?
    push expr(arglist)
  elsif arglist.children.empty?
    push '[]'
  else
    push '[', expr(arglist), ']'
  end
end

def compile_block_pass

def compile_block_pass
  if iter
    push ', ', expr(iter)
  end
end

def compile_break_catcher

def compile_break_catcher
  if iter_has_break?
    unshift 'return '
    unshift '(function(){var $brk = Opal.new_brk(); try {'
    line '} catch (err) { if (err === $brk) { return err.$v } else { throw err } }})()'
  end
end

def compile_eval_var

def compile_eval_var
  push meth.to_s
end

def compile_irb_var

Used to generate the code to use this sexp as an ivar var reference
def compile_irb_var
  with_temp do |tmp|
    lvar = meth
    call = s(:send, s(:self), meth.intern, s(:arglist))
    push "((#{tmp} = Opal.irb_vars.#{lvar}) == null ? ", expr(call), " : #{tmp})"
  end
end

def compile_method_name

def compile_method_name
  push ", '#{meth}'"
end

def compile_receiver

def compile_receiver
  push recv(receiver_sexp)
end

def compile_refinements

def compile_refinements
  refinements = scope.collect_refinements_temps.map { |i| s(:js_tmp, i) }
  push expr(s(:array, *refinements)), ', '
end

def compile_simple_call_chain

def compile_simple_call_chain
  push recv(receiver_sexp), method_jsid, '(', expr(arglist), ')'
end

def compile_using_refined_send


Opal.refined_send(a, 'b', [c], block, [[Opal.MyRefinements]])

a.b(c, &block)
@example

Compiles method call using `Opal.refined_send`
def compile_using_refined_send
  helper :refined_send
  push '$refined_send('
  compile_refinements
  compile_receiver
  compile_method_name
  compile_arguments
  compile_block_pass
  push ')'
end

def compile_using_send


Opal.send(a, 'b', [c], block)

a.b(c, &block)
@example

Compiles method call using `Opal.send`
def compile_using_send
  helper :send
  push '$send('
  compile_receiver
  compile_method_name
  compile_arguments
  compile_block_pass
  push ')'
end

def default_compile

def default_compile
  if auto_await?
    push 'await '
    scope.await_encountered = true
  end
  if invoke_using_refinement?
    compile_using_refined_send
  elsif invoke_using_send?
    compile_using_send
  else
    compile_simple_call_chain
  end
  compile_break_catcher
end

def handle_special(&compile_default)

to be generated by CallNode.
this method. If this method returns nil, then the method will continue
Handle "special" method calls, e.g. require(). Subclasses can override
def handle_special(&compile_default)
  if SPECIALS.include? meth
    method = method("handle_#{meth}")
    method.arity == 1 ? method[compile_default] : method[]
  else
    yield # i.e. compile_default.call
  end
end

def initialize(*)

def initialize(*)
  super
  @recvr, @meth, *args = *@sexp
  *rest, last_arg = *args
  if last_arg && %i[iter block_pass].include?(last_arg.type)
    @iter = last_arg
    args = rest
  else
    @iter = nil
  end
  @arglist = s(:arglist, *args)
end

def invoke_using_refinement?

def invoke_using_refinement?
  !scope.scope.collect_refinements_temps.empty?
end

def invoke_using_send?

Other tags:
    See: #compile_arguments -
def invoke_using_send?
  iter || splat?
end

def iter_has_break?

def iter_has_break?
  return false unless iter
  finder = Opal::Rewriters::BreakFinder.new
  finder.process(iter)
  finder.found_break?
end

def method_jsid

def method_jsid
  mid_to_jsid meth.to_s
end

def push_nesting?

def push_nesting?
  recv = children.first
  children.size == 2 && (           # only receiver and method
    recv.nil? || (                  # and no receiver
      recv.type == :const &&        # or receiver
      recv.children.last == :Module # is Module
    )
  )
end

def receiver_sexp

def receiver_sexp
  recvr || s(:self)
end

def record_method?

def record_method?
  true
end

def sexp_with_arglist

def sexp_with_arglist
  @sexp.updated(nil, [recvr, meth, arglist])
end

def splat?

def splat?
  arglist.children.any? { |a| a.type == :splat }
end

def using_eval?

def using_eval?
  @compiler.eval? && scope.top? && @compiler.scope_variables.include?(meth)
end

def using_irb?

or it might be a method call
a variable reference in irb mode in top scope might be a var ref,
def using_irb?
  @compiler.irb? && scope.top? && variable_like?
end

def using_refinement(arg)

def using_refinement(arg)
  prev, curr = *scope.refinements_temp
  if prev
    push "(#{curr} = #{prev}.slice(), #{curr}.push(", expr(arg), '), self)'
  else
    push "(#{curr} = [", expr(arg), '], self)'
  end
end

def variable_like?

def variable_like?
  arglist == s(:arglist) && recvr.nil? && iter.nil?
end