mirah 0.1.0.pre-java → 0.1.1-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 (92) hide show
  1. data/History.txt +736 -0
  2. data/README.md +71 -0
  3. data/Rakefile +227 -73
  4. data/examples/Fib.class +0 -0
  5. data/examples/macros/{string-each-char.mirah → string_each_char.mirah} +2 -3
  6. data/examples/simple_class.mirah +3 -3
  7. data/examples/{dynamic.mirah → simple_class.mirah~} +7 -12
  8. data/javalib/mirah-bootstrap.jar +0 -0
  9. data/javalib/mirah-builtins.jar +0 -0
  10. data/javalib/mirah-compiler.jar +0 -0
  11. data/javalib/mirah-parser.jar +0 -0
  12. data/javalib/mirah-util.jar +0 -0
  13. data/lib/mirah.rb +8 -1
  14. data/lib/mirah/ast.rb +1 -1
  15. data/lib/mirah/ast/scope.rb +16 -0
  16. data/lib/mirah/commands/base.rb +1 -3
  17. data/lib/mirah/compiler.rb +17 -3
  18. data/lib/mirah/errors.rb +10 -10
  19. data/lib/mirah/generator.rb +21 -9
  20. data/lib/mirah/jvm/compiler.rb +17 -0
  21. data/lib/mirah/jvm/compiler/base.rb +24 -5
  22. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +83 -20
  23. data/lib/mirah/jvm/method_lookup.rb +43 -22
  24. data/lib/mirah/jvm/types.rb +1 -2
  25. data/lib/mirah/jvm/types/array_type.rb +1 -6
  26. data/lib/mirah/jvm/types/ast_ext.rb +31 -0
  27. data/lib/mirah/jvm/types/basic_types.rb +1 -2
  28. data/lib/mirah/jvm/types/boolean.rb +11 -10
  29. data/lib/mirah/jvm/types/extensions.rb +14 -5
  30. data/lib/mirah/jvm/types/factory.rb +128 -43
  31. data/lib/mirah/jvm/types/floats.rb +8 -10
  32. data/lib/mirah/jvm/types/integers.rb +16 -9
  33. data/lib/mirah/jvm/types/intrinsics.rb +17 -69
  34. data/lib/mirah/jvm/types/meta_type.rb +5 -0
  35. data/lib/mirah/jvm/types/methods.rb +317 -151
  36. data/lib/mirah/jvm/types/methods.rb~ +973 -0
  37. data/lib/mirah/jvm/types/number.rb +29 -6
  38. data/lib/mirah/jvm/types/primitive_type.rb +35 -7
  39. data/lib/mirah/jvm/types/source_mirror.rb +11 -6
  40. data/lib/mirah/jvm/types/type.rb +52 -0
  41. data/lib/mirah/jvm/types/type_definition.rb +8 -2
  42. data/lib/mirah/transform/ast_ext.rb +9 -31
  43. data/lib/mirah/transform/transformer.rb +1 -1
  44. data/lib/mirah/typer.rb +2 -1
  45. data/lib/mirah/util/argument_processor.rb +10 -14
  46. data/lib/mirah/util/argument_processor.rb~ +146 -0
  47. data/lib/mirah/util/compilation_state.rb +15 -9
  48. data/lib/mirah/util/process_errors.rb +8 -2
  49. data/lib/mirah/version.rb +2 -2
  50. data/lib/mirah_task.rb +0 -7
  51. data/test/core/typer_test.rb +21 -13
  52. data/test/core/util/argument_processor_test.rb +19 -19
  53. data/test/core/util/class_loader_test.rb +19 -4
  54. data/test/core/util/compilation_state_test.rb +38 -0
  55. data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
  56. data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
  57. data/test/fixtures/org/foo/LowerCaseInnerClass.java +7 -0
  58. data/test/jvm/blocks_test.rb +50 -29
  59. data/test/jvm/bytecode_test_helper.rb +71 -57
  60. data/test/jvm/cast_test.rb +162 -0
  61. data/test/jvm/constructors_test.rb +48 -0
  62. data/test/jvm/enumerable_test.rb +136 -7
  63. data/test/jvm/example_test.rb +39 -0
  64. data/test/jvm/factory_test.rb +6 -0
  65. data/test/jvm/generics_test.rb +0 -5
  66. data/test/jvm/import_test.rb +81 -0
  67. data/test/jvm/interface_test.rb +113 -0
  68. data/test/jvm/java_typer_test.rb +57 -11
  69. data/test/jvm/jvm_commands_test.rb +24 -0
  70. data/test/jvm/jvm_compiler_test.rb +186 -370
  71. data/test/jvm/macros_test.rb +67 -6
  72. data/test/jvm/main_method_test.rb +1 -1
  73. data/test/jvm/mirror_compilation_test_helper.rb +24 -0
  74. data/test/jvm/new_backend_test_helper.rb +25 -0
  75. data/test/jvm/rescue_test.rb +153 -18
  76. data/test/jvm/string_test.rb +41 -0
  77. data/test/jvm/varargs_test.rb +65 -0
  78. data/test/mirrors/base_type_test.rb +96 -0
  79. data/test/mirrors/bytecode_mirror_test.rb +86 -0
  80. data/test/mirrors/generics_test.rb +776 -0
  81. data/test/mirrors/member_test.rb +69 -0
  82. data/test/mirrors/method_lookup_test.rb +574 -0
  83. data/test/mirrors/mirrors_test.rb +562 -0
  84. data/test/mirrors/simple_async_mirror_loader_test.rb +110 -0
  85. data/test/mirrors/simple_mirror_loader_test.rb +104 -0
  86. data/test/test_helper.rb +2 -1
  87. metadata +244 -217
  88. data/README.txt +0 -59
  89. data/javalib/dynalink-0.2.jar +0 -0
  90. data/lib/mirah/jvm/typer.rb +0 -177
  91. data/lib/mirah/jvm/types/dynamic_type.rb +0 -45
  92. data/lib/mirah/jvm/types/unreachable_type.rb +0 -27
