Class: Opal::Nodes::CallNode

Inherits:
Base
  • Object
show all
Defined in:
opal/lib/opal/nodes/call.rb

Direct Known Subclasses

AttrAssignNode, JsAttrAssignNode, JsCallNode

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, Helpers::PROTO_SPECIAL_METHODS, Helpers::PROTO_SPECIAL_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, #ivar, #js_falsy, #js_truthy, #js_truthy_optimize, #line, #lvar_to_js, #mid_to_jsid, #property, #valid_ivar_name?, #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)


96
97
98
# File 'opal/lib/opal/nodes/call.rb', line 96

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

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

  default_compile
end

#compile_assignmentObject



109
110
111
112
113
114
115
116
117
118
119
120
# File 'opal/lib/opal/nodes/call.rb', line 109

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



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

def compile_default!
  @compile_default = true
end

#compile_default?Boolean

Returns:

  • (Boolean)


147
148
149
# File 'opal/lib/opal/nodes/call.rb', line 147

def compile_default?
  @compile_default
end

#compile_irb_varObject

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



101
102
103
104
105
106
107
# File 'opal/lib/opal/nodes/call.rb', line 101

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



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
87
88
89
90
# File 'opal/lib/opal/nodes/call.rb', line 43

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.



131
132
133
134
135
136
137
138
139
140
141
# File 'opal/lib/opal/nodes/call.rb', line 131

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

#record_method?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'opal/lib/opal/nodes/call.rb', line 39

def record_method?
  true
end

#recv_sexpObject



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

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)


124
125
126
# File 'opal/lib/opal/nodes/call.rb', line 124

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