Class: Opal::Nodes::CallNode

Inherits:
Base show all
Defined in:
opal/lib/opal/nodes/call.rb,
opal/lib/mspec/opal/special_calls.rb

Direct Known Subclasses

AttrAssignNode

Defined Under Namespace

Classes: DependencyResolver

Constant Summary

SPECIALS =
{}
OPERATORS =

Operators that get optimized by compiler

{ :+ => :plus, :- => :minus, :* => :times, :/ => :divide,
:< => :lt, :<= => :le, :> => :gt, :>= => :ge }

Constants included from Helpers

Helpers::BASIC_IDENTIFIER_RULES, Helpers::ES3_RESERVED_WORD_EXCLUSIVE, Helpers::ES51_RESERVED_WORD, Helpers::IMMUTABLE_PROPS

Instance Attribute Summary

Attributes inherited from Base

#compiler, #type

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#add_gvar, #add_ivar, #add_local, #add_temp, children, #children, #compile_to_fragments, #error, #expr, #expr?, #expr_or_nil, #fragment, handle, handlers, #helper, #in_while?, #initialize, #process, #push, #recv, #recv?, #s, #scope, #stmt, #stmt?, #unshift, #while_loop, #with_temp, #wrap

Methods included from Helpers

#current_indent, #empty_line, #indent, #js_falsy, #js_truthy, #js_truthy_optimize, #line, #lvar_to_js, #mid_to_jsid, #property, #valid_name?, #variable

Constructor Details

This class inherits a constructor from Opal::Nodes::Base

Class Method Details

.add_special(name, options = {}, &handler) ⇒ Object



19
20
21
22
# File 'opal/lib/opal/nodes/call.rb', line 19

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

Instance Method Details

#attr_assignment?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'opal/lib/opal/nodes/call.rb', line 92

def attr_assignment?
  @assignment ||= meth.to_s =~ /#{REGEXP_START}[\da-z]+\=#{REGEXP_END}/i
end

#compileObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'opal/lib/opal/nodes/call.rb', line 24

def compile
  # handle some methods specially
  handle_special

  # some special methods need to skip compilation
  return unless compile_default?

  compiler.method_calls << meth.to_sym

  # if trying to access an lvar in irb mode
  return compile_irb_var if using_irb?

  default_compile
end

#compile_assignmentObject



105
106
107
108
109
110
111
112
113
114
115
116
# File 'opal/lib/opal/nodes/call.rb', line 105

def compile_assignment
  with_temp do |args_tmp|
    with_temp do |recv_tmp|
      args = expr(arglist)
      mid = mid_to_jsid meth.to_s
      push "((#{args_tmp} = [", args, "]), "+
           "#{recv_tmp} = ", recv(recv_sexp), ", ",
           recv_tmp, mid, ".apply(#{recv_tmp}, #{args_tmp}), "+
           "#{args_tmp}[#{args_tmp}.length-1])"
    end
  end
end

#compile_default!Object



139
140
141
# File 'opal/lib/opal/nodes/call.rb', line 139

def compile_default!
  @compile_default = true
end

#compile_default?Boolean

Returns:

  • (Boolean)


143
144
145
# File 'opal/lib/opal/nodes/call.rb', line 143

def compile_default?
  @compile_default
end

#compile_irb_varObject

Used to generate the code to use this sexp as an ivar var reference



97
98
99
100
101
102
103
# File 'opal/lib/opal/nodes/call.rb', line 97

def compile_irb_var
  with_temp do |tmp|
    lvar = variable(meth)
    call = s(:call, s(:self), meth.intern, s(:arglist))
    push "((#{tmp} = Opal.irb_vars.#{lvar}) == null ? ", expr(call), " : #{tmp})"
  end
end

#default_compileObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'opal/lib/opal/nodes/call.rb', line 39

def default_compile

  mid = mid_to_jsid meth.to_s

  splat = arglist[1..-1].any? { |a| a.first == :splat }

  if Sexp === arglist.last and arglist.last.type == :block_pass
    block = arglist.pop
  elsif iter
    block = iter
  end

  blktmp  = scope.new_temp if block
  tmprecv = scope.new_temp if splat || blktmp

  # must do this after assigning temp variables
  block = expr(block) if block

  recv_code = recv(recv_sexp)
  call_recv = s(:js_tmp, tmprecv || recv_code)

  if blktmp and !splat
    arglist.insert 1, call_recv
  end

  args = expr(arglist)

  if tmprecv
    push "(#{tmprecv} = ", recv_code, ")#{mid}"
  else
    push recv_code, mid
  end

  if blktmp
    unshift "(#{blktmp} = "
    push ", #{blktmp}.$$p = ", block, ", #{blktmp})"
  end

  if splat
    push ".apply(", (tmprecv || recv_code), ", ", args, ")"
  elsif blktmp
    push ".call(", args, ")"
  else
    push "(", args, ")"
  end

  scope.queue_temp blktmp if blktmp
end

#handle_specialObject

Handle "special" method calls, e.g. require(). Subclasses can override this method. If this method returns nil, then the method will continue to be generated by CallNode.



127
128
129
130
131
132
133
134
135
136
137
# File 'opal/lib/opal/nodes/call.rb', line 127

def handle_special
  @compile_default = true

  if SPECIALS.include? meth
    @compile_default = false
    __send__("handle_#{meth}")
  elsif RuntimeHelpers.compatible?(recvr, meth, arglist)
    @compile_default = false
    push(RuntimeHelpers.new(@sexp, @level, @compiler).compile)
  end
end

#recv_sexpObject



88
89
90
# File 'opal/lib/opal/nodes/call.rb', line 88

def recv_sexp
  recvr || s(:self)
end

#using_irb?Boolean

a variable reference in irb mode in top scope might be a var ref, or it might be a method call

Returns:

  • (Boolean)


120
121
122
# File 'opal/lib/opal/nodes/call.rb', line 120

def using_irb?
  @compiler.irb? and scope.top? and arglist == s(:arglist) and recvr.nil? and iter.nil?
end