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.
Files changed (171) hide show
  1. data/History.txt +372 -0
  2. data/README.txt +4 -5
  3. data/Rakefile +178 -55
  4. data/examples/appengine/Readme +3 -3
  5. data/examples/appengine/src/org/mirah/MirahApp.mirah +1 -1
  6. data/examples/appengine/src/org/mirah/list.dhtml +1 -1
  7. data/examples/bintrees.mirah +1 -1
  8. data/examples/edb.mirah +1 -1
  9. data/examples/fib.mirah +1 -1
  10. data/examples/interfaces.mirah +1 -1
  11. data/examples/macros/{string-each-char.mirah → string_each_char.mirah} +4 -5
  12. data/examples/maven/README.txt +1 -1
  13. data/examples/maven/src/main/mirah/hello_mirah.mirah +1 -1
  14. data/examples/plugins/appengine/Rakefile +1 -1
  15. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/MetaModel.mirah +1 -1
  16. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +1 -1
  17. data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +1 -1
  18. data/examples/rosettacode/100-doors.mirah +6 -6
  19. data/examples/rosettacode/README.txt +3 -3
  20. data/examples/rosettacode/boolean-values.mirah +1 -1
  21. data/examples/rosettacode/comments.mirah +1 -1
  22. data/examples/rosettacode/count-occurrences-of-a-substring.mirah +1 -1
  23. data/examples/rosettacode/factorial.mirah +1 -1
  24. data/examples/rosettacode/fibonacci.mirah +1 -1
  25. data/examples/rosettacode/fizz-buzz.mirah +2 -2
  26. data/examples/rosettacode/flatten-a-list.mirah +4 -4
  27. data/examples/rosettacode/guess-the-number.mirah +2 -2
  28. data/examples/rosettacode/hamming-numbers.mirah +4 -4
  29. data/examples/rosettacode/is-string-numeric.mirah +22 -22
  30. data/examples/rosettacode/palindrome.mirah +2 -2
  31. data/examples/rosettacode/random-numbers.mirah +1 -1
  32. data/examples/rosettacode/repeat-a-string.mirah +1 -1
  33. data/examples/rosettacode/reverse-a-string.mirah +1 -1
  34. data/examples/rosettacode/rot-13.mirah +5 -5
  35. data/examples/rosettacode/secure-temporary-file.mirah +2 -2
  36. data/examples/rosettacode/sleep.mirah +1 -1
  37. data/examples/rosettacode/string-length.mirah +5 -5
  38. data/examples/swing.mirah +1 -1
  39. data/examples/test.edb +1 -1
  40. data/javalib/mirah-bootstrap.jar +0 -0
  41. data/javalib/mirah-builtins.jar +0 -0
  42. data/javalib/mirah-parser.jar +0 -0
  43. data/javalib/mirah-util.jar +0 -0
  44. data/lib/duby.rb +1 -1
  45. data/lib/mirah.rb +50 -28
  46. data/lib/mirah/ast.rb +15 -605
  47. data/lib/mirah/ast/scope.rb +98 -69
  48. data/lib/mirah/commands.rb +1 -1
  49. data/lib/mirah/commands/base.rb +7 -7
  50. data/lib/mirah/commands/compile.rb +3 -3
  51. data/lib/mirah/commands/parse.rb +7 -5
  52. data/lib/mirah/commands/run.rb +12 -19
  53. data/lib/mirah/compiler.rb +15 -23
  54. data/lib/mirah/errors.rb +16 -1
  55. data/lib/mirah/generator.rb +79 -39
  56. data/lib/mirah/jvm/compiler.rb +1 -19
  57. data/lib/mirah/jvm/compiler/base.rb +233 -90
  58. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +675 -363
  59. data/lib/mirah/jvm/method_lookup.rb +134 -65
  60. data/lib/mirah/jvm/typer.rb +10 -5
  61. data/lib/mirah/jvm/types.rb +10 -2
  62. data/lib/mirah/jvm/types/array_type.rb +10 -12
  63. data/lib/mirah/{compiler/type.rb → jvm/types/ast_ext.rb} +12 -8
  64. data/lib/mirah/jvm/types/basic_types.rb +26 -33
  65. data/lib/mirah/jvm/types/bitescript_ext.rb +1 -1
  66. data/lib/mirah/jvm/types/block_type.rb +15 -0
  67. data/lib/mirah/jvm/types/boolean.rb +8 -4
  68. data/lib/mirah/jvm/types/dynamic_type.rb +12 -13
  69. data/lib/mirah/jvm/types/enumerable.rb +7 -7
  70. data/lib/mirah/jvm/types/extensions.rb +11 -6
  71. data/lib/mirah/jvm/types/factory.rb +624 -94
  72. data/lib/mirah/jvm/types/floats.rb +21 -15
  73. data/lib/mirah/jvm/types/generic_type.rb +72 -0
  74. data/lib/mirah/jvm/types/implicit_nil_type.rb +29 -0
  75. data/lib/mirah/jvm/types/integers.rb +26 -71
  76. data/lib/mirah/jvm/types/interface_definition.rb +3 -3
  77. data/lib/mirah/jvm/types/intrinsics.rb +203 -168
  78. data/lib/mirah/jvm/types/literals.rb +6 -6
  79. data/lib/mirah/jvm/types/meta_type.rb +13 -4
  80. data/lib/mirah/jvm/types/methods.rb +281 -93
  81. data/lib/mirah/jvm/types/null_type.rb +17 -5
  82. data/lib/mirah/jvm/types/number.rb +10 -7
  83. data/lib/mirah/jvm/types/primitive_type.rb +17 -6
  84. data/lib/mirah/jvm/types/source_mirror.rb +12 -7
  85. data/lib/mirah/jvm/types/type.rb +107 -23
  86. data/lib/mirah/jvm/types/type_definition.rb +25 -10
  87. data/lib/mirah/jvm/types/unreachable_type.rb +1 -1
  88. data/lib/mirah/jvm/types/void_type.rb +3 -3
  89. data/lib/mirah/parser.rb +154 -16
  90. data/lib/mirah/plugin/edb.rb +1 -1
  91. data/lib/mirah/transform.rb +1 -2
  92. data/lib/mirah/transform/ast_ext.rb +24 -43
  93. data/lib/mirah/transform/transformer.rb +29 -224
  94. data/lib/mirah/typer.rb +2 -16
  95. data/lib/mirah/util/argument_processor.rb +25 -10
  96. data/lib/mirah/util/class_loader.rb +1 -1
  97. data/lib/mirah/util/compilation_state.rb +16 -17
  98. data/lib/mirah/util/delegate.rb +2 -2
  99. data/lib/mirah/util/logging.rb +110 -0
  100. data/lib/mirah/util/process_errors.rb +69 -11
  101. data/lib/mirah/version.rb +1 -1
  102. data/test/core/commands_test.rb +6 -24
  103. data/test/core/env_test.rb +5 -5
  104. data/{lib/mirah/jvm/source_generator/typer.rb → test/core/generator_test.rb} +9 -9
  105. data/test/core/typer_test.rb +196 -158
  106. data/test/core/util/argument_processor_test.rb +10 -10
  107. data/test/core/util/class_loader_test.rb +6 -5
  108. data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
  109. data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
  110. data/test/fixtures/org/foo/LowerCaseInnerClass.java +7 -0
  111. data/test/jvm/annotations_test.rb +5 -5
  112. data/test/jvm/blocks_test.rb +140 -88
  113. data/test/jvm/bytecode_test_helper.rb +112 -94
  114. data/test/jvm/cast_test.rb +162 -0
  115. data/test/jvm/constructors_test.rb +18 -8
  116. data/test/jvm/enumerable_test.rb +77 -44
  117. data/test/jvm/example_test.rb +53 -0
  118. data/test/jvm/factory_test.rb +7 -1
  119. data/test/jvm/generics_test.rb +57 -0
  120. data/test/jvm/hash_test.rb +106 -0
  121. data/test/jvm/import_test.rb +81 -0
  122. data/test/jvm/interface_test.rb +73 -0
  123. data/test/jvm/java_typer_test.rb +92 -66
  124. data/{lib/mirah/typer/base.rb → test/jvm/jvm_commands_test.rb} +6 -10
  125. data/test/jvm/jvm_compiler_test.rb +170 -604
  126. data/test/jvm/list_extensions_test.rb +23 -0
  127. data/test/jvm/macros_test.rb +197 -32
  128. data/test/jvm/main_method_test.rb +4 -4
  129. data/test/jvm/numeric_extensions_test.rb +13 -0
  130. data/test/jvm/rescue_test.rb +73 -16
  131. data/test/jvm/varargs_test.rb +65 -0
  132. data/test/test_helper.rb +1 -2
  133. metadata +234 -251
  134. data/examples/SortClosure$__xform_tmp_1.class +0 -0
  135. data/examples/SortClosure$__xform_tmp_2.class +0 -0
  136. data/examples/SortClosure.class +0 -0
  137. data/examples/macros/StringEachChar$Extension1.class +0 -0
  138. data/lib/mirah/ast/call.rb +0 -345
  139. data/lib/mirah/ast/class.rb +0 -359
  140. data/lib/mirah/ast/flow.rb +0 -381
  141. data/lib/mirah/ast/intrinsics.rb +0 -563
  142. data/lib/mirah/ast/literal.rb +0 -178
  143. data/lib/mirah/ast/local.rb +0 -112
  144. data/lib/mirah/ast/method.rb +0 -408
  145. data/lib/mirah/ast/structure.rb +0 -387
  146. data/lib/mirah/ast/type.rb +0 -146
  147. data/lib/mirah/commands/base.rb~ +0 -57
  148. data/lib/mirah/compiler/call.rb +0 -45
  149. data/lib/mirah/compiler/class.rb +0 -81
  150. data/lib/mirah/compiler/flow.rb +0 -109
  151. data/lib/mirah/compiler/literal.rb +0 -130
  152. data/lib/mirah/compiler/local.rb +0 -59
  153. data/lib/mirah/compiler/method.rb +0 -44
  154. data/lib/mirah/compiler/structure.rb +0 -65
  155. data/lib/mirah/jvm/compiler/java_source.rb +0 -787
  156. data/lib/mirah/jvm/method_lookup.rb~ +0 -247
  157. data/lib/mirah/jvm/source_generator/builder.rb +0 -468
  158. data/lib/mirah/jvm/source_generator/loops.rb +0 -131
  159. data/lib/mirah/jvm/source_generator/precompile.rb +0 -210
  160. data/lib/mirah/plugin/gwt.rb +0 -189
  161. data/lib/mirah/plugin/java.rb +0 -70
  162. data/lib/mirah/transform/error.rb +0 -13
  163. data/lib/mirah/transform/helper.rb +0 -765
  164. data/lib/mirah/typer/simple.rb +0 -384
  165. data/lib/mirah/version.rb~ +0 -18
  166. data/test/core/ast_test.rb +0 -382
  167. data/test/core/compilation_test.rb +0 -130
  168. data/test/core/macros_test.rb +0 -61
  169. data/test/jvm/javac_test_helper.rb +0 -89
  170. data/test/jvm/jvm_compiler_test.rb~ +0 -2181
  171. 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