mirah 0.0.12-java → 0.1.0-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 +372 -0
- data/README.txt +4 -5
- data/Rakefile +178 -55
- data/examples/appengine/Readme +3 -3
- data/examples/appengine/src/org/mirah/MirahApp.mirah +1 -1
- data/examples/appengine/src/org/mirah/list.dhtml +1 -1
- data/examples/bintrees.mirah +1 -1
- data/examples/edb.mirah +1 -1
- data/examples/fib.mirah +1 -1
- data/examples/interfaces.mirah +1 -1
- data/examples/macros/{string-each-char.mirah → string_each_char.mirah} +4 -5
- data/examples/maven/README.txt +1 -1
- data/examples/maven/src/main/mirah/hello_mirah.mirah +1 -1
- data/examples/plugins/appengine/Rakefile +1 -1
- data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/MetaModel.mirah +1 -1
- data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +1 -1
- data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +1 -1
- data/examples/rosettacode/100-doors.mirah +6 -6
- data/examples/rosettacode/README.txt +3 -3
- data/examples/rosettacode/boolean-values.mirah +1 -1
- data/examples/rosettacode/comments.mirah +1 -1
- data/examples/rosettacode/count-occurrences-of-a-substring.mirah +1 -1
- data/examples/rosettacode/factorial.mirah +1 -1
- data/examples/rosettacode/fibonacci.mirah +1 -1
- data/examples/rosettacode/fizz-buzz.mirah +2 -2
- data/examples/rosettacode/flatten-a-list.mirah +4 -4
- data/examples/rosettacode/guess-the-number.mirah +2 -2
- data/examples/rosettacode/hamming-numbers.mirah +4 -4
- data/examples/rosettacode/is-string-numeric.mirah +22 -22
- data/examples/rosettacode/palindrome.mirah +2 -2
- data/examples/rosettacode/random-numbers.mirah +1 -1
- data/examples/rosettacode/repeat-a-string.mirah +1 -1
- data/examples/rosettacode/reverse-a-string.mirah +1 -1
- data/examples/rosettacode/rot-13.mirah +5 -5
- data/examples/rosettacode/secure-temporary-file.mirah +2 -2
- data/examples/rosettacode/sleep.mirah +1 -1
- data/examples/rosettacode/string-length.mirah +5 -5
- data/examples/swing.mirah +1 -1
- data/examples/test.edb +1 -1
- data/javalib/mirah-bootstrap.jar +0 -0
- data/javalib/mirah-builtins.jar +0 -0
- data/javalib/mirah-parser.jar +0 -0
- data/javalib/mirah-util.jar +0 -0
- data/lib/duby.rb +1 -1
- data/lib/mirah.rb +50 -28
- data/lib/mirah/ast.rb +15 -605
- data/lib/mirah/ast/scope.rb +98 -69
- data/lib/mirah/commands.rb +1 -1
- data/lib/mirah/commands/base.rb +7 -7
- data/lib/mirah/commands/compile.rb +3 -3
- data/lib/mirah/commands/parse.rb +7 -5
- data/lib/mirah/commands/run.rb +12 -19
- data/lib/mirah/compiler.rb +15 -23
- data/lib/mirah/errors.rb +16 -1
- data/lib/mirah/generator.rb +79 -39
- data/lib/mirah/jvm/compiler.rb +1 -19
- data/lib/mirah/jvm/compiler/base.rb +233 -90
- data/lib/mirah/jvm/compiler/jvm_bytecode.rb +675 -363
- data/lib/mirah/jvm/method_lookup.rb +134 -65
- data/lib/mirah/jvm/typer.rb +10 -5
- data/lib/mirah/jvm/types.rb +10 -2
- data/lib/mirah/jvm/types/array_type.rb +10 -12
- data/lib/mirah/{compiler/type.rb → jvm/types/ast_ext.rb} +12 -8
- data/lib/mirah/jvm/types/basic_types.rb +26 -33
- data/lib/mirah/jvm/types/bitescript_ext.rb +1 -1
- data/lib/mirah/jvm/types/block_type.rb +15 -0
- data/lib/mirah/jvm/types/boolean.rb +8 -4
- data/lib/mirah/jvm/types/dynamic_type.rb +12 -13
- data/lib/mirah/jvm/types/enumerable.rb +7 -7
- data/lib/mirah/jvm/types/extensions.rb +11 -6
- data/lib/mirah/jvm/types/factory.rb +624 -94
- data/lib/mirah/jvm/types/floats.rb +21 -15
- data/lib/mirah/jvm/types/generic_type.rb +72 -0
- data/lib/mirah/jvm/types/implicit_nil_type.rb +29 -0
- data/lib/mirah/jvm/types/integers.rb +26 -71
- data/lib/mirah/jvm/types/interface_definition.rb +3 -3
- data/lib/mirah/jvm/types/intrinsics.rb +203 -168
- data/lib/mirah/jvm/types/literals.rb +6 -6
- data/lib/mirah/jvm/types/meta_type.rb +13 -4
- data/lib/mirah/jvm/types/methods.rb +281 -93
- data/lib/mirah/jvm/types/null_type.rb +17 -5
- data/lib/mirah/jvm/types/number.rb +10 -7
- data/lib/mirah/jvm/types/primitive_type.rb +17 -6
- data/lib/mirah/jvm/types/source_mirror.rb +12 -7
- data/lib/mirah/jvm/types/type.rb +107 -23
- data/lib/mirah/jvm/types/type_definition.rb +25 -10
- data/lib/mirah/jvm/types/unreachable_type.rb +1 -1
- data/lib/mirah/jvm/types/void_type.rb +3 -3
- data/lib/mirah/parser.rb +154 -16
- data/lib/mirah/plugin/edb.rb +1 -1
- data/lib/mirah/transform.rb +1 -2
- data/lib/mirah/transform/ast_ext.rb +24 -43
- data/lib/mirah/transform/transformer.rb +29 -224
- data/lib/mirah/typer.rb +2 -16
- data/lib/mirah/util/argument_processor.rb +25 -10
- data/lib/mirah/util/class_loader.rb +1 -1
- data/lib/mirah/util/compilation_state.rb +16 -17
- data/lib/mirah/util/delegate.rb +2 -2
- data/lib/mirah/util/logging.rb +110 -0
- data/lib/mirah/util/process_errors.rb +69 -11
- data/lib/mirah/version.rb +1 -1
- data/test/core/commands_test.rb +6 -24
- data/test/core/env_test.rb +5 -5
- data/{lib/mirah/jvm/source_generator/typer.rb → test/core/generator_test.rb} +9 -9
- data/test/core/typer_test.rb +196 -158
- data/test/core/util/argument_processor_test.rb +10 -10
- data/test/core/util/class_loader_test.rb +6 -5
- data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass.java +7 -0
- data/test/jvm/annotations_test.rb +5 -5
- data/test/jvm/blocks_test.rb +140 -88
- data/test/jvm/bytecode_test_helper.rb +112 -94
- data/test/jvm/cast_test.rb +162 -0
- data/test/jvm/constructors_test.rb +18 -8
- data/test/jvm/enumerable_test.rb +77 -44
- data/test/jvm/example_test.rb +53 -0
- data/test/jvm/factory_test.rb +7 -1
- data/test/jvm/generics_test.rb +57 -0
- data/test/jvm/hash_test.rb +106 -0
- data/test/jvm/import_test.rb +81 -0
- data/test/jvm/interface_test.rb +73 -0
- data/test/jvm/java_typer_test.rb +92 -66
- data/{lib/mirah/typer/base.rb → test/jvm/jvm_commands_test.rb} +6 -10
- data/test/jvm/jvm_compiler_test.rb +170 -604
- data/test/jvm/list_extensions_test.rb +23 -0
- data/test/jvm/macros_test.rb +197 -32
- data/test/jvm/main_method_test.rb +4 -4
- data/test/jvm/numeric_extensions_test.rb +13 -0
- data/test/jvm/rescue_test.rb +73 -16
- data/test/jvm/varargs_test.rb +65 -0
- data/test/test_helper.rb +1 -2
- metadata +234 -251
- 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/lib/mirah/ast/call.rb +0 -345
- data/lib/mirah/ast/class.rb +0 -359
- data/lib/mirah/ast/flow.rb +0 -381
- data/lib/mirah/ast/intrinsics.rb +0 -563
- data/lib/mirah/ast/literal.rb +0 -178
- data/lib/mirah/ast/local.rb +0 -112
- data/lib/mirah/ast/method.rb +0 -408
- data/lib/mirah/ast/structure.rb +0 -387
- data/lib/mirah/ast/type.rb +0 -146
- data/lib/mirah/commands/base.rb~ +0 -57
- data/lib/mirah/compiler/call.rb +0 -45
- data/lib/mirah/compiler/class.rb +0 -81
- data/lib/mirah/compiler/flow.rb +0 -109
- data/lib/mirah/compiler/literal.rb +0 -130
- data/lib/mirah/compiler/local.rb +0 -59
- data/lib/mirah/compiler/method.rb +0 -44
- data/lib/mirah/compiler/structure.rb +0 -65
- data/lib/mirah/jvm/compiler/java_source.rb +0 -787
- data/lib/mirah/jvm/method_lookup.rb~ +0 -247
- data/lib/mirah/jvm/source_generator/builder.rb +0 -468
- data/lib/mirah/jvm/source_generator/loops.rb +0 -131
- data/lib/mirah/jvm/source_generator/precompile.rb +0 -210
- data/lib/mirah/plugin/gwt.rb +0 -189
- data/lib/mirah/plugin/java.rb +0 -70
- data/lib/mirah/transform/error.rb +0 -13
- data/lib/mirah/transform/helper.rb +0 -765
- data/lib/mirah/typer/simple.rb +0 -384
- data/lib/mirah/version.rb~ +0 -18
- data/test/core/ast_test.rb +0 -382
- data/test/core/compilation_test.rb +0 -130
- data/test/core/macros_test.rb +0 -61
- data/test/jvm/javac_test_helper.rb +0 -89
- data/test/jvm/jvm_compiler_test.rb~ +0 -2181
- data/test/plugins/gwt_test.rb +0 -69
|
@@ -1,247 +0,0 @@
|
|
|
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
|
|
@@ -1,468 +0,0 @@
|
|
|
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
|
-
require 'mirah/jvm/types'
|
|
17
|
-
|
|
18
|
-
module Mirah
|
|
19
|
-
class JVM::Types::Type
|
|
20
|
-
def to_source
|
|
21
|
-
java_name = name
|
|
22
|
-
java_name = java_name.tr('$', '.')
|
|
23
|
-
"#{java_name}#{'[]' if array?}"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
module JavaSource
|
|
28
|
-
JVMTypes ||= Mirah::JVM::Types
|
|
29
|
-
|
|
30
|
-
class Builder
|
|
31
|
-
attr_accessor :package, :classes, :filename, :compiler
|
|
32
|
-
|
|
33
|
-
def initialize(filename, compiler)
|
|
34
|
-
@filename = filename
|
|
35
|
-
@classes = {}
|
|
36
|
-
@compiler = compiler
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def define_class(name, opts={})
|
|
40
|
-
superclass = opts[:superclass]
|
|
41
|
-
interfaces = opts[:interfaces]
|
|
42
|
-
abstract = opts[:abstract]
|
|
43
|
-
cls = ClassBuilder.new(self, name, superclass, interfaces, abstract)
|
|
44
|
-
container = self
|
|
45
|
-
if name.include? ?$
|
|
46
|
-
path = name.split '$'
|
|
47
|
-
name = path.pop
|
|
48
|
-
path.each do |piece|
|
|
49
|
-
container = container.classes[piece]
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
container.classes[name] = cls
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def public_interface(name, *interfaces)
|
|
56
|
-
cls = InterfaceBuilder.new(self, name, interfaces)
|
|
57
|
-
@classes[name] = cls
|
|
58
|
-
cls
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def generate
|
|
62
|
-
@classes.values.each do |cls|
|
|
63
|
-
yield cls.filename, cls
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
class Output
|
|
69
|
-
def initialize
|
|
70
|
-
@out = ""
|
|
71
|
-
@indent = 0
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def puts(*lines)
|
|
75
|
-
lines.each do |line|
|
|
76
|
-
print_indent
|
|
77
|
-
@out << line.to_s
|
|
78
|
-
@out << "\n"
|
|
79
|
-
@indented = false
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def print_indent
|
|
84
|
-
@indent ||= 0
|
|
85
|
-
@out << (' ' * @indent) unless @indented
|
|
86
|
-
@indented = true
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def print(str)
|
|
90
|
-
print_indent
|
|
91
|
-
@out << str.to_s
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def indent
|
|
95
|
-
@indent += 2
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def dedent
|
|
99
|
-
@indent -= 2
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def <<(other)
|
|
103
|
-
other.to_s.each_line do |line|
|
|
104
|
-
print_indent
|
|
105
|
-
print(line)
|
|
106
|
-
@indented = false
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def to_s
|
|
111
|
-
@out
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
module Helper
|
|
116
|
-
def puts(*args)
|
|
117
|
-
@out.puts(*args)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def print(*args)
|
|
121
|
-
@out.print(*args)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def indent
|
|
125
|
-
@out.indent
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def dedent
|
|
129
|
-
@out.dedent
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def block(line='')
|
|
133
|
-
puts line + " {"
|
|
134
|
-
indent
|
|
135
|
-
yield
|
|
136
|
-
dedent
|
|
137
|
-
puts "}"
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def init_value(type)
|
|
141
|
-
# TODO move this to types?
|
|
142
|
-
case type
|
|
143
|
-
when JVMTypes::Boolean
|
|
144
|
-
'false'
|
|
145
|
-
when JVMTypes::PrimitiveType, JVMTypes::NarrowingType
|
|
146
|
-
'0'
|
|
147
|
-
else
|
|
148
|
-
'null'
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def annotate(annotations)
|
|
153
|
-
annotations.each do |annotation|
|
|
154
|
-
puts annotation_value(annotation)
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def annotation_value(value)
|
|
159
|
-
case value
|
|
160
|
-
when Java::JavaLang::Integer
|
|
161
|
-
value.to_s
|
|
162
|
-
when Java::JavaLang::String, String
|
|
163
|
-
value.to_s.inspect
|
|
164
|
-
when Array
|
|
165
|
-
values = value.map{|x|annotation_value(x)}.join(", ")
|
|
166
|
-
"{#{values}}"
|
|
167
|
-
when BiteScript::ASM::Type
|
|
168
|
-
value.getClassName.gsub("$", ".")
|
|
169
|
-
when Mirah::AST::Annotation
|
|
170
|
-
name = value.name.gsub("$", ".")
|
|
171
|
-
values = value.values.map {|n, v| "#{n}=#{annotation_value(v)}"}
|
|
172
|
-
"@#{name}(#{values.join ', '})"
|
|
173
|
-
else
|
|
174
|
-
raise "Unsupported annotation value #{value.inspect}"
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
class ClassBuilder
|
|
180
|
-
include Helper
|
|
181
|
-
include Mirah::JVM::Compiler::JVMBytecode::JVMLogger
|
|
182
|
-
attr_reader :package, :name, :superclass, :filename, :class_name, :out
|
|
183
|
-
attr_reader :interfaces, :abstract
|
|
184
|
-
def initialize(builder, name, superclass, interfaces, abstract)
|
|
185
|
-
@builder = builder
|
|
186
|
-
@package = builder.package
|
|
187
|
-
if @package
|
|
188
|
-
@name = "#{@package}.#{name}"
|
|
189
|
-
else
|
|
190
|
-
@name = name
|
|
191
|
-
end
|
|
192
|
-
if name =~ %r{[/.]}
|
|
193
|
-
pieces = name.split(%r{[/.]})
|
|
194
|
-
name = pieces.pop
|
|
195
|
-
@package = pieces.join('.')
|
|
196
|
-
end
|
|
197
|
-
@class_name = name
|
|
198
|
-
if @class_name =~ /\$([^$]+)/
|
|
199
|
-
@class_name = $1
|
|
200
|
-
@static = true
|
|
201
|
-
@inner_class = true
|
|
202
|
-
end
|
|
203
|
-
@superclass = superclass || JVMTypes::Object
|
|
204
|
-
@interfaces = interfaces
|
|
205
|
-
@filename = "#{name}.java"
|
|
206
|
-
@filename = "#{package.tr('.', '/')}/#{@filename}" if @package
|
|
207
|
-
@out = Output.new
|
|
208
|
-
@stopped = false
|
|
209
|
-
@methods = []
|
|
210
|
-
@fields = {}
|
|
211
|
-
@inner_classes = {}
|
|
212
|
-
@abstract = abstract
|
|
213
|
-
start
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def compiler
|
|
217
|
-
@builder.compiler
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def classes
|
|
221
|
-
@inner_classes
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def start
|
|
225
|
-
unless @inner_class
|
|
226
|
-
puts "// Generated from #{@builder.filename}"
|
|
227
|
-
puts "package #{package};" if package
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def finish_declaration
|
|
232
|
-
return if @declaration_finished
|
|
233
|
-
raise "Already stopped class #{class_name}" if @stopped
|
|
234
|
-
|
|
235
|
-
@declaration_finished = true
|
|
236
|
-
modifiers = "public#{' static' if @static}#{' abstract' if @abstract}"
|
|
237
|
-
print "#{modifiers} class #{class_name} extends #{superclass.name}"
|
|
238
|
-
unless @interfaces.empty?
|
|
239
|
-
print " implements "
|
|
240
|
-
@interfaces.each_with_index do |interface, index|
|
|
241
|
-
print ', ' unless index == 0
|
|
242
|
-
print interface.to_source
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
puts " {"
|
|
246
|
-
indent
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def stop
|
|
250
|
-
return if @stopped
|
|
251
|
-
finish_declaration
|
|
252
|
-
@methods.each do |method|
|
|
253
|
-
@out << method.out
|
|
254
|
-
end
|
|
255
|
-
@inner_classes.values.each do |inner_class|
|
|
256
|
-
@out << inner_class.out
|
|
257
|
-
end
|
|
258
|
-
log "Class #{name} complete (#{@out.to_s.size})"
|
|
259
|
-
@stopped = true
|
|
260
|
-
dedent
|
|
261
|
-
puts "}"
|
|
262
|
-
log "Class #{name} complete (#{@out.to_s.size})"
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
def main
|
|
266
|
-
build_method('main', :public, :static, [], JVMTypes::Void,
|
|
267
|
-
[JVMTypes::String.array_type, 'argv'])
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def declare_field(name, type, static, access='private', annotations=[])
|
|
271
|
-
finish_declaration
|
|
272
|
-
return if @fields[name]
|
|
273
|
-
static = static ? ' static' : ''
|
|
274
|
-
annotate(annotations)
|
|
275
|
-
puts "#{access}#{static} #{type.to_source} #{name};"
|
|
276
|
-
@fields[name] = true
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
def build_method(name, visibility, static, exceptions, type, *args)
|
|
280
|
-
finish_declaration
|
|
281
|
-
type ||= Mirah::AST::type(nil, :void)
|
|
282
|
-
@methods << MethodBuilder.new(self,
|
|
283
|
-
:name => name,
|
|
284
|
-
:visibility => visibility,
|
|
285
|
-
:static => static,
|
|
286
|
-
:return => type,
|
|
287
|
-
:args => args,
|
|
288
|
-
:exceptions => exceptions)
|
|
289
|
-
@methods[-1]
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
def build_constructor(visibility, exceptions, *args)
|
|
293
|
-
finish_declaration
|
|
294
|
-
@methods << MethodBuilder.new(self,
|
|
295
|
-
:name => class_name,
|
|
296
|
-
:visibility => visibility,
|
|
297
|
-
:args => args,
|
|
298
|
-
:exceptions => exceptions)
|
|
299
|
-
@methods[-1]
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
def generate
|
|
303
|
-
stop
|
|
304
|
-
@out.to_s
|
|
305
|
-
end
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
class InterfaceBuilder < ClassBuilder
|
|
309
|
-
def initialize(builder, name, interfaces)
|
|
310
|
-
super(builder, name, nil, interfaces, true)
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
def finish_declaration
|
|
314
|
-
return if @declaration_finished
|
|
315
|
-
@declaration_finished = true
|
|
316
|
-
print "public interface #{class_name}"
|
|
317
|
-
unless @interfaces.empty?
|
|
318
|
-
print " extends "
|
|
319
|
-
@interfaces.each_with_index do |interface, index|
|
|
320
|
-
print ', ' unless index == 0
|
|
321
|
-
print interface.to_source
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
puts " {"
|
|
325
|
-
indent
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
def build_method(name, visibility, static, exceptions, type, *args)
|
|
329
|
-
raise "Interfaces can't have static methods" if static
|
|
330
|
-
finish_declaration
|
|
331
|
-
type ||= Mirah::AST::type(nil, :void)
|
|
332
|
-
@methods << MethodBuilder.new(self,
|
|
333
|
-
:name => name,
|
|
334
|
-
:visibility => visibility,
|
|
335
|
-
:return => type,
|
|
336
|
-
:args => args,
|
|
337
|
-
:abstract => true,
|
|
338
|
-
:exceptions => exceptions)
|
|
339
|
-
@methods[-1]
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
class MethodBuilder
|
|
344
|
-
include Helper
|
|
345
|
-
|
|
346
|
-
attr_accessor :name, :type, :out, :klass
|
|
347
|
-
|
|
348
|
-
def initialize(cls, options)
|
|
349
|
-
@class = cls
|
|
350
|
-
@klass = cls
|
|
351
|
-
@compiler = cls.compiler
|
|
352
|
-
@out = Output.new
|
|
353
|
-
@visibility = options[:visibility]
|
|
354
|
-
@name = options[:name]
|
|
355
|
-
@type = options[:return]
|
|
356
|
-
@typename = @type && @type.to_source
|
|
357
|
-
@locals = {}
|
|
358
|
-
@args = options[:args].map do |arg|
|
|
359
|
-
unless arg.kind_of? Array
|
|
360
|
-
arg = [arg.inferred_type, arg.name]
|
|
361
|
-
end
|
|
362
|
-
@locals[arg[1]] = arg[0]
|
|
363
|
-
arg
|
|
364
|
-
end
|
|
365
|
-
@static = options[:static] ? ' static' : nil
|
|
366
|
-
@abstract = options[:abstract] && ' abstract'
|
|
367
|
-
@exceptions = options[:exceptions] || []
|
|
368
|
-
@temps = 0
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
def start
|
|
372
|
-
print "#{@visibility}#{@static}#{@abstract} #{@typename} #{@name}("
|
|
373
|
-
@args.each_with_index do |(type, name), i|
|
|
374
|
-
print ', ' unless i == 0
|
|
375
|
-
print "#{type.to_source} #{name}"
|
|
376
|
-
end
|
|
377
|
-
print ')'
|
|
378
|
-
unless @exceptions.empty?
|
|
379
|
-
print ' throws '
|
|
380
|
-
@exceptions.each_with_index do |exception, i|
|
|
381
|
-
print ', ' unless i == 0
|
|
382
|
-
print exception.to_source
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
if @abstract
|
|
386
|
-
puts ";"
|
|
387
|
-
def self.puts(*args); end
|
|
388
|
-
def self.print(*args); end
|
|
389
|
-
else
|
|
390
|
-
puts " {"
|
|
391
|
-
end
|
|
392
|
-
indent
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
def stop
|
|
396
|
-
dedent
|
|
397
|
-
puts "}"
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
def returns_void?
|
|
401
|
-
type.nil? || type.void?
|
|
402
|
-
end
|
|
403
|
-
|
|
404
|
-
def declare_local(type, name, initialize=true)
|
|
405
|
-
unless @locals[name]
|
|
406
|
-
if initialize
|
|
407
|
-
print "#{type.to_source} #{name} = "
|
|
408
|
-
if block_given?
|
|
409
|
-
yield self
|
|
410
|
-
else
|
|
411
|
-
print init_value(type)
|
|
412
|
-
end
|
|
413
|
-
puts ';'
|
|
414
|
-
end
|
|
415
|
-
@locals[name] = type
|
|
416
|
-
end
|
|
417
|
-
name
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
def local?(name)
|
|
421
|
-
!!@locals[name]
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
def tmp(type, &block)
|
|
425
|
-
@temps += 1
|
|
426
|
-
declare_local(type, "temp$#{@temps}", &block)
|
|
427
|
-
end
|
|
428
|
-
|
|
429
|
-
def label
|
|
430
|
-
@temps += 1
|
|
431
|
-
"label#{@temps}"
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
def push_int(value)
|
|
435
|
-
print value
|
|
436
|
-
end
|
|
437
|
-
|
|
438
|
-
def ldc_float(value)
|
|
439
|
-
print "(float)#{value}"
|
|
440
|
-
end
|
|
441
|
-
|
|
442
|
-
def ldc_double(value)
|
|
443
|
-
print value
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
def ldc_long(value)
|
|
447
|
-
print "#{value}L"
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
def ldc_class(type)
|
|
451
|
-
print "#{type.to_source}.class"
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
def instanceof(type)
|
|
455
|
-
print " instanceof #{type.to_source}"
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
def method_missing(name, *args)
|
|
459
|
-
if name.to_s =~ /.const_(m)?(\d)/
|
|
460
|
-
print '-' if $1
|
|
461
|
-
print $2
|
|
462
|
-
else
|
|
463
|
-
super
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
end
|
|
467
|
-
end
|
|
468
|
-
end
|