Class: Java::OrgJrubyAst::CallNode

Inherits:
Object
  • Object
show all
Defined in:
lib/duby/old/compiler_old.rb,
lib/duby/old/declaration.rb,
lib/duby/old/typer_old.rb,
lib/duby/old/signature.rb,
lib/duby/old/mapper.rb

Instance Method Summary collapse

Instance Method Details

#compile(builder) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/duby/old/compiler_old.rb', line 110

def compile(builder)
  receiver_type = receiver_node.type(builder)
  
  if receiver_type.primitive?
    # we're performing an operation against a primitive, map it accordingly
    log "Compiling #{name} at #{position.start_line} as primitive op"
    compile_primitive(receiver_type, builder)
  elsif receiver_type.array?
    log "Compiling #{name} at #{position.start_line} as array op"
    compile_array(receiver_type, builder)
  else
    case name
    when "new"
      log "Compiling #{name} at #{position.start_line} as object instantiation"
      compile_new(receiver_type, builder)
    else
      log "Compiling #{name} at #{position.start_line} as call"
      compile_call(receiver_type, builder)
    end
  end
end

#compile_args(builder) ⇒ Object



158
159
160
161
162
163
164
# File 'lib/duby/old/compiler_old.rb', line 158

def compile_args(builder)
  args_list = args_node.child_nodes.to_a
  args_list.each_index do |idx|
    node = args_list[idx]
    node.compile(builder)
  end
end

#compile_array(type, builder) ⇒ Object



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/duby/old/compiler_old.rb', line 294

def compile_array(type, builder)
  receiver_node.compile(builder)

  case name
  when "length"
    if args_node
      raise CompileError.new(position, "Array length does not take an argument")
    end
    
    builder.arraylength
  when "[]"
    if !args_node || args_node.size != 1
      raise CompileError.new(position, "Array accessignment must have exactly one argument")
    end

    node = args_node.get(0)
    # TODO: check or cast to int for indexing
    node.compile(builder)
    
    if type.component_type.primitive?
      case type.component_type
      when Jboolean, Jbyte
        builder.baload
      when Jchar
        builder.caload
      when Jshort
        builder.saload
      when Jint
        builder.iaload
      when Jlong
        builder.laload
      when Jfloat
        builder.faload
      when Jdouble
        builder.daload
      end
    else
      builder.aaload
    end
  when "[]="
    if !args_node || args_node.size != 2
      raise CompileError.new(position, "Array assignment must have exactly two arguments")
    end

    # TODO: check or cast to int for indexing
    args_node.get(0).compile(builder)
    # TODO: check type matches?
    args_node.get(1).compile(builder)
    
    builder.aastore
  else
    raise CompileError.new(position, "Array operation #{name} not supported")
  end
end

#compile_call(receiver_type, builder) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/duby/old/compiler_old.rb', line 132

def compile_call(receiver_type, builder)
  case receiver_node
  when ConstNode
    # static call
    static = true
  else
    receiver_node.compile(builder)
  end

  # I removed this because inference is working...but will it be needed under some circumstances?
#          # inefficient to cast every time; better inference will help
#          builder.checkcast(receiver_type)

  compile_args(builder)

  if static
    builder.invokestatic receiver_type, mapped_name(builder), signature(builder)
  else
    if (receiver_type.interface?)
      builder.invokeinterface receiver_type, mapped_name(builder), signature(builder)
    else
      builder.invokevirtual receiver_type, mapped_name(builder), signature(builder)
    end
  end
end

#compile_new(type, builder) ⇒ Object



349
350
351
352
353
354
355
356
# File 'lib/duby/old/compiler_old.rb', line 349

def compile_new(type, builder)
  builder.new type
  builder.dup
  
  compile_args(builder)
  
  builder.invokespecial type, mapped_name(builder), signature(builder)
end

#compile_primitive(type, builder) ⇒ Object



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
220
221
222
223
224
225
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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/duby/old/compiler_old.rb', line 166

