mirah 0.0.10-java → 0.0.11-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.
- data/History.txt +44 -0
- data/README.txt +12 -7
- data/Rakefile +13 -12
- data/examples/SortClosure$__xform_tmp_1.class +0 -0
- data/examples/SortClosure$__xform_tmp_2.class +0 -0
- data/examples/SortClosure.class +0 -0
- data/examples/macros/StringEachChar$Extension1.class +0 -0
- data/javalib/mirah-bootstrap.jar +0 -0
- data/lib/mirah/appengine_tasks.rb +8 -6
- data/lib/mirah/ast/flow.rb +3 -3
- data/lib/mirah/ast/structure.rb +23 -2
- data/lib/mirah/commands/base.rb +5 -2
- data/lib/mirah/commands/base.rb~ +57 -0
- data/lib/mirah/commands/run.rb +15 -8
- data/lib/mirah/jvm/compiler/java_source.rb +15 -11
- data/lib/mirah/jvm/method_lookup.rb~ +247 -0
- data/lib/mirah/jvm/types/bitescript_ext.rb +41 -0
- data/lib/mirah/jvm/types/boolean.rb +33 -0
- data/lib/mirah/jvm/types/factory.rb +43 -3
- data/lib/mirah/jvm/types/integers.rb +1 -14
- data/lib/mirah/jvm/types/intrinsics.rb +1 -14
- data/lib/mirah/jvm/types/source_mirror.rb +6 -3
- data/lib/mirah/parser.rb +2 -6
- data/lib/mirah/transform/transformer.rb +2 -0
- data/lib/mirah/util/argument_processor.rb +33 -12
- data/lib/mirah/util/class_loader.rb +7 -2
- data/lib/mirah/util/compilation_state.rb +8 -0
- data/lib/mirah/version.rb +1 -1
- data/lib/mirah/version.rb~ +18 -0
- data/test/core/{test_ast.rb → ast_test.rb} +5 -1
- data/test/core/{test_commands.rb → commands_test.rb} +29 -2
- data/test/core/{test_compilation.rb → compilation_test.rb} +2 -2
- data/test/core/{test_env.rb → env_test.rb} +2 -2
- data/test/core/{test_macros.rb → macros_test.rb} +2 -2
- data/test/core/{test_typer.rb → typer_test.rb} +1 -1
- data/test/core/util/argument_processor_test.rb +64 -0
- data/test/core/util/class_loader_test.rb +31 -0
- data/test/fixtures/my.properties +0 -0
- data/test/fixtures/org/foo/A.class +0 -0
- data/test/jvm/{test_annotations.rb → annotations_test.rb} +2 -2
- data/test/jvm/blocks_test.rb +262 -0
- data/test/jvm/bytecode_test_helper.rb +1 -33
- data/test/jvm/constructors_test.rb +110 -0
- data/test/jvm/{test_enumerable.rb → enumerable_test.rb} +2 -2
- data/test/jvm/factory_test.rb +22 -0
- data/test/jvm/{test_java_typer.rb → java_typer_test.rb} +1 -1
- data/test/jvm/jvm_compiler_test.rb +2162 -0
- data/test/jvm/{test_jvm_compiler.rb → jvm_compiler_test.rb~} +43 -220
- data/test/jvm/{test_macros.rb → macros_test.rb} +2 -2
- data/test/jvm/{test_main_method.rb → main_method_test.rb} +2 -2
- data/test/jvm/{test_rescue.rb → rescue_test.rb} +33 -2
- data/test/plugins/{test_gwt.rb → gwt_test.rb} +2 -2
- data/test/test_helper.rb +40 -0
- metadata +33 -33
- 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 =
|
263
|
+
stream = resource_loader.getResourceAsStream(classname + ".class")
|
225
264
|
if stream
|
226
265
|
BiteScript::ASM::ClassMirror.load(stream) if stream
|
227
266
|
else
|
228
|
-
|
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
|
-
|
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)
|