mirah 0.1.2-java → 0.1.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +225 -0
  3. data/Rakefile +108 -315
  4. data/TODO.md +100 -0
  5. data/bin/bundler +16 -0
  6. data/bin/rake +16 -0
  7. data/dist/mirahc.jar +0 -0
  8. data/examples/appengine/Readme +0 -1
  9. data/examples/literals.mirah +17 -0
  10. data/examples/macros/string_each_char.mirah +1 -1
  11. data/lib/mirah.rb +11 -21
  12. data/lib/mirah/transform/transformer.rb +1 -2
  13. data/lib/mirah/util/class_loader.rb +1 -1
  14. data/lib/mirah/util/logging.rb +0 -63
  15. data/lib/mirah/util/process_errors.rb +1 -0
  16. data/lib/mirah/version.rb +1 -1
  17. data/{examples/simple_class.mirah~ → test/artifacts/jar_test.rb} +7 -11
  18. data/{lib/mirah/commands.rb → test/artifacts/jruby_test.rb} +8 -5
  19. data/test/core/typer_test.rb +29 -11
  20. data/test/core/util/argument_processor_test.rb +24 -23
  21. data/test/core/util/class_loader_test.rb +7 -4
  22. data/test/core/util/{compilation_state_test.rb → jvm_version_test.rb} +20 -16
  23. data/test/fixtures/org/foo/ImplicitClassRetAnno.java +4 -0
  24. data/test/fixtures/org/foo/IntAnno.java +9 -0
  25. data/test/jvm/annotations_test.rb +11 -11
  26. data/test/jvm/blocks_test.rb +16 -12
  27. data/test/jvm/constructors_test.rb +8 -8
  28. data/test/jvm/enumerable_test.rb +48 -24
  29. data/test/jvm/generics_test.rb +3 -7
  30. data/test/jvm/import_test.rb +14 -0
  31. data/test/jvm/interface_test.rb +9 -24
  32. data/test/jvm/jvm_commands_test.rb +22 -4
  33. data/test/jvm/jvm_compiler_test.rb +124 -79
  34. data/test/jvm/list_extensions_test.rb +1 -1
  35. data/test/jvm/macros_test.rb +67 -14
  36. data/test/jvm/main_method_test.rb +1 -1
  37. data/test/jvm/new_backend_test_helper.rb +100 -3
  38. data/{lib/mirah/jvm/types/bitescript_ext.rb → test/jvm/static_fields_test.rb} +22 -21
  39. data/test/mirrors/base_type_test.rb +4 -3
  40. data/test/mirrors/bytecode_mirror_test.rb +35 -15
  41. data/test/mirrors/generics_test.rb +14 -5
  42. data/test/mirrors/member_test.rb +2 -1
  43. data/test/mirrors/method_lookup_test.rb +18 -6
  44. data/test/mirrors/mirrors_test.rb +87 -20
  45. data/test/mirrors/simple_async_mirror_loader_test.rb +7 -3
  46. data/test/mirrors/simple_mirror_loader_test.rb +5 -5
  47. data/test/test_helper.rb +25 -1
  48. metadata +18 -78
  49. data/bin/mirahp +0 -27
  50. data/bin/mirahp.cmd +0 -16
  51. data/examples/Fib.class +0 -0
  52. data/javalib/mirah-bootstrap.jar +0 -0
  53. data/javalib/mirah-builtins.jar +0 -0
  54. data/javalib/mirah-compiler.jar +0 -0
  55. data/javalib/mirah-mirrors.jar +0 -0
  56. data/javalib/mirah-newast-transitional.jar +0 -0
  57. data/javalib/mirah-parser.jar +0 -0
  58. data/javalib/mirah-util.jar +0 -0
  59. data/lib/mirah/ast.rb +0 -43
  60. data/lib/mirah/ast/scope.rb +0 -262
  61. data/lib/mirah/commands/base.rb +0 -59
  62. data/lib/mirah/commands/compile.rb +0 -39
  63. data/lib/mirah/commands/parse.rb +0 -36
  64. data/lib/mirah/commands/run.rb +0 -78
  65. data/lib/mirah/generator.rb +0 -150
  66. data/lib/mirah/jvm/compiler.rb +0 -50
  67. data/lib/mirah/jvm/compiler/base.rb +0 -421
  68. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +0 -1194
  69. data/lib/mirah/jvm/method_lookup.rb +0 -307
  70. data/lib/mirah/jvm/types.rb +0 -45
  71. data/lib/mirah/jvm/types/array_type.rb +0 -60
  72. data/lib/mirah/jvm/types/ast_ext.rb +0 -31
  73. data/lib/mirah/jvm/types/basic_types.rb +0 -41
  74. data/lib/mirah/jvm/types/block_type.rb +0 -15
  75. data/lib/mirah/jvm/types/boolean.rb +0 -70
  76. data/lib/mirah/jvm/types/enumerable.rb +0 -80
  77. data/lib/mirah/jvm/types/extensions.rb +0 -110
  78. data/lib/mirah/jvm/types/factory.rb +0 -830
  79. data/lib/mirah/jvm/types/floats.rb +0 -99
  80. data/lib/mirah/jvm/types/generic_type.rb +0 -72
  81. data/lib/mirah/jvm/types/implicit_nil_type.rb +0 -29
  82. data/lib/mirah/jvm/types/integers.rb +0 -131
  83. data/lib/mirah/jvm/types/interface_definition.rb +0 -20
  84. data/lib/mirah/jvm/types/intrinsics.rb +0 -385
  85. data/lib/mirah/jvm/types/literals.rb +0 -89
  86. data/lib/mirah/jvm/types/meta_type.rb +0 -54
  87. data/lib/mirah/jvm/types/methods.rb +0 -946
  88. data/lib/mirah/jvm/types/null_type.rb +0 -39
  89. data/lib/mirah/jvm/types/number.rb +0 -184
  90. data/lib/mirah/jvm/types/primitive_type.rb +0 -76
  91. data/lib/mirah/jvm/types/source_mirror.rb +0 -274
  92. data/lib/mirah/jvm/types/type.rb +0 -311
  93. data/lib/mirah/jvm/types/type_definition.rb +0 -72
  94. data/lib/mirah/jvm/types/void_type.rb +0 -19
  95. data/lib/mirah/util/compilation_state.rb +0 -60
  96. data/test/core/commands_test.rb +0 -89
  97. data/test/core/generator_test.rb +0 -26
  98. data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
  99. data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
  100. data/test/jvm/bytecode_test_helper.rb +0 -193
  101. data/test/jvm/factory_test.rb +0 -28
  102. data/test/jvm/java_typer_test.rb +0 -283