def compile_primitive(type, builder)
  receiver_node.compile(builder)

  if !args_node
    case type
    when Jboolean, Jbyte, Jshort, Jchar
      # TODO: cast and do the same as int
      raise CompileError.new(position, "Unary primitive operations on #{type} not supported")
    when Jint
      case name
      when "-@"
        builder.ineg
      when "+@"
        # do nothing
      else
        raise CompileError.new(position, "Primitive int operation #{name} not supported")
      end
    when Jlong
      case name
      when "-@"
        builder.lneg
      when "+@"
        # do nothing
      else
        raise CompileError.new(position, "Primitive long operation #{name} not supported")
      end
    when Jfloat
      case name
      when "-@"
        builder.fneg
      when "+@"
        # do nothing
      else
        raise CompileError.new(position, "Primitive float operation #{name} not supported")
      end
    when Jdouble
      case name
      when "-@"
        builder.dneg
      when "+@"
        # do nothing
      else
        raise CompileError.new(position, "Primitive double operation #{name} not supported")
      end
    else
      raise CompileError.new(position, "Unary primitive operations on #{type} not supported")
    end
  elsif args_node.size != 1
    raise CompileError.new(position, "Binary primitive operations require exactly one argument")
  else
    node = args_node.get(0)
    # TODO: check or cast types according to receiver's type
    node.compile(builder)

    case type
    when Jboolean, Jbyte, Jshort, Jchar
      # TODO: cast and do the same as int
      raise CompileError.new(position, "Binary primitive operations on #{type} not supported")
    when Jint
      case name
      when "+"
        builder.iadd
      when "-"
        builder.isub
      when "/"
        builder.idiv
      when "*"
        builder.imul
      when "&"
        builder.iand
      when "|"
        builder.ior
      when "^"
        builder.ixor
      else
        raise CompileError.new(position, "Primitive int operation #{name} not supported")
      end
    when Jlong
      case name
      when "+"
        builder.ladd
      when "-"
        builder.lsub
      when "/"
        builder.ldiv
      when "*"
        builder.lmul
      when "&"
        builder.land
      when "|"
        builder.lor
      when "^"
        builder.lxor
      else
        raise CompileError.new(position, "Primitive long operation #{name} not supported")
      end
    when Jfloat
      case name
      when "+"
        builder.fadd
      when "-"
        builder.fsub
      when "/"
        builder.fdiv
      when "*"
        builder.fmul
      else
        raise CompileError.new(position, "Primitive float operation #{name} not supported")
      end
    when Jdouble
      case name
      when "+"
        builder.dadd
      when "-"
        builder.dsub
      when "/"
        builder.ddiv
      when "*"
        builder.dmul
      else
        raise CompileError.new(position, "Primitive double operation #{name} not supported")
      end
    else
      raise CompileError.new(position, "Primitive #{type} operations not supported")
    end
  end
end

#declared_type(builder) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/duby/old/declaration.rb', line 9

def declared_type(builder)
  if name == "[]"
    # array type, top should be a constant; find the rest
    array = true
    elements = []
  else
    elements = [name]
  end
  
  receiver = receiver_node
  
  loop do
    case receiver
    when ConstNode
      elements << receiver_node.name
      break
    when CallNode
      elements.unshift(receiver.name)
      receiver = receiver.receiver_node
    when SymbolNode
      elements.unshift(receiver.name)
      break
    when VCallNode
      elements.unshift(receiver.name)
      break
    end
  end
  
  # join and load
  class_name = elements.join(".")
  type = builder.type(class_name)
  
  if array
    type.array_class
  else
    type
  end
end

#mapped_name(builder) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/duby/old/mapper.rb', line 9

def mapped_name(builder)
  # TODO move to a utility somewhere for smart name mappings
  # TODO or at least make it a table...
  mapped_name = name
  case receiver_node.type(builder)
  when JString
    case name
    when "+"
      mapped_name = "concat"
    # This doesn't work yet, because format is a static method on String
#            when "%"
#              mapped_name = "format"
    end
  else
    case name
    when "new"
      mapped_name = "<init>"
    end
  end
  
  mapped_name
end

#signature(builder) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/duby/old/signature.rb', line 9

def signature(builder)
  arg_types = []
  args_node.child_nodes.each do |node|
    arg_types << node.type(builder)
  end if args_node
  
  recv_java_class = receiver_node.type(builder)
  declared_method = recv_java_class.declared_method_smart(mapped_name(builder), *arg_types)
  return_type = declared_method.return_type
  
  if (return_type)
    return_class = builder.type(return_type.to_s)
  else
    return_type = Void
  end
  
  return [
    return_class,
    *declared_method.parameter_types.map {|type| builder.type(type.to_s)}
  ]
end

#type(builder) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/duby/old/typer_old.rb', line 26

def type(builder)
  @return_type ||= begin
    recv_type = receiver_node.type(builder)
    
    # if we already have an exact class, use it
    if recv_type.array?
      if name == "length"
        Jint
      else
        recv_type = recv_type.component_type
      end
    elsif JavaClass === recv_type
      recv_type
    else
      # otherwise, find the target method and get its return type
      recv_java_class = recv_type
      arg_types = []
      args_node.child_nodes.each do |node|
        arg_types << node.type(builder)
      end if args_node
      declared_method = recv_java_class.declared_method_smart(mapped_name(builder), *arg_types)
      return_type = declared_method.return_type

      builder.type(return_type.to_s)
    end
  end
end