mirah 0.0.12-java → 0.1.0-java

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