mirah 0.0.7-java → 0.0.8-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 (182) hide show
  1. data/History.txt +181 -0
  2. data/README.txt +6 -10
  3. data/Rakefile +86 -9
  4. data/bin/mirah +2 -0
  5. data/bin/mirahc +2 -0
  6. data/bin/mirahp +2 -0
  7. data/{bin/dubyp → examples/interfaces.mirah} +16 -9
  8. data/examples/macros/square.mirah +12 -0
  9. data/examples/macros/square_int.mirah +12 -0
  10. data/examples/macros/string-each-char.mirah +14 -0
  11. data/examples/maven/README.txt +2 -0
  12. data/examples/maven/pom.xml +23 -0
  13. data/examples/maven/src/main/mirah/hello_mirah.mirah +9 -0
  14. data/examples/rosettacode/100-doors.mirah +44 -0
  15. data/examples/rosettacode/99-bottles-of-beer.mirah +13 -0
  16. data/examples/rosettacode/README.txt +9 -0
  17. data/examples/rosettacode/boolean-values.mirah +29 -0
  18. data/examples/rosettacode/comments.mirah +2 -0
  19. data/examples/rosettacode/copy-a-string.mirah +10 -0
  20. data/examples/rosettacode/count-occurrences-of-a-substring.mirah +40 -0
  21. data/examples/rosettacode/create-a-file.mirah +6 -0
  22. data/examples/rosettacode/empty-string.mirah +9 -0
  23. data/examples/rosettacode/factorial.mirah +10 -0
  24. data/examples/rosettacode/fibonacci.mirah +21 -0
  25. data/examples/rosettacode/file-size.mirah +5 -0
  26. data/examples/rosettacode/fizz-buzz.mirah +21 -0
  27. data/examples/rosettacode/flatten-a-list.mirah +24 -0
  28. data/examples/rosettacode/guess-the-number.mirah +21 -0
  29. data/examples/rosettacode/is-string-numeric.mirah +127 -0
  30. data/examples/rosettacode/palindrome.mirah +14 -0
  31. data/examples/rosettacode/repeat-a-string.mirah +9 -0
  32. data/examples/rosettacode/reverse-a-string.mirah +6 -0
  33. data/examples/rosettacode/rot-13.mirah +20 -0
  34. data/examples/rosettacode/user-input.mirah +4 -0
  35. data/examples/sort_closure.mirah +1 -1
  36. data/javalib/dynalink-0.2.jar +0 -0
  37. data/javalib/mirah-bootstrap.jar +0 -0
  38. data/lib/mirah.rb +7 -16
  39. data/lib/mirah/ast.rb +22 -92
  40. data/lib/mirah/ast/call.rb +41 -9
  41. data/lib/mirah/ast/class.rb +34 -6
  42. data/lib/mirah/ast/flow.rb +17 -5
  43. data/lib/mirah/ast/intrinsics.rb +50 -8
  44. data/lib/mirah/ast/literal.rb +7 -0
  45. data/lib/mirah/ast/local.rb +9 -1
  46. data/lib/mirah/ast/method.rb +21 -8
  47. data/lib/mirah/ast/scope.rb +1 -1
  48. data/lib/mirah/ast/structure.rb +81 -15
  49. data/lib/mirah/ast/type.rb +4 -0
  50. data/{bin/dubyc → lib/mirah/commands.rb} +4 -11
  51. data/lib/mirah/commands/base.rb +54 -0
  52. data/lib/mirah/commands/compile.rb +39 -0
  53. data/{examples/wiki/Rakefile → lib/mirah/commands/parse.rb} +18 -17
  54. data/lib/mirah/commands/run.rb +73 -0
  55. data/lib/mirah/compiler.rb +37 -417
  56. data/lib/mirah/compiler/call.rb +45 -0
  57. data/lib/mirah/compiler/class.rb +81 -0
  58. data/lib/mirah/compiler/flow.rb +109 -0
  59. data/lib/mirah/compiler/literal.rb +130 -0
  60. data/lib/mirah/compiler/local.rb +59 -0
  61. data/lib/mirah/compiler/method.rb +44 -0
  62. data/lib/mirah/compiler/structure.rb +65 -0
  63. data/lib/mirah/compiler/type.rb +27 -0
  64. data/lib/mirah/env.rb +4 -6
  65. data/lib/mirah/generator.rb +61 -0
  66. data/lib/mirah/jvm/compiler.rb +8 -867
  67. data/lib/mirah/jvm/compiler/base.rb +270 -0
  68. data/lib/mirah/jvm/compiler/java_source.rb +779 -0
  69. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +851 -0
  70. data/lib/mirah/jvm/method_lookup.rb +21 -2
  71. data/lib/mirah/jvm/source_generator/builder.rb +10 -13
  72. data/lib/mirah/jvm/source_generator/loops.rb +99 -93
  73. data/lib/mirah/jvm/source_generator/precompile.rb +3 -2
  74. data/lib/mirah/jvm/typer.rb +3 -3
  75. data/lib/mirah/jvm/types.rb +10 -426
  76. data/lib/mirah/jvm/types/array_type.rb +62 -0
  77. data/lib/mirah/jvm/types/basic_types.rb +1 -0
  78. data/lib/mirah/jvm/types/dynamic_type.rb +46 -0
  79. data/lib/mirah/jvm/types/factory.rb +23 -5
  80. data/lib/mirah/jvm/types/interface_definition.rb +20 -0
  81. data/lib/mirah/jvm/types/intrinsics.rb +15 -3
  82. data/lib/mirah/jvm/types/meta_type.rb +45 -0
  83. data/lib/mirah/jvm/types/methods.rb +12 -5
  84. data/lib/mirah/jvm/types/null_type.rb +27 -0
  85. data/lib/mirah/jvm/types/primitive_type.rb +38 -0
  86. data/lib/mirah/jvm/types/source_mirror.rb +266 -0
  87. data/lib/mirah/jvm/types/type.rb +173 -0
  88. data/lib/mirah/jvm/types/type_definition.rb +55 -0
  89. data/lib/mirah/jvm/types/unreachable_type.rb +27 -0
  90. data/lib/mirah/jvm/types/void_type.rb +19 -0
  91. data/lib/mirah/parser.rb +90 -0
  92. data/lib/mirah/plugin/gwt.rb +5 -5
  93. data/lib/mirah/plugin/java.rb +1 -1
  94. data/lib/mirah/transform.rb +4 -321
  95. data/lib/mirah/transform/ast_ext.rb +63 -0
  96. data/lib/mirah/transform/error.rb +13 -0
  97. data/lib/mirah/transform/helper.rb +761 -0
  98. data/lib/mirah/transform/transformer.rb +255 -0
  99. data/lib/mirah/typer.rb +2 -383
  100. data/{bin/duby → lib/mirah/typer/base.rb} +12 -10
  101. data/lib/mirah/typer/simple.rb +377 -0
  102. data/lib/mirah/util/argument_processor.rb +114 -0
  103. data/lib/mirah/util/class_loader.rb +37 -0
  104. data/lib/mirah/util/compilation_state.rb +51 -0
  105. data/lib/mirah/util/process_errors.rb +33 -0
  106. data/lib/mirah/version.rb +1 -1
  107. data/lib/mirah_task.rb +3 -2
  108. data/test/{test_ast.rb → core/test_ast.rb} +6 -0
  109. data/test/{test_compilation.rb → core/test_compilation.rb} +0 -0
  110. data/test/{test_env.rb → core/test_env.rb} +24 -25
  111. data/test/{test_macros.rb → core/test_macros.rb} +2 -4
  112. data/test/{test_typer.rb → core/test_typer.rb} +0 -3
  113. data/test/jvm/bytecode_test_helper.rb +181 -0
  114. data/test/{test_javac_compiler.rb → jvm/javac_test_helper.rb} +38 -22
  115. data/test/jvm/test_enumerable.rb +304 -0
  116. data/test/{test_java_typer.rb → jvm/test_java_typer.rb} +2 -4
  117. data/test/{test_jvm_compiler.rb → jvm/test_jvm_compiler.rb} +146 -443
  118. data/test/jvm/test_macros.rb +147 -0
  119. data/test/jvm/test_main_method.rb +15 -0
  120. data/test/{test_gwt.rb → plugins/test_gwt.rb} +0 -2
  121. metadata +103 -91
  122. data/bin/jrubyp +0 -52
  123. data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +0 -339
  124. data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +0 -42
  125. data/examples/wiki/src/org/mirah/wiki/error.eduby.html +0 -2
  126. data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +0 -69
  127. data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +0 -7
  128. data/examples/wiki/src/org/mirah/wiki/view.eduby.html +0 -15
  129. data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
  130. data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
  131. data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
  132. data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
  133. data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
  134. data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
  135. data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
  136. data/examples/wiki/war/app.yaml +0 -21
  137. data/examples/wiki/war/public/favicon.ico +0 -0
  138. data/examples/wiki/war/public/images/appengine_duby.png +0 -0
  139. data/examples/wiki/war/public/images/back.gif +0 -0
  140. data/examples/wiki/war/public/images/dir.gif +0 -0
  141. data/examples/wiki/war/public/images/file.gif +0 -0
  142. data/examples/wiki/war/public/javascripts/prettify.js +0 -61
  143. data/examples/wiki/war/public/robots.txt +0 -0
  144. data/examples/wiki/war/public/stylesheets/main.css +0 -156
  145. data/examples/wiki/war/public/stylesheets/prettify.css +0 -1
  146. data/examples/wiki/war/public/stylesheets/sh_style.css +0 -66
  147. data/examples/wiki/war/public/stylesheets/source.css +0 -21
  148. data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
  149. data/examples/wiki/war/public/wmd/images/bg.png +0 -0
  150. data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
  151. data/examples/wiki/war/public/wmd/images/bold.png +0 -0
  152. data/examples/wiki/war/public/wmd/images/code.png +0 -0
  153. data/examples/wiki/war/public/wmd/images/h1.png +0 -0
  154. data/examples/wiki/war/public/wmd/images/hr.png +0 -0
  155. data/examples/wiki/war/public/wmd/images/img.png +0 -0
  156. data/examples/wiki/war/public/wmd/images/italic.png +0 -0
  157. data/examples/wiki/war/public/wmd/images/link.png +0 -0
  158. data/examples/wiki/war/public/wmd/images/ol.png +0 -0
  159. data/examples/wiki/war/public/wmd/images/redo.png +0 -0
  160. data/examples/wiki/war/public/wmd/images/separator.png +0 -0
  161. data/examples/wiki/war/public/wmd/images/ul.png +0 -0
  162. data/examples/wiki/war/public/wmd/images/undo.png +0 -0
  163. data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
  164. data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
  165. data/examples/wiki/war/public/wmd/showdown.js +0 -421
  166. data/examples/wiki/war/public/wmd/wmd-base.js +0 -1799
  167. data/examples/wiki/war/public/wmd/wmd-plus.js +0 -311
  168. data/examples/wiki/war/public/wmd/wmd.js +0 -73
  169. data/examples/wiki/war/src/org/mirah/wiki/MirahWiki.duby +0 -339
  170. data/examples/wiki/war/src/org/mirah/wiki/edit.eduby.html +0 -42
  171. data/examples/wiki/war/src/org/mirah/wiki/error.eduby.html +0 -2
  172. data/examples/wiki/war/src/org/mirah/wiki/layout.eduby.html +0 -69
  173. data/examples/wiki/war/src/org/mirah/wiki/parser.eduby.html +0 -7
  174. data/examples/wiki/war/src/org/mirah/wiki/view.eduby.html +0 -15
  175. data/javalib/dynalink-0.1.jar +0 -0
  176. data/javalib/jsr292-mock.jar +0 -0
  177. data/lib/mirah/class_loader.rb +0 -35
  178. data/lib/mirah/compilation_state.rb +0 -28
  179. data/lib/mirah/impl.rb +0 -273
  180. data/lib/mirah/jvm/base.rb +0 -267
  181. data/lib/mirah/jvm/source_compiler.rb +0 -760
  182. data/lib/mirah/transform2.rb +0 -752
