mirah 0.0.10-java → 0.0.11-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/History.txt +44 -0
  2. data/README.txt +12 -7
  3. data/Rakefile +13 -12
  4. data/examples/SortClosure$__xform_tmp_1.class +0 -0
  5. data/examples/SortClosure$__xform_tmp_2.class +0 -0
  6. data/examples/SortClosure.class +0 -0
  7. data/examples/macros/StringEachChar$Extension1.class +0 -0
  8. data/javalib/mirah-bootstrap.jar +0 -0
  9. data/lib/mirah/appengine_tasks.rb +8 -6
  10. data/lib/mirah/ast/flow.rb +3 -3
  11. data/lib/mirah/ast/structure.rb +23 -2
  12. data/lib/mirah/commands/base.rb +5 -2
  13. data/lib/mirah/commands/base.rb~ +57 -0
  14. data/lib/mirah/commands/run.rb +15 -8
  15. data/lib/mirah/jvm/compiler/java_source.rb +15 -11
  16. data/lib/mirah/jvm/method_lookup.rb~ +247 -0
  17. data/lib/mirah/jvm/types/bitescript_ext.rb +41 -0
  18. data/lib/mirah/jvm/types/boolean.rb +33 -0
  19. data/lib/mirah/jvm/types/factory.rb +43 -3
  20. data/lib/mirah/jvm/types/integers.rb +1 -14
  21. data/lib/mirah/jvm/types/intrinsics.rb +1 -14
  22. data/lib/mirah/jvm/types/source_mirror.rb +6 -3
  23. data/lib/mirah/parser.rb +2 -6
  24. data/lib/mirah/transform/transformer.rb +2 -0
  25. data/lib/mirah/util/argument_processor.rb +33 -12
  26. data/lib/mirah/util/class_loader.rb +7 -2
  27. data/lib/mirah/util/compilation_state.rb +8 -0
  28. data/lib/mirah/version.rb +1 -1
  29. data/lib/mirah/version.rb~ +18 -0
  30. data/test/core/{test_ast.rb → ast_test.rb} +5 -1
  31. data/test/core/{test_commands.rb → commands_test.rb} +29 -2
  32. data/test/core/{test_compilation.rb → compilation_test.rb} +2 -2
  33. data/test/core/{test_env.rb → env_test.rb} +2 -2
  34. data/test/core/{test_macros.rb → macros_test.rb} +2 -2
  35. data/test/core/{test_typer.rb → typer_test.rb} +1 -1
  36. data/test/core/util/argument_processor_test.rb +64 -0
  37. data/test/core/util/class_loader_test.rb +31 -0
  38. data/test/fixtures/my.properties +0 -0
  39. data/test/fixtures/org/foo/A.class +0 -0
  40. data/test/jvm/{test_annotations.rb → annotations_test.rb} +2 -2
  41. data/test/jvm/blocks_test.rb +262 -0
  42. data/test/jvm/bytecode_test_helper.rb +1 -33
  43. data/test/jvm/constructors_test.rb +110 -0
  44. data/test/jvm/{test_enumerable.rb → enumerable_test.rb} +2 -2
  45. data/test/jvm/factory_test.rb +22 -0
  46. data/test/jvm/{test_java_typer.rb → java_typer_test.rb} +1 -1
  47. data/test/jvm/jvm_compiler_test.rb +2162 -0
  48. data/test/jvm/{test_jvm_compiler.rb → jvm_compiler_test.rb~} +43 -220
  49. data/test/jvm/{test_macros.rb → macros_test.rb} +2 -2
  50. data/test/jvm/{test_main_method.rb → main_method_test.rb} +2 -2
  51. data/test/jvm/{test_rescue.rb → rescue_test.rb} +33 -2
  52. data/test/plugins/{test_gwt.rb → gwt_test.rb} +2 -2
  53. data/test/test_helper.rb +40 -0
  54. metadata +33 -33
  55. data/test/jvm/test_blocks.rb +0 -62
