Class: Mirah::AST::Call

Inherits:
Node
  • Object
show all
Includes:
Named, Scoped
Defined in:
lib/mirah/ast/call.rb,
lib/mirah/compiler/call.rb,
lib/mirah/jvm/source_generator/precompile.rb

Direct Known Subclasses

Colon2

Instance Attribute Summary collapse

Attributes included from Named

#name

Attributes inherited from Node

#children, #inferred_type, #newline, #parent, #position

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Scoped

#containing_scope, #scope

Methods included from Named

#string_value, #to_s, #validate_name

Methods inherited from Node

#<<, ===, #[], #[]=, #_dump, _load, #_set_parent, child, child_name, #child_nodes, #each, #empty?, #inferred_type!, #initialize_copy, #insert, #inspect, #inspect_children, #line_number, #log, #precompile, #resolve_if, #resolved!, #resolved?, #simple_name, #string_value, #temp, #to_s, #top_level?, #validate_child, #validate_children

Constructor Details

#initialize(parent, line_number, name, &kids) ⇒ Call

Returns a new instance of Call.



139
140
141
142
# File 'lib/mirah/ast/call.rb', line 139

def initialize(parent, line_number, name, &kids)
  super(parent, line_number, &kids)
  self.name = name
end

Instance Attribute Details

#castObject Also known as: cast?

Returns the value of attribute cast.



127
128
129
# File 'lib/mirah/ast/call.rb', line 127

def cast
  @cast
end

#inlinedObject

Returns the value of attribute inlined.



127
128
129
# File 'lib/mirah/ast/call.rb', line 127

def inlined
  @inlined
end

#proxyObject

Returns the value of attribute proxy.



127
128
129
# File 'lib/mirah/ast/call.rb', line 127

def proxy
  @proxy
end

Class Method Details

.new(*args, &block) ⇒ Object



134
135
136
137
# File 'lib/mirah/ast/call.rb', line 134

def self.new(*args, &block)
  real_node = super
  real_node.proxy = NodeProxy.new(real_node)
end

Instance Method Details

#argumentsObject



154
155
156
157
158
159
160
# File 'lib/mirah/ast/call.rb', line 154

def arguments
  args = java.util.ArrayList.new(parameters.size)
  parameters.each do |param|
    args.add(param)
  end
  args
end

#compile(compiler, expression) ⇒ Object



28
29
30
31
32
33
# File 'lib/mirah/compiler/call.rb', line 28

def compile(compiler, expression)
  compiler.line(line_number)
  compiler.call(self, expression)
rescue Exception => ex
  raise Mirah::InternalCompilerError.wrap(ex, self)
end

#expr?(compiler) ⇒ Boolean

Returns:



92
93
94
95
96
97
98
# File 'lib/mirah/jvm/source_generator/precompile.rb', line 92

def expr?(compiler)
  target.expr?(compiler) &&
      parameters.all? {|p| p.expr?(compiler)} &&
      cast || (
        !method.return_type.kind_of?(Mirah::AST::InlineCode) &&
        !method.return_type.void?)
end

#infer(typer, expression) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/mirah/ast/call.rb', line 162

def infer(typer, expression)
  unless @inferred_type
    receiver_type = typer.infer(target, true)
    should_defer = receiver_type.nil?
    parameter_types = parameters.map do |param|
      typer.infer(param, true) || should_defer = true
    end

    parameter_types << Mirah::AST.block_type if block

    unless should_defer
      class_name, array = self.type_name(true)
      if class_name && parameters.size == 1 && typer.known_type(scope, class_name)
        # Support casts to fully-qualified names and inner classes.
        begin
          type = inferred_type = typer.type_reference(scope, class_name, array)
          @inferred_type = type unless (type && type.error?)
          if @inferred_type
            # cast operation
            resolved!
            self.cast = true
            return @inferred_type
          end
        rescue
        end
      end
      @inferred_type = typer.method_type(receiver_type, name,
                                         parameter_types)
      if @inferred_type.kind_of? InlineCode
        @inlined = @inferred_type.inline(typer.transformer, self)
        proxy.__inline__(@inlined)
        return proxy.infer(typer, expression)
      end
    end

    if @inferred_type
      if block && !receiver_type.error?
        method = receiver_type.get_method(name, parameter_types)
        block.prepare(typer, method)
      end
      @inferred_type = receiver_type if @inferred_type.void?
      resolved!
    else
      if should_defer
        message = nil
      else
        parameter_names = parameter_types.map {|t| t.full_name}.join(', ')
        receiver = receiver_type.full_name
        desc = "#{name}(#{parameter_names})"
        kind = receiver_type.meta? ? "static" : "instance"
        message = "Cannot find #{kind} method #{desc} on #{receiver}"
      end
      typer.defer(proxy, message)
    end
  end

  @inferred_type
end

#method(compiler = nil) ⇒ Object



85
86
87
88
89
90
# File 'lib/mirah/jvm/source_generator/precompile.rb', line 85

def method(compiler=nil)
  @method ||= begin
    arg_types = parameters.map {|p| p.inferred_type}
    target.inferred_type.get_method(name, arg_types)
  end
end

#precompile_target(compiler) ⇒ Object



100
101
102
103
104
105
106
# File 'lib/mirah/jvm/source_generator/precompile.rb', line 100

def precompile_target(compiler)
  if method.return_type.void? && target.expr?(compiler)
    TempValue.new(target, compiler)
  else
    target.precompile(compiler)
  end
end

#type_name(force = false) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/mirah/ast/call.rb', line 226

def type_name(force=false)
  if !force && parameters && !parameters.empty?
    return nil
  end
  if name == "[]"
    # array type, top should be a constant; find the rest
    array = true
    elements = []
  else
    array = false
    elements = [name]
  end
  old_receiver = nil
  receiver = self.target
  while !receiver.eql?(old_receiver)
    old_receiver = receiver
    case receiver
    when Constant, Local, Annotation
      elements.unshift(receiver.name)
    when FunctionalCall
      if receiver.parameters.nil? || receiver.parameters.empty?
        elements.unshift(receiver.name)
      else
        return nil, nil
      end
    when Call
      if receiver.parameters.nil? || receiver.parameters.empty?
        elements.unshift(receiver.name)
        receiver = receiver.target
      else
        return nil, nil
      end
    when String
      elements.unshift(receiver.literal)
    end
  end

  return elements.join("."), array
end

#type_reference(typer) ⇒ Object



221
222
223
224
# File 'lib/mirah/ast/call.rb', line 221

def type_reference(typer)
  class_name, array = type_name
  typer.type_reference(scope, class_name, array)
end

#validate_parametersObject



144
145
146
147
148
149
150
151
152
# File 'lib/mirah/ast/call.rb', line 144

def validate_parameters
  parameters.each_with_index do |child, i|
    if UnquotedValue === child
      child = child.node
      child.parent = self
      parameters[i] = child
    end
  end
end