@@ -0,0 +1,270 @@
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 Compiler
19
+ class Base
20
+ attr_accessor :filename, :method, :static, :class
21
+
22
+ class CompilationError < Mirah::NodeError
23
+ end
24
+
25
+ def initialize
26
+ @jump_scope = []
27
+ @bindings = Hash.new {|h, type| h[type] = type.define(@file)}
28
+ @captured_locals = Hash.new {|h, binding| h[binding] = {}}
29
+ @self_scope = nil
30
+ end
31
+
32
+ def error(message, node)
33
+ raise CompilationError.new(message, node)
34
+ end
35
+
36
+ def compile(ast, expression = false)
37
+ begin
38
+ ast.compile(self, expression)
39
+ rescue => ex
40
+ raise Mirah::InternalCompilerError.wrap(ex, ast)
41
+ end
42
+ log "Compilation successful!"
43
+ end
44
+
45
+ def log(message); Mirah::JVM::Compiler::JVMBytecode.log(message); end
46
+
47
+ def toplevel_class
48
+ @class = @type.define(@file)
49
+ end
50
+
51
+ def generate
52
+ log "Generating #{output_type}..."
53
+ @file.generate do |filename, builder|
54
+ log " #{builder.class_name}"
55
+ if block_given?
56
+ yield filename, builder
57
+ else
58
+ File.open(filename, 'wb') {|f| f.write(builder.generate)}
59
+ end
60
+ end
61
+ log "...done!"
62
+ end
63
+
64
+ def define_main(script)
65
+ @static = true
66
+ @filename = File.basename(script.filename)
67
+ classname = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(@filename)
68
+ @type = AST.type(script, classname)
69
+ @file = file_builder(@filename)
70
+
71
+ # Define a main method unless all of the script's children are 'top level'
72
+ # nodes (e.g. Import, ClassDefinition, InterfaceDeclaration).
73
+ unless script.body.children.all? { |c| c && c.top_level? }
74
+ @class = @type.define(@file)
75
+ with :method => @class.main do
76
+ log "Starting main method"
77
+
78
+ @method.start
79
+ @current_scope = script.static_scope
80
+ declare_locals(@current_scope)
81
+ begin_main
82
+
83
+ prepare_binding(script) do
84
+ script.body.compile(self, false)
85
+ end
86
+
87
+ finish_main
88
+ @method.stop
89
+ end
90
+ @class.stop
91
+
92
+ log "Main method complete!"
93
+ else
94
+ script.body.compile(self, false)
95
+ end
96
+ end
97
+
98
+ def begin_main; end
99
+ def finish_main; end
100
+
101
+ # arg_types must be an Array
102
+ def create_method_builder(name, node, static, exceptions, return_type, arg_types)
103
+ @class.build_method(name.to_s, node.visibility, static,
104
+ exceptions, return_type, *arg_types)
105
+ end
106
+
107
+ def base_define_method(node, args_are_types)
108
+ name, signature, args = node.name, node.signature, node.arguments.args
109
+ if name == "initialize" && node.static?
110
+ name = "<clinit>"
111
+ end
112
+ if args_are_types
113
+ arg_types = args.map { |arg| arg.inferred_type } if args
114
+ else
115
+ arg_types = args
116
+ end
117
+ arg_types ||= []
118
+ return_type = signature[:return]
119
+ exceptions = signature[:throws]
120
+
121
+ with :static => @static || node.static?, :current_scope => node.static_scope do
122
+ method = create_method_builder(name, node, @static, exceptions,
123
+ return_type, arg_types)
124
+ annotate(method, node.annotations)
125
+ yield method, arg_types
126
+ end
127
+
128
+ arg_types_for_opt = []
129
+ args_for_opt = []
130
+ if args
131
+ args.each do |arg|
132
+ if AST::OptionalArgument === arg
133
+ new_args = if args_are_types
134
+ arg_types_for_opt
135
+ else
136
+ args_for_opt
137
+ end
138
+ method = create_method_builder(name, node, @static, exceptions,
139
+ return_type, new_args)
140
+ with :method => method do
141
+ log "Starting new method #{name}(#{arg_types_for_opt})"
142
+
143
+ annotate(method, node.annotations)
144
+ @method.start
145
+
146
+ define_optarg_chain(name, arg,
147
+ return_type,
148
+ args_for_opt,
149
+ arg_types_for_opt)
150
+
151
+ @method.stop
152
+ end
153
+ end
154
+ arg_types_for_opt << arg.inferred_type
155
+ args_for_opt << arg
156
+ end
157
+ end
158
+ end
159
+
160
+ def constructor(node, args_are_types)
161
+ args = node.arguments.args || []
162
+ arg_types = if args_are_types
163
+ args.map { |arg| arg.inferred_type }
164
+ else
165
+ args
166
+ end
167
+ exceptions = node.signature[:throws]
168
+ method = @class.build_constructor(node.visibility, exceptions, *arg_types)
169
+ annotate(method, node.annotations)
170
+ with :current_scope => node.static_scope do
171
+ yield(method, args)
172
+ end
173
+ end
174
+
175
+ def define_class(class_def, expression)
176
+ with(:type => class_def.inferred_type,
177
+ :class => class_def.inferred_type.define(@file),
178
+ :static => false) do
179
+ annotate(@class, class_def.annotations)
180
+ class_def.body.compile(self, false) if class_def.body
181
+ @class.stop
182
+ end
183
+ end
184
+
185
+ def declare_argument(name, type)
186
+ # declare local vars for arguments here
187
+ end
188
+
189
+ def body(body, expression)
190
+ saved_self = @self_scope
191
+ if body.kind_of?(Mirah::AST::ScopedBody)
192
+ scope = body.static_scope
193
+ declare_locals(scope)
194
+ if scope != @self_scope
195
+ if scope.self_node && scope.self_node != :self
196
+ # FIXME This is a horrible hack!
197
+ # Instead we should eliminate unused self's.
198
+ unless scope.self_type.name == 'mirah.impl.Builtin'
199
+ local_assign(
200
+ scope, 'self', scope.self_type, false, scope.self_node)
201
+ end
202
+ end
203
+ @self_scope = scope
204
+ end
205
+ end
206
+ # all except the last element in a body of code is treated as a statement
207
+ i, last = 0, body.children.size - 1
208
+ while i < last
209
+ body.children[i].compile(self, false)
210
+ i += 1
211
+ end
212
+ yield body.children[last] if last >= 0
213
+ @self_scope = saved_self
214
+ end
215
+
216
+ def scoped_body(scope, expression)
217
+ body(scope, expression)
218
+ end
219
+
220
+ def scoped_local_name(name, scope=nil)
221
+ if scope.nil? || scope == @current_scope
222
+ name
223
+ else
224
+ "#{name}$#{scope.object_id}"
225
+ end
226
+ end
227
+
228
+ def import(short, long)
229
+ end
230
+
231
+ def fixnum(type, value)
232
+ type.literal(method, value)
233
+ end
234
+ alias float fixnum
235
+
236
+ def compile_self
237
+ if @self_scope && @self_scope.self_node && @self_scope.self_node != :self
238
+ local(@self_scope, 'self', @self_scope.self_type)
239
+ else
240
+ real_self
241
+ end
242
+ end
243
+
244
+ def get_binding(type)
245
+ @bindings[type]
246
+ end
247
+
248
+ def declared_captures(binding=nil)
249
+ @captured_locals[binding || @binding]
250
+ end
251
+
252
+ def with(vars)
253
+ orig_values = {}
254
+ begin
255
+ vars.each do |name, new_value|
256
+ name = "@#{name}"
257
+ orig_values[name] = instance_variable_get name
258
+ instance_variable_set name, new_value
259
+ end
260
+ yield
261
+ ensure
262
+ orig_values.each do |name, value|
263
+ instance_variable_set name, value
264
+ end
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
270
+ end
@@ -0,0 +1,779 @@
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'
17
+ require 'mirah/ast'
18
+ require 'mirah/jvm/types'
19
+ require 'mirah/jvm/compiler'
20
+ require 'mirah/jvm/source_generator/builder'
21
+ require 'mirah/jvm/source_generator/precompile'
22
+ require 'mirah/jvm/source_generator/loops'
23
+
24
+ class String
25
+ def compile(compiler, expression)
26
+ compiler.method.print self if expression
27
+ end
28
+ end
29
+
30
+ module Mirah
31
+ module JVM
32
+ module Compiler
33
+ class JavaSource < Base
34
+ JVMTypes = Mirah::JVM::Types
35
+ attr_accessor :lvalue
36
+
37
+ Operators = [
38
+ '+', '-', '+@', '-@', '/', '%', '*', '<',
39
+ '<=', '==', '!=', '>=', '>',
40
+ '<<', '>>', '>>>', '|', '&', '^', '~'
41
+ ]
42
+ ArrayOps = [
43
+ '[]', '[]=', 'length'
44
+ ]
45
+
46
+ ImplicitReturn = Struct.new(:value)
47
+
48
+ def initialize
49
+ super
50
+ end
51
+
52
+ def file_builder(filename)
53
+ Mirah::JavaSource::Builder.new(filename, self)
54
+ end
55
+
56
+ def output_type
57
+ "source files"
58
+ end
59
+
60
+ def define_class(class_def, expression)
61
+ with(:type => class_def.inferred_type,
62
+ :class => class_def.inferred_type.define(@file),
63
+ :static => false) do
64
+ annotate(@class, class_def.annotations)
65
+ class_def.body.compile(self, false) if class_def.body
66
+ @class.stop unless @method && @method.name == 'main' && @class == @method.klass
67
+ end
68
+ end
69
+
70
+ def define_method(node)
71
+ base_define_method(node, false) do |method, _|
72
+ with :method => method do
73
+ log "Starting new method #{node.name}"
74
+ @method.start
75
+
76
+ prepare_binding(node) do
77
+ declare_locals(node.static_scope)
78
+ unless @method.type.nil? || @method.type.void?
79
+ self.return(ImplicitReturn.new(node.body))
80
+ else
81
+ node.body.compile(self, false) if node.body
82
+ end
83
+ end
84
+
85
+ log "Method #{node.name} complete!"
86
+ @method.stop
87
+ end
88
+ end
89
+ end
90
+
91
+ def annotate(node, annotations)
92
+ node.annotate(annotations)
93
+ end
94
+
95
+ def define_optarg_chain(name, arg, return_type,
96
+ args_for_opt, arg_types_for_opt)
97
+ # declare all args so they get their values
98
+ @method.print "return " unless @method.type.nil? || @method.type.void?
99
+ @method.print "this." unless @static
100
+ @method.print "#{name}("
101
+ @method.print args_for_opt.map(&:name).join(', ')
102
+ @method.print ', 'if args_for_opt.size > 0
103
+ arg.value.compile(self, true)
104
+
105
+ # invoke the next one in the chain
106
+ @method.print ");\n"
107
+ end
108
+
109
+ def constructor(node)
110
+ super(node, false) do |method, _|
111
+ with :method => method do
112
+ @method.start
113
+ if node.delegate_args
114
+ delegate = if node.calls_super
115
+ "super"
116
+ else
117
+ "this"
118
+ end
119
+ method.print "#{delegate}("
120
+ node.delegate_args.each_with_index do |arg, index|
121
+ method.print ', ' unless index == 0
122
+ raise "Invalid constructor argument #{arg}" unless arg.expr?(self)
123
+ arg.compile(self, true)
124
+ end
125
+ method.puts ");"
126
+ end
127
+
128
+ prepare_binding(node) do
129
+ declare_locals(node.static_scope)
130
+ node.body.compile(self, false) if node.body
131
+ end
132
+ method.stop
133
+ end
134
+ end
135
+ end
136
+
137
+ def prepare_binding(scope)
138
+ if scope.has_binding?
139
+ type = scope.binding_type
140
+ @binding = @bindings[type]
141
+ @method.puts "#{type.to_source} $binding = new #{type.to_source}();"
142
+ if scope.respond_to? :arguments
143
+ scope.arguments.args.each do |param|
144
+ if scope.static_scope.captured?(param.name)
145
+ captured_local_declare(scope, param.name, param.inferred_type)
146
+ @method.puts "$binding.#{param.name} = #{param.name};"
147
+ end
148
+ end
149
+ end
150
+ end
151
+ begin
152
+ yield
153
+ ensure
154
+ if scope.has_binding?
155
+ @binding.stop
156
+ @binding = nil
157
+ end
158
+ end
159
+ end
160
+
161
+ def define_closure(class_def, expression)
162
+ compiler = ClosureCompiler.new(@file, @type, self)
163
+ compiler.define_class(class_def, expression)
164
+ end
165
+
166
+ def return(node)
167
+ if @method.type.nil? || @method.type.void?
168
+ @method.puts 'return;'
169
+ return
170
+ end
171
+ if node.value.expr?(self)
172
+ @method.print 'return '
173
+ node.value.compile(self, true)
174
+ @method.puts ';'
175
+ else
176
+ store_value('return ', node.value)
177
+ end
178
+ end
179
+
180
+ def _raise(node)
181
+ if node.expr?(self)
182
+ @method.print 'throw '
183
+ node.compile(self, true)
184
+ @method.puts ';'
185
+ else
186
+ store_value('throw ', node)
187
+ end
188
+ end
189
+
190
+ def rescue(node, expression)
191
+ @method.block 'try' do
192
+ if node.else_node.nil?
193
+ maybe_store(node.body, expression) if node.body
194
+ else
195
+ node.body.compile(self, false) if node.body
196
+ end
197
+ end
198
+ node.clauses.each do |clause|
199
+ clause.types.each do |type|
200
+ name = scoped_local_name(clause.name || 'tmp$ex', clause.static_scope)
201
+ @method.declare_local(type, name, false)
202
+ @method.block "catch (#{type.to_source} #{name})" do
203
+ declare_locals(clause.static_scope)
204
+ maybe_store(clause.body, expression)
205
+ end
206
+ end
207
+ end
208
+ if node.else_node
209
+ maybe_store(node.else_node, expression)
210
+ end
211
+ end
212
+
213
+ def ensure(node, expression)
214
+ @method.block 'try' do
215
+ maybe_store(node.body, expression)
216
+ end
217
+ @method.block 'finally' do
218
+ node.clause.compile(self, false)
219
+ end
220
+ end
221
+
222
+ def line(num)
223
+ end
224
+
225
+ def declare_local(name, type)
226
+ @method.declare_local(type, name)
227
+ end
228
+
229
+ def declare_field(name, type, annotations, static_field)
230
+ @class.declare_field(name, type, @static || static_field, 'private', annotations)
231
+ end
232
+
233
+ def local(scope, name, type)
234
+ name = scoped_local_name(name, scope)
235
+ @method.print name
236
+ end
237
+
238
+ def field(name, type, annotations, static_field)
239
+ name = name[1..-1] if name =~ /^@/
240
+ declare_field(name, type, annotations, static_field)
241
+ @method.print "#{this}.#{name}"
242
+ end
243
+
244
+ def this(method=nil)
245
+ if method && method.static?
246
+ method.declaring_class.name
247
+ elsif @self_scope && @self_scope.self_node && @self_scope.self_node != :self
248
+ scoped_local_name('self', @self_scope)
249
+ else
250
+ @static ? @class.class_name : 'this'
251
+ end
252
+ end
253
+
254
+ def declare_locals(scope)
255
+ scope.locals.each do |name|
256
+ full_name = scoped_local_name(name, scope)
257
+ unless scope.captured?(name) || method.local?(full_name)
258
+ declare_local(full_name, scope.local_type(name))
259
+ end
260
+ end
261
+ end
262
+
263
+ def local_assign(scope, name, type, expression, value)
264
+ simple = value.expr?(self)
265
+ value = value.precompile(self)
266
+ name = scoped_local_name(name, scope)
267
+ if method.local?(name)
268
+ if expression
269
+ if simple
270
+ @method.print '('
271
+ else
272
+ @method.print @lvalue
273
+ end
274
+ end
275
+ @method.print "#{name} = "
276
+ value.compile(self, true)
277
+ if simple && expression
278
+ @method.print ')'
279
+ else
280
+ @method.puts ';'
281
+ end
282
+ else
283
+ @method.declare_local(type, name) do
284
+ value.compile(self, true)
285
+ end
286
+ if expression
287
+ @method.puts "#{@lvalue}#{name};"
288
+ end
289
+ end
290
+ end
291
+
292
+ def field_declare(name, type, annotations)
293
+ name = name[1..-1] if name =~ /^@/
294
+ declare_field(name, type, annotations)
295
+ end
296
+
297
+ def local_declare(scope, name, type)
298
+ name = scoped_local_name(name, scope)
299
+ declare_local(name, type)
300
+ end
301
+
302
+ def field_assign(name, type, expression, value, annotations, static_field)
303
+ name = name[1..-1] if name =~ /^@/
304
+ declare_field(name, type, annotations, static_field)
305
+ lvalue = "#{@lvalue if expression}#{this}.#{name} = "
306
+ store_value(lvalue, value)
307
+ end
308
+
309
+ def captured_local_declare(scope, name, type)
310
+ unless declared_captures[name]
311
+ declared_captures[name] = type
312
+ @binding.declare_field(name, type, false, '')
313
+ end
314
+ end
315
+
316
+ def captured_local(scope, name, type)
317
+ captured_local_declare(scope, name, type)
318
+ @method.print "$binding.#{name}"
319
+ end
320
+
321
+ def captured_local_assign(node, expression)
322
+ scope, name, type = node.containing_scope, node.name, node.inferred_type
323
+ captured_local_declare(scope, name, type)
324
+ lvalue = "#{@lvalue if expression}$binding.#{name} = "
325
+ store_value(lvalue, node.value)
326
+ end
327
+
328
+ def store_value(lvalue, value)
329
+ if value.is_a? String
330
+ @method.puts "#{lvalue}#{value};"
331
+ elsif value.expr?(self)
332
+ @method.print lvalue
333
+ value.compile(self, true)
334
+ @method.puts ';'
335
+ else
336
+ with :lvalue => lvalue do
337
+ value.compile(self, true)
338
+ end
339
+ end
340
+ end
341
+
342
+ def assign(name, value)
343
+ store_value("#{name} = ", value)
344
+ name
345
+ end
346
+
347
+ def maybe_store(value, expression)
348
+ if expression
349
+ store_value(@lvalue, value)
350
+ else
351
+ value.compile(self, false)
352
+ end
353
+ end
354
+
355
+ def body(body, expression)
356
+ super(body, expression) do |last|
357
+ maybe_store(last, expression)
358
+ end
359
+ end
360
+
361
+ def scoped_body(scope, expression)
362
+ @method.block do
363
+ super
364
+ end
365
+ end
366
+
367
+ def branch_expression(node)
368
+ node.condition.compile(self, true)
369
+ @method.print ' ? ('
370
+ if node.body
371
+ node.body.compile(self, true)
372
+ else
373
+ @method.print @method.init_value(node.inferred_type)
374
+ end
375
+ @method.print ') : ('
376
+ if node.else
377
+ node.else.compile(self, true)
378
+ else
379
+ @method.print @method.init_value(node.inferred_type)
380
+ end
381
+ @method.print ')'
382
+ end
383
+
384
+ def branch(node, expression)
385
+ if expression && node.expr?(self)
386
+ return branch_expression(node)
387
+ end
388
+ predicate = node.condition.predicate.precompile(self)
389
+ @method.print 'if ('
390
+ predicate.compile(self, true)
391
+ @method.block ")" do
392
+ if node.body
393
+ maybe_store(node.body, expression)
394
+ elsif expression
395
+ store_value(@lvalue, @method.init_value(node.inferred_type))
396
+ end
397
+ end
398
+ if node.else || expression
399
+ @method.block 'else' do
400
+ if node.else
401
+ maybe_store(node.else, expression)
402
+ else
403
+ store_value(@lvalue, @method.init_value(node.inferred_type))
404
+ end
405
+ end
406
+ end
407
+ end
408
+
409
+ def loop(loop, expression)
410
+ if loop.redo? || loop.post || !loop.condition.predicate.expr?(self)
411
+ loop = ComplexWhileLoop.new(loop, self)
412
+ else
413
+ loop = SimpleWhileLoop.new(loop, self)
414
+ end
415
+ with(:loop => loop) do
416
+ loop.compile(expression)
417
+ end
418
+ end
419
+
420
+ def expr?(target, params)
421
+ !([target] + params).any? {|x| x.kind_of? Mirah::AST::TempValue}
422
+ end
423
+
424
+ def operator(target, op, params, expression)
425
+ simple = expr?(target, params)
426
+ if expression && !simple
427
+ @method.print @lvalue
428
+ end
429
+ if params.size == 0
430
+ # unary operator
431
+ op = op[0,1]
432
+ @method.print op
433
+ target.compile(self, true)
434
+ else
435
+ @method.print '('
436
+ other = params[0]
437
+ target.compile(self, true)
438
+ @method.print " #{op} "
439
+ other.compile(self, true)
440
+ @method.print ')'
441
+ end
442
+ unless expression && simple
443
+ @method.puts ';'
444
+ end
445
+ end
446
+
447
+ def precompile_nodes(nodes)
448
+ if nodes.all? {|n| n.expr?(self)}
449
+ nodes
450
+ else
451
+ nodes.map do |node|
452
+ tempval = node.precompile(self)
453
+ if node == tempval && !node.kind_of?(Mirah::AST::Literal)
454
+ tempval = node.temp(self)
455
+ end
456
+ tempval
457
+ end
458
+ end
459
+ end
460
+
461
+ def compile_args(call)
462
+ precompile_nodes(call.parameters)
463
+ end
464
+
465
+ def self_type
466
+ type = AST.type(nil, @class.name.tr('/', '.'))
467
+ type = type.meta if @static
468
+ type
469
+ end
470
+
471
+ def super_call(call, expression)
472
+ super_method_call(this, call, compile_args(call), expression)
473
+ end
474
+
475
+ def cast(call, expression)
476
+ args = compile_args(call)
477
+ simple = call.expr?(self)
478
+ @method.print @lvalue if expression && !simple
479
+ @method.print "((#{call.inferred_type.to_source})("
480
+ args.each{|arg| arg.compile(self, true)}
481
+ @method.print "))"
482
+ @method.puts ';' unless simple && expression
483
+ end
484
+
485
+ def self_call(call, expression)
486
+ if call.cast?
487
+ cast(call, expression)
488
+ else
489
+ type = call.scope.static_scope.self_type
490
+ type = type.meta if (@static && type == @type)
491
+ params = call.parameters.map do |param|
492
+ param.inferred_type
493
+ end
494
+ method = type.get_method(call.name, params)
495
+ method_call(this(method), call, compile_args(call), expression)
496
+ end
497
+ end
498
+
499
+ def call(call, expression)
500
+ return cast(call, expression) if call.cast?
501
+ if Mirah::AST::Constant === call.target || Mirah::AST::Colon2 === call.target
502
+ target = call.target.inferred_type.to_source
503
+ else
504
+ target = call.precompile_target(self)
505
+ end
506
+ params = compile_args(call)
507
+
508
+ if Operators.include? call.name
509
+ operator(target, call.name, params, expression)
510
+ elsif call.target.inferred_type.array? && ArrayOps.include?(call.name)
511
+ array_op(target, call.name, params, expression)
512
+ elsif call.name == 'nil?'
513
+ operator(target, '==', ['null'], expression)
514
+ else
515
+ method_call(target, call, params, expression)
516
+ end
517
+ end
518
+
519
+ def array_op(target, name, args, expression)
520
+ simple = expr?(target, args)
521
+ index, value = args
522
+ if expression && !simple
523
+ @method.print @lvalue
524
+ end
525
+ target.compile(self, true)
526
+ if name == 'length'
527
+ @method.print '.length'
528
+ else
529
+ @method.print '['
530
+ index.compile(self, true)
531
+ @method.print ']'
532
+ if name == '[]='
533
+ @method.print " = "
534
+ value.compile(self, true)
535
+ end
536
+ end
537
+ unless simple && expression
538
+ @method.puts ';'
539
+ end
540
+ end
541
+
542
+ def break(node)
543
+ error("break outside of loop", node) unless @loop
544
+ @loop.break
545
+ end
546
+
547
+ def next(node)
548
+ error("next outside of loop", node) unless @loop
549
+ @loop.next
550
+ end
551
+
552
+ def redo(node)
553
+ error("redo outside of loop", node) unless @loop
554
+ @loop.redo
555
+ end
556
+
557
+ # TODO: merge cleanly with method_call logic
558
+ def super_method_call(target, call, params, expression)
559
+ simple = call.expr?(self)
560
+ method = call.method(self)
561
+ unless simple || method.return_type.void?
562
+ @method.print @lvalue if expression
563
+ end
564
+ if method.constructor?
565
+ @method.print "super("
566
+ else
567
+ @method.print "super.#{method.name}("
568
+ end
569
+ params.each_with_index do |param, index|
570
+ @method.print ', ' unless index == 0
571
+ param.compile(self, true)
572
+ end
573
+ if simple && expression
574
+ @method.print ')'
575
+ else
576
+ @method.puts ');'
577
+ end
578
+ if method.return_type.void? && expression
579
+ @method.print @lvalue
580
+ if method.static?
581
+ @method.puts 'null;'
582
+ else
583
+ target.compile(self, true)
584
+ @method.puts ';'
585
+ end
586
+ end
587
+
588
+ end
589
+
590
+ def method_call(target, call, params, expression)
591
+ simple = call.expr?(self)
592
+ method = call.method(self)
593
+ unless simple || method.return_type.void?
594
+ @method.print @lvalue if expression
595
+ end
596
+
597
+ # preamble
598
+ if method.constructor?
599
+ @method.print "new "
600
+ target.compile(self, true)
601
+ @method.print '('
602
+ elsif method.field?
603
+ target.compile(self, true)
604
+ @method.print ".#{method.name}"
605
+ if method.argument_types.size == 1
606
+ @method.print " = ("
607
+ end
608
+ elsif Mirah::JVM::Types::Intrinsic === method
609
+ method.call(self, call, expression)
610
+ return
611
+ else
612
+ target.compile(self, true)
613
+ @method.print ".#{method.name}("
614
+ end
615
+
616
+ # args
617
+ params.each_with_index do |param, index|
618
+ @method.print ', ' unless index == 0
619
+ param.compile(self, true)
620
+ end
621
+
622
+ # postamble
623
+ if !method.field? || (method.field? && method.argument_types.size == 1)
624
+ if simple && expression
625
+ @method.print ')'
626
+ else
627
+ @method.puts ');'
628
+ end
629
+ end
630
+
631
+ # cleanup
632
+ if method.return_type.void? && expression
633
+ @method.print @lvalue
634
+ if method.static?
635
+ @method.puts 'null;'
636
+ else
637
+ target.compile(self, true)
638
+ @method.puts ';'
639
+ end
640
+ end
641
+ end
642
+
643
+ def temp(expression, value=nil)
644
+ value ||= expression
645
+ type = value.inferred_type
646
+ if value.expr?(self)
647
+ @method.tmp(type) do
648
+ value.compile(self, true)
649
+ end
650
+ else
651
+ assign(@method.tmp(type), value)
652
+ end
653
+ end
654
+
655
+ def empty_array(type, size)
656
+ sizevar = size.precompile(self)
657
+ @method.print "#{@lvalue unless size.expr?(self)}new #{type.name}["
658
+ sizevar.compile(self, true)
659
+ @method.print ']'
660
+ end
661
+
662
+ def string(value)
663
+ @method.print value.inspect
664
+ end
665
+
666
+ def boolean(value)
667
+ @method.print value ? 'true' : 'false'
668
+ end
669
+
670
+ def regexp(value, flags = 0)
671
+ @method.print "java.util.regex.Pattern.compile("
672
+ @method.print value.inspect
673
+ @method.print ")"
674
+ end
675
+
676
+ def array(node, expression)
677
+ if expression
678
+ # create unmodifiable list from array (simplest way to do this in Java source)
679
+ @method.print "java.util.Collections.unmodifiableList(java.util.Arrays.asList("
680
+
681
+ # elements, as expressions
682
+ comma = false
683
+ node.children.each do |n|
684
+ @method.print ", " if comma
685
+ n.compile(self, true)
686
+ comma = true
687
+ end
688
+
689
+ @method.print("))")
690
+ else
691
+ # elements, as non-expressions
692
+ # TODO: ensure they're all reference types!
693
+ node.children.each do |n|
694
+ n.compile(self, false)
695
+ end
696
+ end
697
+ end
698
+
699
+ def build_string(orig_nodes, expression)
700
+ if expression
701
+ nodes = precompile_nodes(orig_nodes)
702
+ simple = nodes.equal?(orig_nodes)
703
+ if !simple
704
+ @method.print(lvalue)
705
+ end
706
+ first = true
707
+ unless nodes[0].kind_of?(Mirah::AST::String)
708
+ @method.print '""'
709
+ first = false
710
+ end
711
+ nodes.each do |node|
712
+ @method.print ' + ' unless first
713
+ first = false
714
+ node.compile(self, true)
715
+ end
716
+ @method.puts ';' unless simple
717
+ else
718
+ orig_nodes.each {|n| n.compile(self, false)}
719
+ end
720
+ end
721
+
722
+ def to_string(body, expression)
723
+ body.compile(self, expression)
724
+ end
725
+
726
+ def null
727
+ @method.print 'null'
728
+ end
729
+
730
+ def binding_reference
731
+ @method.print '$binding'
732
+ end
733
+
734
+ def real_self
735
+ @method.print 'this'
736
+ end
737
+
738
+ def print(node)
739
+ value = node.parameters[0]
740
+ value = value && value.precompile(self)
741
+ if node.println
742
+ @method.print "System.out.println("
743
+ else
744
+ @method.print "System.out.print("
745
+ end
746
+ value.compile(self, true) if value
747
+ @method.puts ');'
748
+ end
749
+
750
+ class ClosureCompiler < JavaSource
751
+ def initialize(file, type, parent)
752
+ @file = file
753
+ @type = type
754
+ @parent = parent
755
+ end
756
+
757
+ def prepare_binding(scope)
758
+ if scope.has_binding?
759
+ type = scope.binding_type
760
+ @binding = @parent.get_binding(type)
761
+ @method.puts("#{type.to_source} $binding = this.binding;")
762
+ end
763
+ begin
764
+ yield
765
+ ensure
766
+ if scope.has_binding?
767
+ @binding = nil
768
+ end
769
+ end
770
+ end
771
+
772
+ def declared_captures
773
+ @parent.declared_captures(@binding)
774
+ end
775
+ end
776
+ end
777
+ end
778
+ end
779
+ end