@@ -0,0 +1,247 @@
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
+ module Mirah
17
+ module JVM
18
+ module MethodLookup
19
+ # dummy log; it's expected the inclusion target will have it
20
+ def log(msg); end
21
+
22
+ def find_method(mapped_type, name, mapped_params, meta)
23
+ raise ArgumentError if mapped_params.any? {|p| p.nil?}
24
+ if name == 'new'
25
+ if meta
26
+ name = "<init>"
27
+ constructor = true
28
+ else
29
+ constructor = false
30
+ end
31
+ end
32
+
33
+ begin
34
+ if constructor
35
+ method = mapped_type.constructor(*mapped_params)
36
+ else
37
+ method = mapped_type.java_method(name, *mapped_params)
38
+ end
39
+ rescue NameError
40
+ # exact args failed, do a deeper search
41
+ log "No exact match for #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})"
42
+
43
+ method = find_jls(mapped_type, name, mapped_params, meta, constructor)
44
+
45
+ unless method
46
+ log "Failed to locate method #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})"
47
+ return nil
48
+ end
49
+ end
50
+
51
+ log "Found method #{method.declaring_class.name}.#{name}(#{method.argument_types.map(&:name).join ', '}) from #{mapped_type.name}"
52
+ return method
53
+ end
54
+
55
+ def find_jls(mapped_type, name, mapped_params, meta, constructor)
56
+ interfaces = []
57
+ if constructor
58
+ by_name = mapped_type.unmeta.declared_constructors
59
+ elsif meta
60
+ by_name = mapped_type.declared_class_methods(name)
61
+ else
62
+ by_name = []
63
+ cls = mapped_type
64
+ #<<<<<<< HEAD
65
+ # while cls
66
+ # if cls.full_name != 'error'
67
+ # by_name += cls.declared_instance_methods(name)
68
+ # interfaces.concat(cls.interfaces)
69
+ # end
70
+ #=======
71
+ while cls && !cls.error?
72
+ by_name += cls.declared_instance_methods(name)
73
+ interfaces.concat(cls.interfaces)
74
+ #>>>>>>> parser_support
75
+ cls = cls.superclass
76
+ end
77
+ if mapped_type.interface? # TODO or abstract
78
+ seen = {}
79
+ until interfaces.empty?
80
+ interface = interfaces.pop
81
+ #<<<<<<< HEAD
82
+ # next if seen[interface]
83
+ #=======
84
+ next if seen[interface] || interface.error?
85
+ #>>>>>>> parser_support
86
+ seen[interface] = true
87
+ interfaces.concat(interface.interfaces)
88
+ by_name += interface.declared_instance_methods(name)
89
+ end
90
+ end
91
+ end
92
+ # filter by arity
93
+ by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size}
94
+
95
+ phase1_methods = phase1(mapped_params, by_name_and_arity)
96
+
97
+ if phase1_methods.size > 1
98
+ method_list = phase1_methods.map do |m|
99
+
100
+ "#{m.name}(#{m.parameter_types.map(&:name).join(', ')})"
101
+ end.join("\n")
102
+ raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{method_list}"
103
+ end
104
+
105
+ phase1_methods[0] ||
106
+ phase2(mapped_params, by_name) ||
107
+ phase3(mapped_params, by_name) ||
108
+ field_lookup(mapped_params, mapped_type, meta, name) ||
109
+ inner_class(mapped_params, mapped_type, meta, name)
110
+ end
111
+
112
+ def phase1(mapped_params, potentials)
113
+ log "Beginning JLS phase 1 search with params (#{mapped_params.map(&:name)})"
114
+
115
+ # cycle through methods looking for more specific matches; gather matches of equal specificity
116
+ methods = potentials.inject([]) do |currents, potential|
117
+ method_params = potential.argument_types
118
+ raise "Bad arguments for method #{potential.declaring_class}.#{potential.name}" unless method_params.all?
119
+
120
+ # exact match always wins; duplicates not possible
121
+ if each_is_exact(mapped_params, method_params)
122
+ return [potential]
123
+ end
124
+
125
+ # otherwise, check for potential match and compare to current
126
+ # TODO: missing ambiguity check; picks last method of equal specificity
127
+ if each_is_exact_or_subtype_or_convertible(mapped_params, method_params)
128
+ if currents.size > 0
129
+ if is_more_specific?(potential.argument_types, currents[0].argument_types)
130
+ # potential is better, dump all currents
131
+ currents = [potential]
132
+ elsif is_more_specific?(currents[0].argument_types, potential.argument_types)
133
+ # currents are better, try next potential
134
+ #next
135
+ else
136
+ # equal specificity, append to currents
137
+ currents << potential
138
+ end
139
+ else
140
+ # no previous matches, use potential
141
+ currents = [potential]
142
+ end
143
+ end
144
+
145
+ currents
146
+ end
147
+
148
+ methods
149
+ end
150
+
151
+ def is_more_specific?(potential, current)
152
+ each_is_exact_or_subtype_or_convertible(potential, current)
153
+ end
154
+
155
+ def phase2(mapped_params, potentials)
156
+ nil
157
+ end
158
+
159
+ def phase3(mapped_params, potentials)
160
+ nil
161
+ end
162
+
163
+ def field_lookup(mapped_params, mapped_type, meta, name)
164
+ log("Attempting #{meta ? 'static' : 'instance'} field lookup for '#{name}' on class #{mapped_type}")
165
+ # if we get to this point, the potentials do not match, so we ignore them
166
+
167
+
168
+ # search for a field of the given name
169
+ if name =~ /_set$/
170
+ # setter
171
+ setter = true
172
+ name = name[0..-5]
173
+ field = mapped_type.field_setter(name)
174
+ else
175
+ # getter
176
+ setter = false
177
+
178
+ # field accesses don't take arguments
179
+ return if mapped_params.size > 0
180
+ field = mapped_type.field_getter(name)
181
+ end
182
+
183
+ return nil unless field
184
+
185
+ if (meta && !field.static?) ||
186
+ (!meta && field.static?)
187
+ field == nil
188
+ end
189
+
190
+ # check accessibility
191
+ # TODO: protected field access check appropriate to current type
192
+ if setter
193
+ raise "cannot set final field '#{name}' on class #{mapped_type}" if field.final?
194
+ end
195
+ raise "cannot access field '#{name}' on class #{mapped_type}" unless field.public?
196
+
197
+ field
198
+ end
199
+
200
+ def inner_class(params, type, meta, name)
201
+ return unless params.size == 0 && meta
202
+ log("Attempting inner class lookup for '#{name}' on #{type}")
203
+ type.inner_class_getter(name)
204
+ end
205
+
206
+ def each_is_exact(incoming, target)
207
+ incoming.each_with_index do |in_type, i|
208
+ target_type = target[i]
209
+
210
+ # exact match
211
+ return false unless target_type == in_type
212
+ end
213
+ return true
214
+ end
215
+
216
+ def each_is_exact_or_subtype_or_convertible(incoming, target)
217
+ incoming.each_with_index do |in_type, i|
218
+ target_type = target[i]
219
+
220
+ # exact match
221
+ next if target_type == in_type
222
+
223
+ # primitive is safely convertible
224
+ if target_type.primitive?
225
+ if in_type.primitive?
226
+ next if primitive_convertible? in_type, target_type
227
+ end
228
+ return false
229
+ end
230
+
231
+ # object type is assignable
232
+ compatible = if target_type.respond_to?(:compatible?)
233
+ target_type.compatible? in_type
234
+ else
235
+ target_type.assignable_from? in_type
236
+ end
237
+ return false unless compatible
238
+ end
239
+ return true
240
+ end
241
+
242
+ def primitive_convertible?(in_type, target_type)
243
+ in_type.convertible_to?(target_type)
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,41 @@
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 BiteScript::MethodBuilder
17
+ def inot
18
+ iconst_m1
19
+ ixor
20
+ end
21
+
22
+ def lnot
23
+ # TODO would any of these be faster?
24
+ # iconst_m1; i2l
25
+ # lconst_1; lneg
26
+ ldc_long(-1)
27
+ ixor
28
+ end
29
+
30
+ def op_to_bool
31
+ done_label = label
32
+ true_label = label
33
+
34
+ yield(true_label)
35
+ iconst_0
36
+ goto(done_label)
37
+ true_label.set!
38
+ iconst_1
39
+ done_label.set!
40
+ end
41
+ end
@@ -28,5 +28,38 @@ module Mirah::JVM::Types
28
28
  builder.invokestatic box_type, "valueOf", [box_type, self]