@@ -1,1194 +0,0 @@
1
- require 'mirah/jvm/types/ast_ext'
2
-
3
- module Mirah
4
- module JVM
5
- module Compiler
6
- class JVMBytecode < Base
7
- java_import java.lang.System
8
- java_import java.io.PrintStream
9
- include Mirah::JVM::MethodLookup
10
- include Mirah::Logging::Logged
11
- Types = Mirah::JVM::Types
12
- java_import 'mirah.lang.ast.Node'
13
- java_import 'mirah.lang.ast.Array'
14
- java_import 'mirah.lang.ast.Annotation'
15
- java_import 'mirah.lang.ast.MethodDefinition'
16
- java_import 'mirah.lang.ast.ConstructorDefinition'
17
- java_import 'mirah.lang.ast.Ensure'
18
- java_import 'mirah.lang.ast.Call'
19
- java_import 'mirah.lang.ast.Loop'
20
- java_import 'mirah.lang.ast.FunctionalCall'
21
- java_import 'mirah.lang.ast.Super'
22
- java_import 'mirah.lang.ast.ZSuper'
23
- java_import 'mirah.lang.ast.ImplicitSelf'
24
- java_import 'mirah.lang.ast.NodeList'
25
- java_import 'mirah.lang.ast.SimpleString'
26
- java_import 'mirah.lang.ast.StringConcat'
27
- java_import 'org.mirah.typer.TypeFuture'
28
-
29
- class FunctionalCall
30
- attr_accessor :target
31
- end
32
- class Super
33
- attr_accessor :target, :name
34
- end
35
-
36
- class << self
37
- attr_accessor :verbose
38
-
39
- def classname_from_filename(filename)
40
- basename = File.basename(filename).sub(/\.(duby|mirah)$/, '')
41
- basename.split(/[_-]/).map{|x| x[0...1].upcase + x[1..-1]}.join
42
- end
43
- end
44
-
45
- def initialize(config, scoper, typer)
46
- super
47
- @jump_scope = []
48
- end
49
-
50
- def logger_name
51
- "org.mirah.ruby.JVM.Compiler.JVMBytecode"
52
- end
53
-
54
- def file_builder(filename)
55
- builder = BiteScript::FileBuilder.new(filename)
56
- builder.to_widen do |_a, _b|
57
- a = @typer.type_system.get_type(_a.tr('/', '.'))
58
- b = @typer.type_system.get_type(_b.tr('/', '.'))
59
- a_ancestors = []
60
- while a
61
- a_ancestors << a.name
62
- a = a.superclass
63
- end
64
- b_ancestors = []
65
- while b
66
- b_ancestors << b.name
67
- b = b.superclass
68
- end
69
- intersection = (a_ancestors & b_ancestors)
70
- if intersection.size == 0
71
- puts "#{_a} => #{a}, #{_b} => #{b}"
72
- puts "#{a_ancestors.inspect} & #{b_ancestors.inspect} = []"
73
- 'java/lang/Object'
74
- else
75
- intersection[0].gsub('.', '/')
76
- end
77
- end
78
- @typer.type_system.define_types(builder)
79
- builder
80
- end
81
-
82
- def output_type
83
- "classes"
84
- end
85
-
86
- def push_jump_scope(node)
87
- raise "Not a node" unless Node === node
88
- begin
89
- @jump_scope << node
90
- yield
91
- ensure
92
- @jump_scope.pop
93
- end
94
- end
95
-
96
- def find_ensures(before)
97
- found = []
98
- @jump_scope.reverse_each do |scope|
99
- if Ensure === scope
100
- found << scope
101
- end
102
- break if before === scope
103
- end
104
- found
105
- end
106
-
107
- def begin_main
108
- # declare argv variable
109
- @method.local('argv', @typer.type_system.type(nil, 'string', true))
110
- end
111
-
112
- def finish_main
113
- @method.returnvoid
114
- end
115
-
116
- def prepare_binding(node)
117
- scope = introduced_scope(node)
118
- if scope.has_binding?
119
- type = scope.binding_type
120
- @binding = @bindings[type]
121
- @method.new type
122
- @method.dup
123
- @method.invokespecial type, "<init>", [@method.void]
124
- if node.respond_to? :arguments
125
- node.arguments.required.each do |param|
126
- name = param.name.identifier
127
- param_type = inferred_type(param)
128
- if scope.captured?(param.name.identifier)
129
- @method.dup
130
- param_type.load(@method, @method.local(name, param_type))
131
- @method.putfield(type, name, param_type)
132
- end
133
- end
134
- end
135
- type.store(@method, @method.local('$binding', type))
136
- end
137
- begin
138
- yield
139
- ensure
140
- if scope.has_binding?
141
- @binding.stop
142
- @binding = nil
143
- end
144
- end
145
- end
146
-
147
- def visitMethodDefinition(node, expression)
148
- push_jump_scope(node) do
149
- base_define_method(node) do |method, arg_types|
150
- return if @class.interface? || node.annotated_abstract?
151
- is_static = self.static || node.kind_of?(StaticMethodDefinition)
152
-
153
- log "Starting new #{is_static ? 'static ' : ''}method #{node.name.identifier}(#{arg_types})"
154
- args = visit(node.arguments, true)
155
- method_body(method, args, node, inferred_type(node).returnType)
156
- log "Method #{node.name.identifier}(#{arg_types}) complete!"
157
- end
158
- end
159
- end
160
-
161
- def define_optarg_chain(name, arg, return_type,
162
- args_for_opt, arg_types_for_opt)
163
- # declare all args so they get their values
164
- @method.aload(0) unless @static
165
- args_for_opt.each do |req_arg|
166
- inferred_type(req_arg).load(@method, @method.local(req_arg.name.identifier, inferred_type(req_arg)))
167
- end
168
- visit(arg.value, true)
169
-
170
- # invoke the next one in the chain
171
- if @static
172
- @method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [inferred_type(arg)])
173
- else
174
- @method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [inferred_type(arg)])
175
- end
176
-
177
- return_type.return(@method)
178
- end
179
-
180
- def visitConstructorDefinition(node, expression)
181
- push_jump_scope(node) do
182
- super(node, true) do |method, args|
183
- method_body(method, args, node, @typer.type_system.type(nil, 'void')) do
184
- method.aload 0
185
- scope = introduced_scope(node)
186
- if node.body.size > 0 &&
187
- (node.body(0).kind_of?(Super) || node.body(0).kind_of?(ZSuper))
188
- super_node = node.body(0)
189
- delegate_class = @type.superclass
190
- delegate_types = []
191
- if super_node.kind_of?(ZSuper)
192
- [node.arguments.required,
193
- node.arguments.optional,
194
- node.arguments.required2
195
- ].each do |args|
196
- args.each do |arg|
197
- arg_type = inferred_type(arg)
198
- delegate_types << arg_type
199
- local(scope, arg.name.identifier, arg_type)
200
- end
201
- end
202
- else
203
- super_node.parameters.each do |param|
204
- param_type = inferred_type(param)
205
- delegate_types << param_type
206
- visit(param, true)
207
- end
208
- end
209
- constructor = delegate_class.constructor(*delegate_types)
210
- method.invokespecial(
211
- delegate_class, "<init>",
212
- [@method.void, *constructor.argument_types])
213
- else
214
- unless (node.body.size > 0 &&
215
- node.body(0).kind_of?(FunctionalCall) &&
216
- node.body(0).name.identifier == 'initialize')
217
- method.invokespecial @class.superclass, "<init>", [@method.void]
218
- end
219
- end
220
- end
221
- end
222
- end
223
- end
224
-
225
- def method_body(method, args, node, return_type)
226
- body = node.body
227
- with(:method => method,
228
- :declared_locals => {}) do
229
-
230
- method.start
231
-
232
- scope = introduced_scope(node)
233
-
234
- # declare all args so they get their values
235
- if args
236
- args.each {|arg| declare_local(scope, arg.name.identifier, inferred_type(arg))}
237
- end
238
- declare_locals(scope)
239
-
240
- yield if block_given?
241
-
242
- prepare_binding(node) do
243
- expression = return_type.name != 'void'
244
- if body
245
- if expression
246
- body_type = inferred_type(body)
247
- unless return_type.assignableFrom(body_type)
248
- error("Invalid return type #{body_type.name}, expected #{return_type.name}", body)
249
- end
250
- end
251
- visit(body, expression)
252
- convert_value inferred_type(body), return_type if expression
253
- end
254
- end
255
-
256
- return_type.return(@method) unless return_type.name == ':unreachable'
257
-
258
- @method.stop
259
- end
260
- end
261
-
262
- def visitClosureDefinition(class_def, expression)
263
- compiler = ClosureCompiler.new(@config, @file, @type, self, @scoper, @typer)
264
- compiler.visitClassDefinition(class_def, expression)
265
- end
266
-
267
- def visitInterfaceDeclaration(class_def, expression)
268
- visitClassDefinition(class_def, expression)
269
- end
270
-
271
- def visitIf(iff, expression)
272
- elselabel = @method.label
273
- donelabel = @method.label
274
-
275
- # this is ugly...need a better way to abstract the idea of compiling a
276
- # conditional branch while still fitting into JVM opcodes
277
- predicate = iff.condition
278
- body = iff.body
279
- elseBody = iff.elseBody
280
- if body.is_a?(NodeList) && body.size == 0
281
- body = nil
282
- end
283
- if elseBody.is_a?(NodeList) && elseBody.size == 0
284
- elseBody = nil
285
- end
286
- if body || expression
287
- jump_if_not(predicate, elselabel)
288
-
289
- if body
290
- visit(body, expression)
291
- elsif expression
292
- inferred_type(iff).init_value(@method)
293
- end
294
-
295
- @method.goto(donelabel)
296
- else
297
- jump_if(predicate, donelabel)
298
- end
299
-
300
- elselabel.set!
301
-
302
- if elseBody
303
- visit(elseBody, expression)
304
- elsif expression
305
- inferred_type(iff).init_value(@method)
306
- end
307
-
308
- donelabel.set!
309
- end
310
-
311
- def visitLoop(loop, expression)
312
- push_jump_scope(loop) do
313
- with(:break_label => @method.label,
314
- :redo_label => @method.label,
315
- :next_label => @method.label) do
316
- predicate = loop.condition
317
-
318
- visit(loop.init, false)
319
-
320
- pre_label = @redo_label
321
-
322
- unless loop.skipFirstCheck
323
- @next_label.set! unless loop.post_size > 0
324
- if loop.negative
325
- # if condition, exit
326
- jump_if(predicate, @break_label)
327
- else
328
- # if not condition, exit
329
- jump_if_not(predicate, @break_label)
330
- end
331
- end
332
-
333
- if loop.pre_size > 0
334
- pre_label = method.label
335
- pre_label.set!
336
- visit(loop.pre, false)
337
- end
338
-
339
-
340
- @redo_label.set!
341
- visit(loop.body, false) if loop.body
342
-
343
- if loop.skipFirstCheck || loop.post_size > 0
344
- @next_label.set!
345
- visit(loop.post, false)
346
- if loop.negative
347
- # if not condition, continue
348
- jump_if_not(predicate, pre_label)
349
- else
350
- # if condition, continue
351
- jump_if(predicate, pre_label)
352
- end
353
- else
354
- @method.goto(@next_label)
355
- end
356
-
357
- @break_label.set!
358
-
359
- # loops always evaluate to null
360
- @method.aconst_null if expression
361
- end
362
- end
363
- end
364
-
365
- def visitBreak(node, expression)
366
- error("break outside of loop", node) unless @break_label
367
- handle_ensures(find_ensures(Loop))
368
- set_position node.position
369
- @method.goto(@break_label)
370
- end
371
-
372
- def visitNext(node, expression)
373
- error("next outside of loop", node) unless @next_label
374
- handle_ensures(find_ensures(Loop))
375
- set_position node.position
376
- @method.goto(@next_label)
377
- end
378
-
379
- def visitRedo(node, expression)
380
- error("redo outside of loop", node) unless @redo_label
381
- handle_ensures(find_ensures(Loop))
382
- set_position node.position
383
- @method.goto(@redo_label)
384
- end
385
-
386
- def jump_if(predicate, target)
387
- type = inferred_type(predicate)
388
- if type.primitive?
389
- raise "Expected boolean, found #{type}" unless type.name == 'boolean'
390
- end
391
- if Call === predicate
392
- method = extract_method(predicate)
393
- if method.respond_to? :jump_if
394
- method.jump_if(self, predicate, target)
395
- return
396
- end
397
- end
398
- visit(predicate, true)
399
- if type.primitive?
400
- @method.ifne(target)
401
- else
402
- @method.ifnonnull(target)
403
- end
404
- end
405
-
406
- def jump_if_not(predicate, target)
407
- type = inferred_type(predicate)
408
- if type.primitive?
409
- raise "Expected boolean, found #{type}" unless type.name == 'boolean'
410
- end
411
- if Call === predicate
412
- method = extract_method(predicate)
413
- if method.respond_to? :jump_if_not
414
- method.jump_if_not(self, predicate, target)
415
- return
416
- end
417
- end
418
- visit(predicate, true)
419
- if type.primitive?
420
- @method.ifeq(target)
421
- else
422
- @method.ifnull(target)
423
- end
424
- end
425
-
426
- def extract_method(call)
427
- target = inferred_type(call.target)
428
- params = call.parameters.map do |param|
429
- inferred_type(param)
430
- end
431
- target.get_method(call.name.identifier, params)
432
- end
433
-
434
- def visitAttrAssign(call, expression)
435
- target = inferred_type(call.target)
436
- value_type = inferred_type(call.value)
437
- setter = "#{call.name.identifier}_set"
438
- method = target.get_method(setter, [value_type])
439
- if method
440
- method.call(self, call, expression, [call.value])
441
- else
442
- target = inferred_type(call.target)
443
- raise "Missing method #{target.full_name}.#{setter}(#{value_type.full_name})"
444
- end
445
- end
446
-
447
- def visitCall(call, expression)
448
- method = extract_method(call)
449
- if method
450
- method.call(self, call, expression)
451
- else
452
- params = call.parameters.map do |param|
453
- inferred_type(param)
454
- end
455
- target = inferred_type(call.target)
456
- raise "Missing method #{target}.#{call.name.identifier}(#{params.join ', '})"
457
- end
458
- end
459
-
460
- def visitVarargsArray type, parameters
461
- @method.push_int parameters.size
462
- @method.anewarray type.component_type
463
- parameters.each.with_index do |value, i|
464
- @method.dup
465
- @method.push_int i
466
- visit(value, true)
467
- convert_value inferred_type(value), type.component_type
468
- @method.aastore
469
- end
470
- end
471
-
472
- def visitFunctionalCall(fcall, expression)
473
- scope = get_scope(fcall)
474
- type = get_scope(fcall).self_type.resolve
475
- type = type.meta if (@static && type == @type)
476
- fcall.target = ImplicitSelf.new
477
- fcall.target.parent = fcall
478
- @typer.infer(fcall.target)
479
-
480
- params = fcall.parameters.map do |param|
481
- inferred_type(param)
482
- end
483
- name = fcall.name.identifier
484
- chained_constructor = false
485
- if name == 'initialize'
486
- if scope.context.kind_of?(ConstructorDefinition) &&
487
- scope.context.body(0) == fcall
488
- name = '<init>'
489
- chained_constructor = true
490
- end
491
- end
492
-
493
- method = type.get_method(name, params)
494
- unless method
495
- target = static ? @class.name : 'self'
496
-
497
- raise NameError, "No method %s.%s(%s)" %
498
- [target, fcall.name.identifier, params.join(', ')]
499
- end
500
- if chained_constructor
501
- method.call(self, fcall, expression, nil, true)
502
- else
503
- method.call(self, fcall, expression)
504
- end
505
- end
506
-
507
- def visitSuper(sup, expression)
508
- mdef = sup.findAncestor(MethodDefinition.java_class)
509
- # FIXME Horrible hack
510
- return if mdef.kind_of?(ConstructorDefinition)
511
- type = @type.superclass
512
- super_type = @typer.type_system.getSuperClass(get_scope(sup).self_type)
513
- @typer.infer(sup.target)
514
-
515
- sup.name = mdef.name.identifier
516
-
517
- # TODO ZSuper
518
- params = sup.parameters.map do |param|
519
- inferred_type(param)
520
- end
521
- method = type.get_method(sup.name, params)
522
- unless method
523
- raise NameError, "No method %s.%s(%s)" %
524
- [type, sup.name, params.join(', ')]
525
- end
526
- method.call_special(self, ImplicitSelf.new, type, sup.parameters, expression)
527
- end
528
-
529
- def visitCast(fcall, expression)
530
- # casting operation, not a call
531
- castee = fcall.value
532
-
533
- # TODO move errors to inference phase
534
- source_type_name = inferred_type(castee).name
535
- target_type_name = inferred_type(fcall).name
536
- if inferred_type(castee).primitive?
537
- if inferred_type(fcall).primitive?
538
- if source_type_name == 'boolean' && target_type_name != "boolean"
539
- raise TypeError.new "not a boolean type: #{inferred_type(castee)}"
540
- end
541
- # ok
542
- primitive = true
543
- else
544
- raise TypeError.new "Cannot cast #{inferred_type(castee)} to #{inferred_type(fcall)}: not a reference type."
545
- end
546
- elsif inferred_type(fcall).primitive?
547
- raise TypeError.new "not a primitive type: #{inferred_type(castee)}"
548
- else
549
- # ok
550
- primitive = false
551
- end
552
-
553
- visit(castee, expression)
554
- if expression
555
- if primitive
556
- source_type_name = 'int' if %w[byte short char].include? source_type_name
557
- if (source_type_name != 'int') && (%w[byte short char].include? target_type_name)
558
- target_type_name = 'int'
559
- end
560
-
561
- if source_type_name != target_type_name
562
- if RUBY_VERSION == "1.9"
563
- @method.send "#{source_type_name[0]}2#{target_type_name[0]}"
564
- else
565
- @method.send "#{source_type_name[0].chr}2#{target_type_name[0].chr}"
566
- end
567
- end
568
- else
569
- if (source_type_name != target_type_name ||
570
- inferred_type(castee).array? != inferred_type(fcall).array?)
571
- @method.checkcast inferred_type(fcall)
572
- end
573
- end
574
- end
575
- end
576
-
577
- def visitNodeList(body, expression)
578
- # last element is an expression only if the body is an expression
579
- super(body, expression) do |last|
580
- if last
581
- visit(last, expression)
582
- elsif expression
583
- inferred_type(body).init_value(method)
584
- end
585
- end
586
- end
587
-
588
- def declared_locals
589
- @declared_locals ||= {}
590
- end
591
-
592
- def annotate(builder, annotations)
593
- annotations.each do |annotation|
594
- next if annotation.type.typeref.name.start_with?('org.mirah.jvm.')
595
- type = inferred_type(annotation)
596
- mirror = type.jvm_type
597
- if mirror.respond_to?(:getDeclaredAnnotation)
598
- retention = mirror.getDeclaredAnnotation('java.lang.annotation.Retention')
599
- else
600
- raise "Unsupported annotation #{mirror} (#{mirror.class})"
601
- end
602
- next if retention && retention.value.name == 'SOURCE'
603
- runtime_retention = (retention && retention.value.name == 'RUNTIME')
604
- builder.annotate(mirror, runtime_retention) do |visitor|
605
- annotation.values.each do |entry|
606
- annotation_value(get_scope(annotation), type, visitor,
607
- entry.key.identifier, entry.value)
608
- end
609
- end
610
- end
611
- end
612
-
613
- def annotation_value(scope, type, builder, name, value)
614
- if name
615
- value_type = type.unmeta.java_method(name).return_type
616
- if value_type.array?
617
- unless value.kind_of?(Array)
618
- raise "#{type.name}.#{name} should be an Array, got #{value.class}"
619
- end
620
- builder.array(name) do |child|
621
- value.values.each do |item|
622
- annotation_value(scope, value_type.component_type, child, nil, item)
623
- end
624
- end
625
- return
626
- end
627
- else
628
- value_type = type
629
- end
630
- primitive_classes = {
631
- 'Z' => java.lang.Boolean,
632
- 'B' => java.lang.Byte,
633
- 'C' => java.lang.Character,
634
- 'S' => java.lang.Short,
635
- 'I' => java.lang.Integer,
636
- 'J' => java.lang.Long,
637
- 'F' => java.lang.Float,
638
- 'D' => java.lang.Double,
639
- }
640
- descriptor = BiteScript::Signature::class_id(value_type)
641
- case descriptor
642
- when 'Ljava/lang/String;'
643
- string_value = if value.kind_of?(StringConcat)
644
- value.strings.map {|x| x.identifier}.join
645
- else
646
- value.identifier
647
- end
648
- builder.visit(name, string_value)
649
- when 'Ljava/lang/Class;'
650
- mirror = @typer.type_system.type(scope, value.typeref.name)
651
- klass = if value.typeref.isArray
652
- BiteScript::ASM::Type.get("[#{mirror.type.descriptor}")
653
- else
654
- mirror
655
- end
656
- builder.visit(name, klass)
657
- when *primitive_classes.keys
658
- klass = primitive_classes[descriptor]
659
- builder.visit(name, klass.new(value.value))
660
- else
661
- if value_type.jvm_type.enum?
662
- builder.enum(name, value_type, value.identifier)
663
- elsif value_type.jvm_type.annotation?
664
- subtype = inferred_type(value)
665
- mirror = subtype.jvm_type
666
- builder.annotation(name, mirror) do |child|
667
- value.values.each do |entry|
668
- annotation_value(scope, subtype, child, entry.key.identifier, entry.value)
669
- end
670
- end
671
- else
672
- raise "Unsupported annotation #{descriptor} #{name} = #{value.class}"
673
- end
674
- end
675
- end
676
-
677
- def declared?(scope, name)
678
- declared_locals.include?(scoped_local_name(name, scope))
679
- end
680
-
681
- def declare_local(scope, name, type)
682
- # TODO confirm types are compatible
683
- name = scoped_local_name(name, scope)
684
- unless declared_locals[name]
685
- declared_locals[name] = type
686
- index = @method.local(name, type)
687
- end
688
- end
689
-
690
- def declare_locals(scope)
691
- scope.locals.each do |name|
692
- unless scope.captured?(name) || declared?(scope, name)
693
- type = scope.local_type(name)
694
- type = type.resolve if type.kind_of?(TypeFuture)
695
- declare_local(scope, name, type)
696
- type.init_value(@method)
697
- type.store(@method, @method.local(scoped_local_name(name, scope), type))
698
- end
699
- end
700
- end
701
-
702
- def get_binding(type)
703
- @bindings[type]
704
- end
705
-
706
- def declared_captures(binding=nil)
707
- @captured_locals[binding || @binding]
708
- end
709
-
710
- def visitLocalDeclaration(local, expression)
711
- scope = get_scope(local)
712
- if scope.has_binding? && scope.captured?(local.name.identifier)
713
- captured_local_declare(scope, local.name.identifier, inferred_type(local))
714
- end
715
- end
716
-
717
- def captured_local_declare(scope, name, type)
718
- unless declared_captures[name]
719
- declared_captures[name] = type
720
- # default should be fine, but I don't think bitescript supports it.
721
- @binding.protected_field(name, type)
722
- end
723
- end
724
-
725
- def visitLocalAccess(local, expression)
726
- if expression
727
- set_position(local.position)
728
- scope = get_scope(local)
729
- if scope.has_binding? && scope.captured?(local.name.identifier)
730
- captured_local(scope, local.name.identifier, inferred_type(local))
731
- else
732
- local(containing_scope(local), local.name.identifier, inferred_type(local))
733
- end
734
- end
735
- end
736
-
737
- def local(scope, name, type)
738
- type.load(@method, @method.local(scoped_local_name(name, scope), type))
739
- end
740
-
741
- def captured_local(scope, name, type)
742
- captured_local_declare(scope, name, type)
743
- binding_reference
744
- @method.getfield(scope.binding_type, name, type)
745
- end
746
-
747
- def visitLocalAssignment(local, expression)
748
- scope = get_scope(local)
749
- if scope.has_binding? && scope.captured?(local.name.identifier)
750
- captured_local_assign(local, expression)
751
- else
752
- local_assign(local, expression)
753
- end
754
- end
755
-
756
- def local_assign(local, expression)
757
- name = local.name.identifier
758
- type = inferred_type(local)
759
- scope = containing_scope(local)
760
- declare_local(scope, name, type)
761
-
762
- visit(local.value, true)
763
- convert_value inferred_type(local.value), type
764
-
765
- # if expression, dup the value we're assigning
766
- if expression
767
- dup_value type
768
- end
769
-
770
- set_position(local.position)
771
- type.store(@method, @method.local(scoped_local_name(name, scope), type))
772
- end
773
-
774
- def captured_local_assign(node, expression)
775
- scope, name = containing_scope(node), node.name.identifier
776
- type = get_scope(node).local_type(name).resolve
777
- captured_local_declare(scope, name, type)
778
- binding_reference
779
- visit(node.value, true)
780
- convert_value(inferred_type(node.value), type)
781
-
782
- # if expression, dup the value we're assigning
783
- if expression
784
- dup_x2_value type
785
- end
786
- set_position(node.position)
787
- @method.putfield(scope.binding_type, name, type)
788
- end
789
-
790
- def visitFieldAccess(field, expression)
791
- return nil unless expression
792
- name = field.name.identifier
793
-
794
- real_type = declared_fields[name] || inferred_type(field)
795
- declare_field(name, real_type, [], field.isStatic)
796
-
797
- set_position(field.position)
798
- # load self object unless static
799
- method.aload 0 unless static || field.isStatic
800
-
801
- if static || field.isStatic
802
- @method.getstatic(@class, name, inferred_type(field))
803
- else
804
- @method.getfield(@class, name, inferred_type(field))
805
- end
806
- end
807
-
808
- def declared_fields
809
- @declared_fields ||= {}
810
- @declared_fields[@class] ||= {}
811
- end
812
-
813
- def declare_field(name, type, annotations, static_field)
814
- # TODO confirm types are compatible
815
- unless declared_fields[name]
816
- declared_fields[name] = type
817
- field = if static || static_field
818
- @class.private_static_field name, type
819
- else
820
- @class.private_field name, type
821
- end
822
- annotate(field, annotations)
823
- end
824
- end
825
-
826
- def visitFieldDeclaration(decl, expression)
827
- declare_field(decl.name.identifier, inferred_type(decl), decl.annotations, decl.isStatic)
828
- end
829
-
830
- def visitFieldAssign(field, expression)
831
- name = field.name.identifier
832
-
833
- real_type = declared_fields[name] || inferred_type(field)
834
-
835
- declare_field(name, real_type, field.annotations, field.isStatic)
836
-
837
- method.aload 0 unless static || field.isStatic
838
- visit(field.value, true)
839
- if expression
840
- instruction = 'dup'
841
- instruction << '2' if real_type.wide?
842
- instruction << '_x1' unless static || field.isStatic
843
- method.send instruction
844
- end
845
- set_position(field.position)
846
- if static || field.isStatic
847
- @method.putstatic(@class, name, real_type)
848
- else
849
- @method.putfield(@class, name, real_type)
850
- end
851
- end
852
-
853
- def visitSimpleString(string, expression)
854
- set_position(string.position)
855
- @method.ldc(string.value) if expression
856
- end
857
-
858
- def visitStringConcat(strcat, expression)
859
- set_position(strcat.position)
860
- if expression
861
- # could probably be more efficient with non-default constructor
862
- builder_class = @typer.type_system.type(nil, 'java.lang.StringBuilder')
863
- @method.new builder_class
864
- @method.dup
865
- @method.invokespecial builder_class, "<init>", [@method.void]
866
-
867
- strcat.strings.each do |node|
868
- visit(node, true)
869
- method = find_method(builder_class, "append", [inferred_type(node)], nil, false)
870
- if method
871
- @method.invokevirtual builder_class, "append", [method.return_type, *method.argument_types]
872
- else
873
- log "Could not find a match for #{java::lang::StringBuilder}.append(#{inferred_type(node)})"
874
- fail "Could not compile"
875
- end
876
- end
877
-
878
- # convert to string
879
- set_position(strcat.position)
880
- @method.invokevirtual java::lang::StringBuilder.java_class, "toString", [@method.string]
881
- else
882
- strcat.strings.each do |node|
883
- visit(node, false)
884
- end
885
- end
886
- end
887
-
888
- def visitStringEval(node, expression)
889
- if expression
890
- visit(node.value, true)
891
- set_position(node.position)
892
- inferred_type(node.value).box(@method) if inferred_type(node.value).primitive?
893
- null = method.label
894
- done = method.label
895
- method.dup
896
- method.ifnull(null)
897
- @method.invokevirtual @method.object, "toString", [@method.string]
898
- @method.goto(done)
899
- null.set!
900
- method.pop
901
- method.ldc("null")
902
- done.set!
903
- else
904
- visit(node.value, false)
905
- end
906
- end
907
-
908
- def visitBoolean(node, expression)
909
- if expression
910
- set_position(node.position)
911
- node.value ? @method.iconst_1 : @method.iconst_0
912
- end
913
- end
914
-
915
- def visitRegex(node, expression)
916
- # TODO: translate flags to Java-appropriate values
917
- if node.strings_size == 1
918
- visit(node.strings(0), expression)
919
- else
920
- visitStringConcat(node, expression)
921
- end
922
- if expression
923
- set_position(node.position)
924
- @method.invokestatic java::util::regex::Pattern, "compile", [java::util::regex::Pattern, @method.string]
925
- end
926
- end
927
-
928
- def visitArray(node, expression)
929
- set_position(node.position)
930
- if expression
931
- # create basic arraylist
932
- @method.new java::util::ArrayList
933
- @method.dup
934
- @method.ldc_int node.values_size
935
- @method.invokespecial java::util::ArrayList, "<init>", [@method.void, @method.int]
936
-
937
- # elements, as expressions
938
- # TODO: ensure they're all reference types!
939
- node.values.each do |n|
940
- @method.dup
941
- visit(n, true)
942
- # TODO this feels like it should be in the node.compile itself
943
- if inferred_type(n).primitive?
944
- inferred_type(n).box(@method)
945
- end
946
- @method.invokeinterface java::util::List, "add", [@method.boolean, @method.object]
947
- @method.pop
948
- end
949
- else
950
- # elements, as non-expressions
951
- # TODO: ensure they're all reference types!
952
- node.values.each do |n|
953
- visit(n, true)
954
- # TODO this feels like it should be in the node.compile itself
955
- if inferred_type(n).primitive?
956
- inferred_type(n).box(@method)
957
- end
958
- end
959
- end
960
- end
961
-
962
- def visitHash(node, expression)
963
- set_position(node.position)
964
- if expression
965
- # create basic arraylist
966
- @method.new java::util::HashMap
967
- @method.dup
968
- @method.ldc_int [node.size / 0.75, 16].max.to_i
969
- @method.invokespecial java::util::HashMap, "<init>", [@method.void, @method.int]
970
-
971
- node.each do |e|
972
- @method.dup
973
- [e.key, e.value].each do |n|
974
- visit(n, true)
975
- # TODO this feels like it should be in the node.compile itself
976
- if inferred_type(n).primitive?
977
- inferred_type(n).box(@method)
978
- end
979
- end
980
- @method.invokeinterface java::util::Map, "put", [@method.object, @method.object, @method.object]
981
- @method.pop
982
- end
983
- else
984
- # elements, as non-expressions
985
- node.each do |n|
986
- visit(n.key, false)
987
- visit(n.value, false)
988
- end
989
- end
990
- end
991
-
992
- def visitNot(node, expression)
993
- visit(node.value, expression)
994
- if expression
995
- set_position(node.position)
996
- type = inferred_type(node.value)
997
- done = @method.label
998
- else_label = @method.label
999
- if type.primitive?
1000
- @method.ifeq else_label
1001
- else
1002
- @method.ifnull else_label
1003
- end
1004
- @method.iconst_0
1005
- @method.goto done
1006
- else_label.set!
1007
- @method.iconst_1
1008
- done.set!
1009
- end
1010
- end
1011
-
1012
- def visitNull(node, expression)
1013
- if expression
1014
- set_position(node.position)
1015
- @method.aconst_null
1016
- end
1017
- end
1018
-
1019
- def visitImplicitNil(node, expression)
1020
- visitNull(node, expression)
1021
- end
1022
-
1023
- def visitBindingReference(node, expression)
1024
- binding_reference
1025
- end
1026
-
1027
- def binding_reference
1028
- @method.aload(@method.local('$binding'))
1029
- end
1030
-
1031
- def real_self
1032
- method.aload(0)
1033
- end
1034
-
1035
- def set_position(position)
1036
- # TODO support positions from multiple files
1037
- @method.line(position.start_line) if @method && position
1038
- end
1039
-
1040
- def print(print_node)
1041
- @method.getstatic System, "out", PrintStream
1042
- print_node.parameters.each {|param| visit(param, true)}
1043
- params = print_node.parameters.map {|param| inferred_type(param).jvm_type}
1044
- method_name = print_node.println ? "println" : "print"
1045
- method = find_method(PrintStream.java_class, method_name, params, nil, false)
1046
- if (method)
1047
- @method.invokevirtual(
1048
- PrintStream,
1049
- method_name,
1050
- [method.return_type, *method.parameter_types])
1051
- else
1052
- log "Could not find a match for #{PrintStream}.#{method_name}(#{params})"
1053
- fail "Could not compile"
1054
- end
1055
- end
1056
-
1057
- def visitReturn(return_node, expression)
1058
- visit(return_node.value, true) if return_node.value
1059
- handle_ensures(find_ensures(MethodDefinition))
1060
- set_position return_node.position
1061
- inferred_type(return_node).return(@method)
1062
- end
1063
-
1064
- def visitRaise(node, expression)
1065
- visit(node.args(0), true)
1066
- set_position(node.position)
1067
- @method.athrow
1068
- end
1069
-
1070
- def visitRescue(rescue_node, expression)
1071
- start = @method.label.set!
1072
- body_end = @method.label
1073
- done = @method.label
1074
- no_else_clauses = rescue_node.else_clause.size == 0
1075
-
1076
- visit(rescue_node.body, expression && no_else_clauses)
1077
- body_end.set!
1078
-
1079
- visit(rescue_node.else_clause, expression) unless no_else_clauses
1080
- return if start.label.offset == body_end.label.offset
1081
-
1082
- @method.goto(done)
1083
- rescue_node.clauses.each do |clause|
1084
- target = @method.label.set!
1085
- if clause.name
1086
- types = clause.types.map {|t| inferred_type(t)}
1087
- widened_type = types.inject {|a, b| a.widen(b)}
1088
- @method.astore(declare_local(introduced_scope(clause), clause.name.identifier, widened_type))
1089
- else
1090
- @method.pop
1091
- end
1092
- declare_locals(introduced_scope(clause))
1093
- visit(clause.body, expression)
1094
- @method.goto(done)
1095
- clause.types.each do |type|
1096
- type = inferred_type(type)
1097
- @method.trycatch(start, body_end, target, type)
1098
- end
1099
- end
1100
- done.set!
1101
- end
1102
-
1103
- def handle_ensures(nodes)
1104
- nodes.each do |ensure_node|
1105
- visit(ensure_node.ensureClause, false)
1106
- end
1107
- end
1108
-
1109
- def visitEnsure(node, expression)
1110
- # TODO this doesn't appear to be used
1111
- #node.state = @method.label # Save the ensure target for JumpNodes
1112
- start = @method.label.set!
1113
- body_end = @method.label
1114
- done = @method.label
1115
- push_jump_scope(node) do
1116
- visit(node.body, expression) # First compile the body
1117
- end
1118
- body_end.set!
1119
- handle_ensures([node]) # run the ensure clause
1120
- @method.goto(done) # and continue on after the exception handler
1121
- target = @method.label.set! # Finally, create the exception handler
1122
- @method.trycatch(start, body_end, target, nil)
1123
- handle_ensures([node])
1124
- @method.athrow
1125
- done.set!
1126
- end
1127
-
1128
- def visitEmptyArray(node, expression)
1129
- if expression
1130
- visit(node.size, true)
1131
- type = @typer.type_system.get(@scoper.getScope(node), node.type).resolve
1132
- type.newarray(@method)
1133
- end
1134
- end
1135
-
1136
- private
1137
-
1138
- def convert_value in_type, out_type
1139
- in_type.compile_widen(@method, out_type) if in_type.name != ':unreachable' && in_type.primitive?
1140
- end
1141
-
1142
- def dup_value type
1143
- if type.primitive? && type.wide?
1144
- @method.dup2
1145
- else
1146
- @method.dup
1147
- end
1148
- end
1149
-
1150
- def dup_x2_value type
1151
- if type.primitive? && type.wide?
1152
- @method.dup2_x2
1153
- else
1154
- @method.dup_x2
1155
- end
1156
- end
1157
-
1158
- class ClosureCompiler < JVMBytecode
1159
- def initialize(config, file, type, parent, scoper, typer)
1160
- super(config, scoper, typer)
1161
- @file = file
1162
- @type = type
1163
- @jump_scope = []
1164
- @parent = parent
1165
- end
1166
-
1167
- def prepare_binding(node)
1168
- scope = introduced_scope(node)
1169
- if scope.has_binding?
1170
- type = scope.binding_type
1171
- @binding = @parent.get_binding(type)
1172
- @method.aload 0
1173
- @method.getfield(@class, 'binding', @binding)
1174
- type.store(@method, @method.local('$binding', type))
1175
- else
1176
- log "No binding for #{node} (#{scope.has_binding?} #{scope.parent} #{scope.parent && scope.parent.has_binding?})"
1177
- end
1178
- begin
1179
- yield
1180
- ensure
1181
- if scope.has_binding?
1182
- @binding = nil
1183
- end
1184
- end
1185
- end
1186
-
1187
- def declared_captures
1188
- @parent.declared_captures(@binding)
1189
- end
1190
- end
1191
- end
1192
- end
1193
- end
1194
- end