mirah 0.0.12-java → 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
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