mirah 0.0.7-java → 0.0.8-java

Sign up to get free protection for your applications and to get access to all the features.
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