mirah 0.1.0.pre-java → 0.1.1-java

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