29
29
  end
30
30
 
31
+ def add_intrinsics
32
+ args = [math_type]
33
+ add_method('==', args, ComparisonIntrinsic.new(self, '==', :eq, args))
34
+ add_method('!=', args, ComparisonIntrinsic.new(self, '!=', :ne, args))
35
+ end
36
+
37
+ def math_type
38
+ Boolean
39
+ end
40
+
41
+ # same as NumberType's
42
+ def compile_boolean_operator(compiler, op, negated, call, label)
43
+ # Promote the target or the argument if necessary
44
+ convert_args(compiler,
45
+ [call.target, *call.parameters],
46
+ [math_type, math_type])
47
+ if negated
48
+ op = invert_op(op)
49
+ end
50
+ if label
51
+ jump_if(compiler.method, op, label)
52
+ else
53
+ compiler.method.op_to_bool do |label|
54
+ jump_if(compiler.method, op, label)
55
+ end
56
+ end
57
+ end
58
+
59
+ # Same as IntegerType's
60
+ # bools are ints for comparison purposes
61
+ def jump_if(builder, op, label)
62
+ builder.send "if_icmp#{op}", label
63
+ end
31
64
  end
32
65
  end
@@ -40,6 +40,7 @@ module Mirah::JVM::Types
40
40
  "null" => Null,
