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
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)
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?
- 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?
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