@@ -99,7 +99,7 @@ module Mirah
99
99
  by_name = if constructor
100
100
  mapped_type.unmeta.declared_constructors
101
101
  elsif meta
102
- mapped_type.declared_class_methods(name)
102
+ mapped_type.find_callable_static_methods(name)
103
103
  else
104
104
  mapped_type.find_callable_methods(name)
105
105
  end
@@ -118,21 +118,27 @@ module Mirah
118
118
 
119
119
  def find_jls2(mapped_type, name, mapped_params, meta, by_name, include_fields=true, scope=nil)
120
120
  return nil if mapped_params.any? {|p| p.nil? || p.isError}
121
- # filter by arity
122
- by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size}
121
+
122
+ # filter by arity, varargs
123
+ by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size }
123
124
 
124
125
  phase1_methods = phase1(mapped_params, by_name_and_arity)
125
126
 
126
127
  if phase1_methods.size > 1
127
128
  method_list = phase1_methods.map do |m|
128
- "#{m.name}(#{m.parameter_types.map(&:name).join(', ')})"
129
+ case m.member
130
+ when BiteScript::ASM::MethodMirror
131
+ m.member.inspect
132
+ else
133
+ "#{m.name}(#{m.parameter_types.map(&:name).join(', ')})"
134
+ end
129
135
  end.join("\n")
130
136
  raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{method_list}"
131
137
  end
132
138
 
133
139
  phase1_methods[0] ||
134
140
  phase2(mapped_params, by_name) ||
135
- phase3(mapped_params, by_name) ||
141
+ phase3(mapped_params, by_name)[0] ||
136
142
  (include_fields &&
137
143
  (field_lookup(mapped_params, mapped_type, meta, name, scope) ||
138
144
  inner_class(mapped_params, mapped_type, meta, name)))
@@ -152,15 +158,17 @@ module Mirah
152
158
  end
153
159
 
154
160
  # otherwise, check for potential match and compare to current
155
- # TODO: missing ambiguity check; picks last method of equal specificity
161
+ # TODO: missing ambiguity check; picks first method of equal specificity
162
+ # Picking the first method means we prefer methods from the child class,
163
+ # which is important if the parent class is not accessible (like AbstractStringBuilder).
156
164
  if each_is_exact_or_subtype_or_convertible(mapped_params, method_params)