41
41
  "dynamic" => DynamicType.new
42
42
  }.freeze
43
+ java_import 'java.net.URLClassLoader'
43
44
 
44
45
  attr_accessor :package
45
46
  attr_reader :known_types
@@ -218,14 +219,53 @@ module Mirah::JVM::Types
218
219
  Unreachable
219
220
  end
220
221
 
222
+ def make_urls(classpath)
223
+ Mirah::Env.decode_paths(classpath).map do |filename|
224
+ java.io.File.new(filename).to_uri.to_url
225
+ end.to_java(java.net.URL)
226
+ end
227
+
228
+ def classpath
229
+ @classpath ||= '.'
230
+ end
231
+
232
+ def classpath=(classpath)
233
+ @classpath = classpath
234
+ @resource_loader = nil
235
+ end
236
+
237
+ def resource_loader
238
+ @resource_loader ||= URLClassLoader.new(make_urls(classpath), bootstrap_loader)
239
+ end
240
+
241
+ def bootstrap_loader
242
+ @bootstrap_loader ||= begin
243
+ parent = if bootclasspath
244
+ Mirah::Util::IsolatedResourceLoader.new(make_urls(bootclasspath))
245
+ end
246
+ bootstrap_jar = File.expand_path("#{__FILE__}/../../../../../javalib/mirah-bootstrap.jar")
247
+ bootstrap_urls = [java.io.File.new(bootstrap_jar).to_uri.to_url].to_java(java.net.URL)
248
+ URLClassLoader.new(bootstrap_urls, parent)
249
+ end
250
+ end
251
+
252
+ def bootclasspath=(classpath)
253
+ @bootclasspath = classpath
254
+ @bootstrap_loader = nil
255
+ @resource_loader = nil
256
+ end
257
+
258
+ attr_reader :bootclasspath
259
+
221
260
  def get_mirror(name)
222
261
  @mirrors[name] ||= begin
223
262
  classname = name.tr('.', '/')
224
- stream = JRuby.runtime.jruby_class_loader.getResourceAsStream(classname + ".class")
263
+ stream = resource_loader.getResourceAsStream(classname + ".class")
225
264
  if stream
226
265
  BiteScript::ASM::ClassMirror.load(stream) if stream
227
266
  else
228
- url = JRuby.runtime.jruby_class_loader.getResource(classname + ".java")
267
+ # TODO(ribrdb) Should this use a separate sourcepath?
268
+ url = resource_loader.getResource(classname + ".java")
229
269
  if url
230
270
  file = java.io.File.new(url.toURI)
231
271
  mirrors = JavaSourceMirror.load(file, self)
@@ -240,4 +280,4 @@ module Mirah::JVM::Types
240
280
  end
241
281
  end
242
282
  end
243
- end
283
+ end
@@ -13,20 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- class BiteScript::MethodBuilder
17
- def inot
18
- iconst_m1
19
- ixor
20
- end
21
-
22
- def lnot
23
- # TODO would any of these be faster?
24
- # iconst_m1; i2l
25
- # lconst_1; lneg
26
- ldc_long(-1)
27
- ixor
28
- end
29
- end
16
+ require 'mirah/jvm/types/bitescript_ext'
30
17
 
31
18
  module Mirah::JVM::Types
32
19
  class IntegerType < Number
@@ -15,20 +15,7 @@
15
15
 
16
16
  require 'bitescript'
17
17
  require 'mirah/jvm/types/enumerable'
18
-
19
- class BiteScript::MethodBuilder
20
- def op_to_bool
21
- done_label = label
22
- true_label = label
23
-
24
- yield(true_label)
25
- iconst_0
26
- goto(done_label)
27
- true_label.set!
28
- iconst_1
29
- done_label.set!
30
- end
31
- end
18
+ require 'mirah/jvm/types/bitescript_ext'
32
19
 
33
20
  module Mirah::JVM::Types
34
21
  class Type
@@ -80,10 +80,13 @@ module Mirah::JVM::Types
80
80
  end
81
81
 
82
82
  def classpath
83
- [
84
- '-classpath',
85
- $CLASSPATH.to_a.join(java.io.File.pathSeparator)
83
+ options = [
84
+ '-classpath', Mirah::AST.type_factory.classpath
86
85
  ]
86
+ if Mirah::AST.type_factory.bootclasspath
87
+ options << '-bootclasspath' << Mirah::AST.type_factory.bootclasspath
88
+ end
89
+ options
87
90
  end
88
91
 
89
92
  def get_java_file(tools)