157
- if currents.size > 0
158
- if is_more_specific?(potential.argument_types, currents[0].argument_types)
159
- # potential is better, dump all currents
160
- currents = [potential]
161
- elsif is_more_specific?(currents[0].argument_types, potential.argument_types)
165
+ if !currents.empty?
166
+ if is_more_specific?(currents[0].argument_types, potential.argument_types)
162
167
  # currents are better, try next potential
163
168
  #next
169
+ elsif is_more_specific?(potential.argument_types, currents[0].argument_types)
170
+ # potential is better, dump all currents
171
+ currents = [potential]
164
172
  else
165
173
  # equal specificity, append to currents
166
174
  currents << potential
@@ -186,7 +194,26 @@ module Mirah
186
194
  end
187
195
 
188
196
  def phase3(mapped_params, potentials)
189
- nil
197
+ potential_varargs = potentials.select{|m| m.respond_to?(:varargs?) && m.varargs? }
198
+ methods = potential_varargs.inject([]) do |currents, potential|
199
+ method_params = potential.argument_types
200
+ # match n-1 params of potential
201
+ non_varargs_params, possible_varargs_params = mapped_params.partition.with_index{|param,i| i < method_params.size-1}
202
+
203
+ vararg_types = possible_varargs_params.size.times.map{ method_params.last.component_type }
204
+
205
+ if each_is_exact(non_varargs_params, method_params[0..-2]) &&
206
+ each_is_exact(possible_varargs_params, vararg_types)
207
+ return [potential]
208
+ end
209
+
210
+ if each_is_exact_or_subtype_or_convertible(non_varargs_params, method_params[0..-2]) &&
211
+ each_is_exact_or_subtype_or_convertible(possible_varargs_params, vararg_types)
212
+ currents << potential
213
+ end
214
+
215
+ currents
216
+ end
190
217
  end
191
218
 
192
219
  def field_lookup(mapped_params, mapped_type, meta, name, scope)
@@ -234,24 +261,17 @@ module Mirah
234
261
  end
235
262
 
236
263
  def inner_class(params, type, meta, name)
237
- return unless params.size == 0 && meta
264
+ return unless params.empty? && meta
238
265
  log("Attempting inner class lookup for '#{name}' on #{type}")
239
266
  type.inner_class_getter(name)
240
267
  end
241
268
 
242
269
  def each_is_exact(incoming, target)
243
- incoming.each_with_index do |in_type, i|
244
- target_type = target[i]
245
-
246
- # exact match
247
- return false unless target_type == in_type
248
- end
249
- return true
270
+ incoming.zip(target).all? { |in_type, target_type| target_type == in_type }
250
271
  end
251
272
 
252
273
  def each_is_exact_or_subtype_or_convertible(incoming, target)
253
- incoming.each_with_index do |in_type, i|
254
- target_type = target[i]
274
+ incoming.zip(target).each do |in_type, target_type|
255
275
 
256
276
  # exact match
257
277
  next if target_type == in_type
@@ -259,6 +279,7 @@ module Mirah
259
279
  unless target_type.respond_to?(:primitive?) && in_type.respond_to?(:primitive?)
260
280
  puts "Huh?"
261
281
  end
282
+
262
283
  # primitive is safely convertible
263
284
  if target_type.primitive?
264
285
  if in_type.primitive?
@@ -29,11 +29,9 @@ require 'mirah/jvm/types/meta_type'
29
29
  require 'mirah/jvm/types/generic_type'
30
30
  require 'mirah/jvm/types/null_type'
31
31
  require 'mirah/jvm/types/implicit_nil_type'
32
- require 'mirah/jvm/types/unreachable_type'
33
32
  require 'mirah/jvm/types/void_type'
34
33
  require 'mirah/jvm/types/block_type'
35
34
  require 'mirah/jvm/types/array_type'
36
- require 'mirah/jvm/types/dynamic_type'
37
35
  require 'mirah/jvm/types/type_definition'
38
36
  require 'mirah/jvm/types/interface_definition'
39
37
  require 'mirah/jvm/types/intrinsics'
@@ -44,3 +42,4 @@ require 'mirah/jvm/types/boolean'
44
42
  require 'mirah/jvm/types/floats'
45
43
  require 'mirah/jvm/types/literals'
46
44
  require 'mirah/jvm/types/factory'
45
+ require 'mirah/jvm/types/extensions'
@@ -6,12 +6,7 @@ module Mirah
6
6
 
7
7
  def initialize(component_type)
8
8
  @component_type = component_type
9
- if @component_type.jvm_type
10
- #@type = java.lang.reflect.Array.newInstance(@component_type.jvm_type, 0).class
11
- else
12
- # FIXME: THIS IS WRONG, but I don't know how to fix it
13
- #@type = @component_type
14
- end
9
+
15
10
  @name = component_type.name
16
11
  @type_system = component_type.type_system
17
12
  self.intrinsics
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
2
+ # All contributing project authors may be found in the NOTICE file.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ class Java::MirahLangAst::NodeImpl
17
+ def annotated_abstract?
18
+ annotations.each do |anno|
19
+ if anno.type.typeref.name == 'org.mirah.jvm.types.Modifiers'
20
+ anno.values.each do |entry|
21
+ if entry.key.identifier == 'flags'
22
+ entry.value.values.each do |value|
23
+ return true if value.identifier == 'ABSTRACT'
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ false
30
+ end
31
+ end
@@ -19,7 +19,7 @@ module Mirah::JVM::Types
19
19
  @known_types.update(
20
20
  'boolean' => BooleanType.new(self, 'boolean', java.lang.Boolean),
21
21
  'byte' => IntegerType.new(self, 'byte', java.lang.Byte),
22
- 'char' => IntegerType.new(self, 'char', java.lang.Character),
22
+ 'char' => CharacterType.new(self, 'char', java.lang.Character),
23
23
  'short' => IntegerType.new(self, 'short', java.lang.Short),
24
24
  'int' => IntegerType.new(self, 'int', java.lang.Integer),
25
25
  'long' => LongType.new(self, 'long', java.lang.Long),
@@ -36,7 +36,6 @@ module Mirah::JVM::Types
36
36
  @known_types['void'] = VoidType.new(self)
37
37
  @known_types['null'] = NullType.new(self)
38
38
  @known_types['implicit_nil'] = ImplicitNilType.new(self)
39
- @known_types['dynamic'] = DynamicType.new(self)
40
39
  end
41
40
  end
42
41
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
1
+ # Copyright (c) 2010-2013 The Mirah project authors. All Rights Reserved.
2
2
  # All contributing project authors may be found in the NOTICE file.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,15 +23,6 @@ module Mirah::JVM::Types
23
23
  'i'
24
24
  end
25
25
 
26
- def box(builder)
27
- box_type = Mirah::AST::type(nil, 'java.lang.Boolean')
28
- builder.invokestatic box_type, "valueOf", [box_type, self]
29
- end
30
-
31
- def box_type
32
- @type_system.type(nil, 'java.lang.Boolean')
33
- end
34
-
35
26
  def add_intrinsics
36
27
  args = [math_type]
37
28
  add_method('==', args, ComparisonIntrinsic.new(self, '==', :eq, args))
@@ -42,6 +33,16 @@ module Mirah::JVM::Types
42
33
  @type_system.type(nil, 'boolean')
43
34
  end
44
35
 
36
+ def compile_widen(builder, type)
37
+ case type.name
38
+ when 'boolean'
39
+ when wrapper_name, 'java.lang.Object'
40
+ builder.invokestatic @wrapper, "valueOf", [@wrapper, builder.send(name)]
41
+ else
42
+ raise ArgumentError, "Invalid widening conversion from #{name} to #{type}"
43
+ end
44
+ end
45
+
45
46
  # same as NumberType's
46
47
  def compile_boolean_operator(compiler, op, negated, call, label)
47
48
  # Promote the target or the argument if necessary
@@ -62,22 +62,31 @@ module Mirah::JVM::Types
62
62
  end
63
63
 
64
64
  def declared_instance_methods(name=nil)
65
- __combine_methods(__getobj__.declared_instance_methods)
65
+ __combine_methods(__getobj__.declared_instance_methods, name)
66
66
  end
67
67
 
68
68
  def declared_class_methods(name=nil)
69
- __combine_methods(__getobj__.declared_class_methods)
69
+ __combine_methods(__getobj__.declared_class_methods, name)
70
70
  end
71
71
 
72
- def __combine_methods(basic_methods)
72
+ def find_callable_methods(name, include_interfaces=false)
73
+ __combine_methods(__getobj__.find_callable_methods(name, include_interfaces), name)
74
+ end
75
+
76
+ def find_callable_static_methods(name)
77
+ __combine_methods(__getobj__.find_callable_static_methods(name), name)
78
+ end
79
+
80
+ def __combine_methods(basic_methods, name)
73
81
  methods = {}
74
82
  basic_methods.each do |method|
75
- key = [method.name, method.parameter_types, method.return_type]
83
+ key = [method.name, method.argument_types, method.return_type]
76
84
  methods[key] = method
77
85
  end
78
86
  @static_includes.each do |type|
79
87
  type.declared_class_methods.each do |method|
80
- key = [method.name, method.parameter_types, method.return_type]
88
+ next if name && method.name != name
89
+ key = [method.name, method.argument_types, method.return_type]
81
90
  methods[key] ||= method
82
91
  end
83
92
  end
@@ -40,13 +40,8 @@ module Mirah::JVM::Types
40
40
  begin
41
41
  java_import 'org.mirah.builtins.Builtins'
42
42
  rescue NameError
43
- $CLASSPATH << File.dirname(__FILE__) + '/../../../../javalib/mirah-builtins.jar'
44
- begin
45
- java_import 'org.mirah.builtins.Builtins'
46
- rescue NameError
47
- # We might be trying to compile mirah-builtins.jar, so just continue.
48
- Builtins = nil
49
- end
43
+ # We might be trying to compile mirah-builtins.jar, so just continue.
44
+ Builtins = nil
50
45
  end
51
46
 
52
47
  java_import 'java.net.URLClassLoader'
@@ -67,6 +62,7 @@ module Mirah::JVM::Types
67
62
  @declarations = []
68
63
  @mirrors = {}
69
64
  @futures = {}
65
+ @fields = {}
70
66
  create_basic_types
71
67
  end
72
68
 
@@ -77,12 +73,13 @@ module Mirah::JVM::Types
77
73
  end
78
74
  @declarations = []
79
75
  @futures = {}
76
+ @fields = {}
80
77
  end
81
78
 
82
79
  def maybe_initialize_builtins(compiler)
83
80
  if Builtins
84
81
  begin
85
- Builtins.initialize_builtins(compiler)
82
+ Builtins.initialize_builtins(compiler.type_system)
86
83
  rescue NativeException => ex
87
84
  error("Error initializing builtins", ex.cause)
88
85
  rescue => ex
@@ -102,6 +99,7 @@ module Mirah::JVM::Types
102
99
  def cache_and_wrap(resolved_type)
103
100
  @futures[resolved_type.name] ||= wrap(resolved_type)
104
101
  end
102
+
105
103
  def cache_and_wrap_type(name)
106
104
  @futures[name] ||= begin
107
105
  type = type(nil, name)
@@ -115,6 +113,7 @@ module Mirah::JVM::Types
115
113
  def addDefaultImports(scope)
116
114
  scope.import('java.lang.*', '*')
117
115
  end
116
+
118
117
  def getNullType; cache_and_wrap_type('null') end
119
118
  def getImplicitNilType; cache_and_wrap_type('implicit_nil') end
120
119
  def getVoidType; cache_and_wrap_type('void') end
@@ -166,6 +165,7 @@ module Mirah::JVM::Types
166
165
  future
167
166
  end
168
167
  end
168
+
169
169
  def getSuperClass(future)
170
170
  superclass = BaseTypeFuture.new(nil)
171
171
  future.on_update do |_, type|
@@ -173,6 +173,7 @@ module Mirah::JVM::Types
173
173
  end
174
174
  superclass
175
175
  end
176
+
176
177
  def getArrayType(type)
177
178
  if type.kind_of?(Type)
178
179
  type.array_type
@@ -182,6 +183,7 @@ module Mirah::JVM::Types
182
183
  future
183
184
  end
184
185
  end
186
+
185
187
  def box(type)
186
188
  boxed = BaseTypeFuture.new(nil)
187
189
  type.on_update do |_, resolved|
@@ -205,6 +207,7 @@ module Mirah::JVM::Types
205
207
  log("Error inferring generics: #{ex.message}\n#{ex.backtrace.join("\n")}")
206
208
  cache_and_wrap_type('java.util.List')
207
209
  end
210
+
208
211
  def getHashLiteralType(key_type, value_type, position)
209
212
  result = Mirah::JVM::Types::GenericType.new(type(nil, 'java.util.HashMap')) # Upgrade to a generic type.
210
213
  generic_key, generic_value = result.type_parameters
@@ -218,6 +221,7 @@ module Mirah::JVM::Types
218
221
  log("Error inferring generics: #{ex.message}\n#{ex.backtrace.join("\n")}")
219
222
  cache_and_wrap_type('java.util.HashMap')
220
223
  end
224
+
221
225
  def get(scope, typeref)
222
226
  basic_type = if scope.nil?
223
227
  cache_and_wrap_type(typeref.name)
@@ -246,6 +250,7 @@ module Mirah::JVM::Types
246
250
  basic_type
247
251
  end
248
252
  end
253
+
249
254
  def getLocalType(scope, name, position)
250
255
  scope.local_type(name, position)
251
256
  end
@@ -270,12 +275,14 @@ module Mirah::JVM::Types
270
275
  type = BaseTypeFuture.new(nil)
271
276
  target.find_method2(target, name, argTypes, macroTypes, target.meta?, scope) do |method|
272
277
  if method.nil?
273
- type.resolved(ErrorType.new([
274
- ["Cannot find %s method %s(%s) on %s" %
275
- [ target.meta? ? "static" : "instance",
276
- name,
277
- argTypes.map{|t| t ? t.full_name : "?"}.join(', '),
278
- target.full_name], position]]))
278
+ unless argTypes.any?{|t| t && t.isError && (type.resolved(t); true)}
279
+ type.resolved(ErrorType.new([
280
+ ["Cannot find %s method %s(%s) on %s" %
281
+ [ target.meta? ? "static" : "instance",
282
+ name,
283
+ argTypes.map{|t| t ? t.full_name : "?"}.join(', '),
284
+ target.full_name], position]]))
285
+ end
279
286
  elsif method.kind_of?(Exception)
280
287
  type.resolved(ErrorType.new([[method.message, position]]))
281
288
  else
@@ -404,38 +411,43 @@ module Mirah::JVM::Types
404
411
  end
405
412
  end
406
413
 
407
- def getMethodDefType(target, name, argTypes)
414
+ def getMethodDefType(target, name, argTypes, returnType, position)
408
415
  if target.nil?
409
- return ErrorType.new([["No target"]])
416
+ return ErrorType.new([["No target", position]])
410
417
  end
411
418
  unless argTypes.all? {|a| a.hasDeclaration}
412
419
  infer_override_args(target, name, argTypes)
413
420
  end
421
+ if returnType.nil?
422
+ returnType = infer_override_return_type(target, name, argTypes)
423
+ end
424
+
414
425
  args = argTypes.map {|a| a.resolve}
415
426
  target = target.resolve
416
- type = _find_method_type(nil, target, name, args, nil, nil)
427
+ type = _find_method_type(nil, target, name, args, nil, position)
417
428
  type.onUpdate do |m, resolved|
418
- resolved = resolved.returnType if resolved.respond_to?(:returnType)
419
- log "Learned {0} method {1}.{2}({3}) = {4}", [
420
- target.meta? ? "static" : "instance",
421
- target.full_name,
422
- name,
423
- args.map{|a| a.full_name}.join(', '),
424
- resolved.full_name].to_java
425
- rewritten_name = name.sub(/=$/, '_set')
426
- if target.meta?
427
- target.unmeta.declare_static_method(rewritten_name, args, resolved, [])
428
- else
429
- target.declare_method(rewritten_name, args, resolved, []) unless target.isError
429
+ _declare_method(target, name, args, type)
430
+ end
431
+
432
+ args.each_with_index do |arg, i|
433
+ if arg.isError
434
+ argTypes[i].onUpdate do |x, resolved|
435
+ args[i] = resolved
436
+ _declare_method(target, name, args, type)
437
+ end
430
438
  end
431
439
  end
440
+
432
441
  if type.kind_of?(ErrorType)
433
442
  puts "Got error type for method #{name} on #{target.resolve} (#{target.resolve.class})"
434
443
  position = type.position rescue nil
435
444
  return_type = AssignableTypeFuture.new(position)
436
445
  return_type.declare(type, position)
437
- type = MethodFuture.new(name, args, return_type, false, nil)
446
+ type = MethodFuture.new(name, args, return_type, false, position)
447
+ elsif returnType
448
+ type.returnType.declare(returnType, position)
438
449
  end
450
+
439
451
  type.to_java(MethodFuture)
440
452
  rescue => ex
441
453
  target_name = target.respond_to?(:name) ? target.name : target.resolve.name
@@ -444,13 +456,48 @@ module Mirah::JVM::Types
444
456
  return_type.declare(ErrorType.new([["Internal error: #{ex}"]]), nil)
445
457
  MethodFuture.new(name, [], return_type, false, nil)
446
458
  end
459
+
460
+ def _declare_method(target, name, args, type)
461
+ return if args.any? {|a| a.isError }
462
+ return unless type.kind_of?(MethodFuture) && type.returnType.isResolved
463
+ resolved = type.returnType.resolve
464
+ resolved = resolved.returnType if resolved.respond_to?(:returnType)
465
+ log "Learned {0} method {1}.{2}({3}) = {4}", [
466
+ target.meta? ? "static" : "instance",
467
+ target.full_name,
468
+ name,
469
+ args.map{|a| a.full_name}.join(', '),
470
+ resolved.full_name].to_java
471
+ rewritten_name = name.sub(/=$/, '_set')
472
+ if target.meta?
473
+ target.unmeta.declare_static_method(rewritten_name, args, resolved, [])
474
+ else
475
+ target.declare_method(rewritten_name, args, resolved, [])
476
+ end
477
+ end
478
+
479
+ def getFieldType(target, name, position)
480
+ # This is currently only used for fields in the current class
481
+ klass = target.resolve
482
+ key = [klass, name]
483
+ t = @fields[key]
484
+ unless t
485
+ t = AssignableTypeFuture.new(position)
486
+ @fields[key] = t
487
+ t.on_update {|x, resolved| klass.unmeta.declare_field(name, resolved, klass.meta?)}
488
+ end
489
+ t
490
+ end
491
+
447
492
  def getMainType(scope, script)
448
493
  filename = File.basename(script.position.source.name || 'DashE')
449
494
  classname = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(filename)
450
495
  getMetaType(cache_and_wrap(declare_type(scope, classname)))
451
496
  end
497
+
452
498
  def defineType(scope, node, name, superclass, interfaces)
453
499
  # TODO what if superclass or interfaces change later?
500
+ log("Defining type #{name} < #{superclass.resolve.name if superclass} #{interfaces.map{|i|i.resolve.name}.inspect}")
454
501
  type = define_type(scope, node)
455
502
  future = @futures[type.name]
456
503
  if future
@@ -468,6 +515,7 @@ module Mirah::JVM::Types
468
515
  def addMacro(klass, macro)
469
516
  klass.unmeta.add_compiled_macro(macro)
470
517
  end
518
+
471
519
  def extendClass(classname, extensions)
472
520
  get_type(classname).load_extensions(extensions)
473
521
  end
@@ -477,13 +525,27 @@ module Mirah::JVM::Types
477
525
  log("Infering argument types for #{name}")
478
526
  by_name = target.resolve.find_callable_methods(name, true)
479
527
  by_name_and_arity = by_name.select {|m| m.argument_types.size == arg_types.size}
480
- if by_name_and_arity.size == 1
481
- arg_types.zip(by_name_and_arity[0].argument_types).each do |arg, super_arg|
528
+ filtered_args = Set.new(by_name_and_arity.map {|m| m.argument_types})
529
+ if filtered_args.size == 1
530
+ arg_types.zip(filtered_args.first).each do |arg, super_arg|
482
531
  arg.declare(cache_and_wrap(super_arg), arg.position)
483
532
  end
533
+ else
534
+ log("Found method types:")
535
+ filtered_args.each {|args| log(" #{args.map{|a|a.full_name}.inspect}")}
536
+ arg_types.each {|arg| arg.declare(ErrorType.new([["Missing declaration"]]), nil)}
484
537
  # TODO else give a more useful error?
485
538
  end
486
539
  end
540
+
541
+ def infer_override_return_type(target, name, arg_types)
542
+ by_name = target.resolve.find_callable_methods(name, true)
543
+ by_name_and_arity = {}
544
+ by_name.each {|m| by_name_and_arity[m.argument_types] = m if m.argument_types.size == arg_types.size }
545
+ resolved_args = arg_types.map {|a| a.resolve}
546
+ match = by_name_and_arity[resolved_args]
547
+ return cache_and_wrap(match.return_type) if match
548
+ end
487
549
 
488
550
  def define_types(builder)
489
551
  @declarations.each do |declaration|
@@ -513,8 +575,9 @@ module Mirah::JVM::Types
513
575
  end
514
576
  orig = name
515
577
  if name.kind_of? Java::JavaClass
578
+ #TODO is is possible to get here anymore?
516
579
  if name.array?
517
- return type(name.component_type, true)
580
+ return type(scope, name.component_type, true)
518
581
  else
519
582
  name = name.name
520
583
  end
@@ -573,10 +636,10 @@ module Mirah::JVM::Types
573
636
  outer_name = $1
574
637
  inner_name = $2
575
638
  outer_type = get_type(outer_name)
576
- return nil if outer_type.nil?
639
+ return nil unless outer_type
577
640
  full_name = "#{outer_type.name}$#{inner_name}"
578
641
  mirror = get_mirror(full_name)
579
- return nil if mirror.nil?
642
+ return nil unless mirror
580
643
  else
581
644
  return nil
582
645
  end
@@ -655,16 +718,25 @@ module Mirah::JVM::Types
655
718
  end.to_java(java.net.URL)
656
719
  end
657
720
 
721
+ def base_classpath
722
+ if __FILE__.include? '.jar'
723
+ Mirah::Env.encode_paths([__FILE__.split('!').first.split(':').last])
724
+ else
725
+ Mirah::Env.encode_paths(['.',
726
+ File.dirname(__FILE__) + '/../../../../javalib/mirah-builtins.jar',
727
+ File.dirname(__FILE__) + '/../../../../javalib/mirah-parser.jar',
728
+ File.dirname(__FILE__) + '/../../../../javalib/mirah-bootstrap.jar'])
729
+ end
730
+ end
731
+
658
732
  def classpath
659
- @classpath ||= Mirah::Env.encode_paths(['.',
660
- #TODO nh make this less hacked together.
661
- File.dirname(__FILE__) + '/../../../../javalib/mirah-builtins.jar',
662
- File.dirname(__FILE__) + '/../../../../javalib/mirah-parser.jar',
663
- File.dirname(__FILE__) + '/../../../../javalib/mirah-bootstrap.jar'])
733
+ @classpath ||= base_classpath
664
734
  end
665
735
 
666
736
  def classpath=(classpath)
667
- @classpath = classpath
737
+ if classpath
738
+ @classpath = classpath + ":" + base_classpath
739
+ end
668
740
  @resource_loader = nil
669
741
  end
670
742
 
@@ -695,18 +767,31 @@ module Mirah::JVM::Types
695
767
 
696
768
  attr_reader :bootclasspath
697
769
 
770
+ def mirror_class(klass)
771
+ name = klass.name.tr('.', '/')
772
+ if klass.respond_to?(:resource_as_stream)
773
+ stream = klass.resource_as_stream("/#{name}.class")
774
+ elsif klass.respond_to?(:get_resource_as_stream)
775
+ stream = klass.get_resource_as_stream("/#{name}.class")
776
+ else
777
+ return get_mirror(klass.name)
778
+ end
779
+ BiteScript::ASM::ClassMirror.load(stream)
780
+ end
781
+
698
782
  def get_mirror(name)
699
783
  @mirrors[name] ||= begin
700
784
  classname = name.tr('.', '/')
701
785
  stream = resource_loader.getResourceAsStream(classname + ".class")
702
786
  if stream
703
- BiteScript::ASM::ClassMirror.load(stream)
787
+ mirror = BiteScript::ASM::ClassMirror.load(stream)
788
+ mirror if mirror.type.class_name == name
704
789
  else
705
790
  # TODO(ribrdb) Should this use a separate sourcepath?
706
791
  url = resource_loader.getResource(classname + ".java")
707
792
  if url
708
793
  file = java.io.File.new(url.toURI)
709
- mirrors = JavaSourceMirror.load(file, self)
794
+ mirrors = JavaSourceMirror.load(file, self) rescue []
710
795
  mirrors.each do |mirror|
711
796
  @mirrors[mirror.type.class_name] = mirror
712
797
  end if mirrors