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,851 @@
1
+ module Mirah
2
+ module JVM
3
+ module Compiler
4
+ class JVMBytecode < Base
5
+ java_import java.lang.System
6
+ java_import java.io.PrintStream
7
+ include Mirah::JVM::MethodLookup
8
+ Types = Mirah::JVM::Types
9
+
10
+ class << self
11
+ attr_accessor :verbose
12
+
13
+ def log(message)
14
+ puts "* [#{name}] #{message}" if JVMBytecode.verbose
15
+ end
16
+
17
+ def classname_from_filename(filename)
18
+ basename = File.basename(filename).sub(/\.(duby|mirah)$/, '')
19
+ basename.split(/_/).map{|x| x[0...1].upcase + x[1..-1]}.join
20
+ end
21
+ end
22
+
23
+ module JVMLogger
24
+ def log(message); JVMBytecode.log(message); end
25
+ end
26
+
27
+ class ImplicitSelf
28
+ attr_reader :inferred_type
29
+
30
+ def initialize(type)
31
+ @inferred_type = type
32
+ end
33
+
34
+ def compile(compiler, expression)
35
+ compiler.compile_self if expression
36
+ end
37
+ end
38
+
39
+ def initialize
40
+ super
41
+ @jump_scope = []
42
+ end
43
+
44
+ def file_builder(filename)
45
+ builder = BiteScript::FileBuilder.new(filename)
46
+ AST.type_factory.define_types(builder)
47
+ builder
48
+ end
49
+
50
+ def output_type
51
+ "classes"
52
+ end
53
+
54
+ def push_jump_scope(node)
55
+ raise "Not a node" unless Mirah::AST::Node === node
56
+ begin
57
+ @jump_scope << node
58
+ yield
59
+ ensure
60
+ @jump_scope.pop
61
+ end
62
+ end
63
+
64
+ def find_ensures(before)
65
+ found = []
66
+ @jump_scope.reverse_each do |scope|
67
+ if Mirah::AST::Ensure === scope
68
+ found << scope
69
+ end
70
+ break if before === scope
71
+ end
72
+ found
73
+ end
74
+
75
+ def begin_main
76
+ # declare argv variable
77
+ @method.local('argv', AST.type(nil, 'string', true))
78
+ end
79
+
80
+ def finish_main
81
+ @method.returnvoid
82
+ end
83
+
84
+ def prepare_binding(scope)
85
+ if scope.has_binding?
86
+ type = scope.binding_type
87
+ @binding = @bindings[type]
88
+ @method.new type
89
+ @method.dup
90
+ @method.invokespecial type, "<init>", [@method.void]
91
+ if scope.respond_to? :arguments
92
+ scope.arguments.args.each do |param|
93
+ name = param.name
94
+ param_type = param.inferred_type
95
+ if scope.static_scope.captured?(param.name)
96
+ @method.dup
97
+ type.load(@method, @method.local(name, param_type))
98
+ @method.putfield(type, name, param_type)
99
+ end
100
+ end
101
+ end
102
+ type.store(@method, @method.local('$binding', type))
103
+ end
104
+ begin
105
+ yield
106
+ ensure
107
+ if scope.has_binding?
108
+ @binding.stop
109
+ @binding = nil
110
+ end
111
+ end
112
+ end
113
+
114
+ def define_method(node)
115
+ push_jump_scope(node) do
116
+ base_define_method(node, true) do |method, arg_types|
117
+ return if @class.interface?
118
+
119
+ log "Starting new #{node.static? ? 'static ' : ''}method #{node.name}(#{arg_types})"
120
+ args = node.arguments.args
121
+ method_body(method, args, node, node.signature[:return])
122
+ log "Method #{node.name}(#{arg_types}) complete!"
123
+ end
124
+ end
125
+ end
126
+
127
+ def define_optarg_chain(name, arg, return_type,
128
+ args_for_opt, arg_types_for_opt)
129
+ # declare all args so they get their values
130
+ @method.aload(0) unless @static
131
+ args_for_opt.each do |req_arg|
132
+ req_arg.inferred_type.load(@method, @method.local(req_arg.name, req_arg.inferred_type))
133
+ end
134
+ arg.value.compile(self, true)
135
+
136
+ # invoke the next one in the chain
137
+ if @static
138
+ @method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
139
+ else
140
+ @method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
141
+ end
142
+
143
+ return_type.return(@method)
144
+ end
145
+
146
+ def constructor(node)
147
+ push_jump_scope(node) do
148
+ super(node, true) do |method, args|
149
+ method_body(method, args, node, Types::Void) do
150
+ method.aload 0
151
+ if node.delegate_args
152
+ if node.calls_super
153
+ delegate_class = @type.superclass
154
+ else
155
+ delegate_class = @type
156
+ end
157
+ delegate_types = node.delegate_args.map do |arg|
158
+ arg.inferred_type
159
+ end
160
+ constructor = delegate_class.constructor(*delegate_types)
161
+ node.delegate_args.each do |arg|
162
+ arg.compile(self, true)
163
+ end
164
+ method.invokespecial(
165
+ delegate_class, "<init>",
166
+ [@method.void, *constructor.argument_types])
167
+ else
168
+ method.invokespecial @class.superclass, "<init>", [@method.void]
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ def method_body(method, args, node, return_type)
176
+ body = node.body
177
+ with(:method => method,
178
+ :declared_locals => {}) do
179
+
180
+ method.start
181
+
182
+ scope = node.static_scope
183
+
184
+ # declare all args so they get their values
185
+ if args
186
+ args.each {|arg| declare_local(scope, arg.name, arg.inferred_type)}
187
+ end
188
+ declare_locals(scope)
189
+
190
+ yield if block_given?
191
+
192
+ prepare_binding(node) do
193
+ expression = return_type != Types::Void
194
+ body.compile(self, expression) if body
195
+ end
196
+
197
+ return_type.return(@method)
198
+
199
+ @method.stop
200
+ end
201
+ end
202
+
203
+ def define_closure(class_def, expression)
204
+ compiler = ClosureCompiler.new(@file, @type, self)
205
+ compiler.define_class(class_def, expression)
206
+ end
207
+
208
+ def branch(iff, expression)
209
+ elselabel = @method.label
210
+ donelabel = @method.label
211
+
212
+ # this is ugly...need a better way to abstract the idea of compiling a
213
+ # conditional branch while still fitting into JVM opcodes
214
+ predicate = iff.condition.predicate
215
+ if iff.body || expression
216
+ jump_if_not(predicate, elselabel)
217
+
218
+ if iff.body
219
+ iff.body.compile(self, expression)
220
+ elsif expression
221
+ iff.inferred_type.init_value(@method)
222
+ end
223
+
224
+ @method.goto(donelabel)
225
+ else
226
+ jump_if(predicate, donelabel)
227
+ end
228
+
229
+ elselabel.set!
230
+
231
+ if iff.else
232
+ iff.else.compile(self, expression)
233
+ elsif expression
234
+ iff.inferred_type.init_value(@method)
235
+ end
236
+
237
+ donelabel.set!
238
+ end
239
+
240
+ def loop(loop, expression)
241
+ push_jump_scope(loop) do
242
+ with(:break_label => @method.label,
243
+ :redo_label => @method.label,
244
+ :next_label => @method.label) do
245
+ predicate = loop.condition.predicate
246
+
247
+ loop.init.compile(self, false) if loop.init?
248
+
249
+ pre_label = @redo_label
250
+
251
+ if loop.check_first
252
+ @next_label.set! unless loop.post?
253
+ if loop.negative
254
+ # if condition, exit
255
+ jump_if(predicate, @break_label)
256
+ else
257
+ # if not condition, exit
258
+ jump_if_not(predicate, @break_label)
259
+ end
260
+ end
261
+
262
+ if loop.pre?
263
+ pre_label = method.label
264
+ pre_label.set!
265
+ loop.pre.compile(self, false)
266
+ end
267
+
268
+
269
+ @redo_label.set!
270
+ loop.body.compile(self, false) if loop.body
271
+
272
+ if loop.check_first && !loop.post?
273
+ @method.goto(@next_label)
274
+ else
275
+ @next_label.set!
276
+ loop.post.compile(self, false) if loop.post?
277
+ if loop.negative
278
+ # if not condition, continue
279
+ jump_if_not(predicate, pre_label)
280
+ else
281
+ # if condition, continue
282
+ jump_if(predicate, pre_label)
283
+ end
284
+ end
285
+
286
+ @break_label.set!
287
+
288
+ # loops always evaluate to null
289
+ @method.aconst_null if expression
290
+ end
291
+ end
292
+ end
293
+
294
+ def break(node)
295
+ error("break outside of loop", node) unless @break_label
296
+ handle_ensures(find_ensures(Mirah::AST::Loop))
297
+ @method.goto(@break_label)
298
+ end
299
+
300
+ def next(node)
301
+ error("next outside of loop", node) unless @next_label
302
+ handle_ensures(find_ensures(Mirah::AST::Loop))
303
+ @method.goto(@next_label)
304
+ end
305
+
306
+ def redo(node)
307
+ error("redo outside of loop", node) unless @redo_label
308
+ handle_ensures(find_ensures(Mirah::AST::Loop))
309
+ @method.goto(@redo_label)
310
+ end
311
+
312
+ def jump_if(predicate, target)
313
+ unless predicate.inferred_type == Types::Boolean
314
+ raise "Expected boolean, found #{predicate.inferred_type}"
315
+ end
316
+ if Mirah::AST::Call === predicate
317
+ method = extract_method(predicate)
318
+ if method.respond_to? :jump_if
319
+ method.jump_if(self, predicate, target)
320
+ return
321
+ end
322
+ end
323
+ predicate.compile(self, true)
324
+ @method.ifne(target)
325
+ end
326
+
327
+ def jump_if_not(predicate, target)
328
+ unless predicate.inferred_type == Types::Boolean
329
+ raise "Expected boolean, found #{predicate.inferred_type}"
330
+ end
331
+ if Mirah::AST::Call === predicate
332
+ method = extract_method(predicate)
333
+ if method.respond_to? :jump_if_not
334
+ method.jump_if_not(self, predicate, target)
335
+ return
336
+ end
337
+ end
338
+ predicate.compile(self, true)
339
+ @method.ifeq(target)
340
+ end
341
+
342
+ def extract_method(call)
343
+ target = call.target.inferred_type!
344
+ params = call.parameters.map do |param|
345
+ param.inferred_type!
346
+ end
347
+ target.get_method(call.name, params)
348
+ end
349
+
350
+ def call(call, expression)
351
+ return cast(call, expression) if call.cast?
352
+ method = extract_method(call)
353
+ if method
354
+ method.call(self, call, expression)
355
+ else
356
+ raise "Missing method #{target}.#{call.name}(#{params.join ', '})"
357
+ end
358
+ end
359
+
360
+ def self_call(fcall, expression)
361
+ return cast(fcall, expression) if fcall.cast?
362
+ type = fcall.scope.static_scope.self_type
363
+ type = type.meta if (@static && type == @type)
364
+ fcall.target = ImplicitSelf.new(type)
365
+
366
+ params = fcall.parameters.map do |param|
367
+ param.inferred_type
368
+ end
369
+ method = type.get_method(fcall.name, params)
370
+ unless method
371
+ target = static ? @class.name : 'self'
372
+
373
+ raise NameError, "No method %s.%s(%s)" %
374
+ [target, fcall.name, params.join(', ')]
375
+ end
376
+ method.call(self, fcall, expression)
377
+ end
378
+
379
+ def super_call(sup, expression)
380
+ type = @type.superclass
381
+ sup.target = ImplicitSelf.new(type)
382
+
383
+ params = sup.parameters.map do |param|
384
+ param.inferred_type
385
+ end
386
+ method = type.get_method(sup.name, params)
387
+ unless method
388
+
389
+ raise NameError, "No method %s.%s(%s)" %
390
+ [type, sup.name, params.join(', ')]
391
+ end
392
+ method.call_special(self, sup, expression)
393
+ end
394
+
395
+ def cast(fcall, expression)
396
+ # casting operation, not a call
397
+ castee = fcall.parameters[0]
398
+
399
+ # TODO move errors to inference phase
400
+ source_type_name = castee.inferred_type.name
401
+ target_type_name = fcall.inferred_type.name
402
+ if castee.inferred_type.primitive?
403
+ if fcall.inferred_type.primitive?
404
+ if source_type_name == 'boolean' && target_type_name != "boolean"
405
+ raise TypeError.new "not a boolean type: #{castee.inferred_type}"
406
+ end
407
+ # ok
408
+ primitive = true
409
+ else
410
+ raise TypeError.new "Cannot cast #{castee.inferred_type} to #{fcall.inferred_type}: not a reference type."
411
+ end
412
+ elsif fcall.inferred_type.primitive?
413
+ raise TypeError.new "not a primitive type: #{castee.inferred_type}"
414
+ else
415
+ # ok
416
+ primitive = false
417
+ end
418
+
419
+ castee.compile(self, expression)
420
+ if expression
421
+ if primitive
422
+ source_type_name = 'int' if %w[byte short char].include? source_type_name
423
+ if (source_type_name != 'int') && (%w[byte short char].include? target_type_name)
424
+ target_type_name = 'int'
425
+ end
426
+
427
+ if source_type_name != target_type_name
428
+ if RUBY_VERSION == "1.9"
429
+ @method.send "#{source_type_name[0]}2#{target_type_name[0]}"
430
+ else
431
+ @method.send "#{source_type_name[0].chr}2#{target_type_name[0].chr}"
432
+ end
433
+ end
434
+ else
435
+ if (source_type_name != target_type_name ||
436
+ castee.inferred_type.array? != fcall.inferred_type.array?)
437
+ @method.checkcast fcall.inferred_type
438
+ end
439
+ end
440
+ end
441
+ end
442
+
443
+ def body(body, expression)
444
+ # last element is an expression only if the body is an expression
445
+ super(body, expression) do |last|
446
+ compile(last, expression)
447
+ end
448
+ end
449
+
450
+ def local(scope, name, type)
451
+ type.load(@method, @method.local(scoped_local_name(name, scope), type))
452
+ end
453
+
454
+ def local_assign(scope, name, type, expression, value)
455
+ declare_local(scope, name, type)
456
+
457
+ value.compile(self, true)
458
+
459
+ # if expression, dup the value we're assigning
460
+ @method.dup if expression
461
+
462
+ type.store(@method, @method.local(scoped_local_name(name, scope), type))
463
+ end
464
+
465
+ def declared_locals
466
+ @declared_locals ||= {}
467
+ end
468
+
469
+ def annotate(builder, annotations)
470
+ annotations.each do |annotation|
471
+ type = annotation.type
472
+ type = type.jvm_type if type.respond_to?(:jvm_type)
473
+ builder.annotate(type, annotation.runtime?) do |visitor|
474
+ annotation.values.each do |name, value|
475
+ annotation_value(visitor, name, value)
476
+ end
477
+ end
478
+ end
479
+ end
480
+
481
+ def annotation_value(builder, name, value)
482
+ case value
483
+ when Mirah::AST::Annotation
484
+ type = value.type
485
+ type = type.jvm_type if type.respond_to?(:jvm_type)
486
+ builder.annotation(name, type) do |child|
487
+ value.values.each do |name, value|
488
+ annotation_value(child, name, value)
489
+ end
490
+ end
491
+ when ::Array
492
+ builder.array(name) do |array|
493
+ value.each do |item|
494
+ annotation_value(array, nil, item)
495
+ end
496
+ end
497
+ else
498
+ builder.value(name, value)
499
+ end
500
+ end
501
+
502
+ def declared?(scope, name)
503
+ declared_locals.include?(scoped_local_name(name, scope))
504
+ end
505
+
506
+ def declare_local(scope, name, type)
507
+ # TODO confirm types are compatible
508
+ name = scoped_local_name(name, scope)
509
+ unless declared_locals[name]
510
+ declared_locals[name] = type
511
+ index = @method.local(name, type)
512
+ end
513
+ end
514
+
515
+ def local_declare(scope, name, type)
516
+ end
517
+
518
+ def declare_locals(scope)
519
+ scope.locals.each do |name|
520
+ unless scope.captured?(name) || declared?(scope, name)
521
+ type = scope.local_type(name)
522
+ declare_local(scope, name, type)
523
+ type.init_value(@method)
524
+ type.store(@method, @method.local(scoped_local_name(name, scope), type))
525
+ end
526
+ end
527
+ end
528
+
529
+ def get_binding(type)
530
+ @bindings[type]
531
+ end
532
+
533
+ def declared_captures(binding=nil)
534
+ @captured_locals[binding || @binding]
535
+ end
536
+
537
+ def captured_local_declare(scope, name, type)
538
+ unless declared_captures[name]
539
+ declared_captures[name] = type
540
+ # default should be fine, but I don't think bitescript supports it.
541
+ @binding.protected_field(name, type)
542
+ end
543
+ end
544
+
545
+ def captured_local(scope, name, type)
546
+ captured_local_declare(scope, name, type)
547
+ binding_reference
548
+ @method.getfield(scope.binding_type, name, type)
549
+ end
550
+
551
+ def captured_local_assign(node, expression)
552
+ scope, name, type = node.containing_scope, node.name, node.inferred_type
553
+ captured_local_declare(scope, name, type)
554
+ binding_reference
555
+ node.value.compile(self, true)
556
+ @method.dup_x2 if expression
557
+ @method.putfield(scope.binding_type, name, type)
558
+ end
559
+
560
+ def field(name, type, annotations, static_field)
561
+ name = name[1..-1] if name =~ /^@/
562
+
563
+ real_type = declared_fields[name] || type
564
+
565
+ declare_field(name, real_type, annotations, static_field)
566
+
567
+ # load self object unless static
568
+ method.aload 0 unless static || static_field
569
+
570
+ if static || static_field
571
+ @method.getstatic(@class, name, type)
572
+ else
573
+ @method.getfield(@class, name, type)
574
+ end
575
+ end
576
+
577
+ def declared_fields
578
+ @declared_fields ||= {}
579
+ @declared_fields[@class] ||= {}
580
+ end
581
+
582
+ def declare_field(name, type, annotations, static_field)
583
+ # TODO confirm types are compatible
584
+ unless declared_fields[name]
585
+ declared_fields[name] = type
586
+ field = if static || static_field
587
+ @class.private_static_field name, type
588
+ else
589
+ @class.private_field name, type
590
+ end
591
+ annotate(field, annotations)
592
+ end
593
+ end
594
+
595
+ def field_declare(name, type, annotations, static_field)
596
+ name = name[1..-1] if name =~ /^@/
597
+ declare_field(name, type, annotations, static_field)
598
+ end
599
+
600
+ def field_assign(name, type, expression, value, annotations, static_field)
601
+ name = name[1..-1] if name =~ /^@/
602
+
603
+ real_type = declared_fields[name] || type
604
+
605
+ declare_field(name, real_type, annotations, static_field)
606
+
607
+ method.aload 0 unless static || static_field
608
+ value.compile(self, true)
609
+ if expression
610
+ instruction = 'dup'
611
+ instruction << '2' if type.wide?
612
+ instruction << '_x1' unless static || static_field
613
+ method.send instruction
614
+ end
615
+
616
+ if static || static_field
617
+ @method.putstatic(@class, name, real_type)
618
+ else
619
+ @method.putfield(@class, name, real_type)
620
+ end
621
+ end
622
+
623
+ def string(value)
624
+ @method.ldc(value)
625
+ end
626
+
627
+ def build_string(nodes, expression)
628
+ if expression
629
+ # could probably be more efficient with non-default constructor
630
+ builder_class = Mirah::AST.type(nil, 'java.lang.StringBuilder')
631
+ @method.new builder_class
632
+ @method.dup
633
+ @method.invokespecial builder_class, "<init>", [@method.void]
634
+
635
+ nodes.each do |node|
636
+ node.compile(self, true)
637
+ method = find_method(builder_class, "append", [node.inferred_type], false)
638
+ if method
639
+ @method.invokevirtual builder_class, "append", [method.return_type, *method.argument_types]
640
+ else
641
+ log "Could not find a match for #{java::lang::StringBuilder}.append(#{node.inferred_type})"
642
+ fail "Could not compile"
643
+ end
644
+ end
645
+
646
+ # convert to string
647
+ @method.invokevirtual java::lang::StringBuilder.java_class, "toString", [@method.string]
648
+ else
649
+ nodes.each do |node|
650
+ node.compile(self, false)
651
+ end
652
+ end
653
+ end
654
+
655
+ def to_string(body, expression)
656
+ if expression
657
+ body.compile(self, true)
658
+ body.inferred_type.box(@method) if body.inferred_type.primitive?
659
+ null = method.label
660
+ done = method.label
661
+ method.dup
662
+ method.ifnull(null)
663
+ @method.invokevirtual @method.object, "toString", [@method.string]
664
+ @method.goto(done)
665
+ null.set!
666
+ method.pop
667
+ method.ldc("null")
668
+ done.set!
669
+ else
670
+ body.compile(self, false)
671
+ end
672
+ end
673
+
674
+ def boolean(value)
675
+ value ? @method.iconst_1 : @method.iconst_0
676
+ end
677
+
678
+ def regexp(value, flags = 0)
679
+ # TODO: translate flags to Java-appropriate values
680
+ @method.ldc(value)
681
+ @method.invokestatic java::util::regex::Pattern, "compile", [java::util::regex::Pattern, @method.string]
682
+ end
683
+
684
+ def array(node, expression)
685
+ if expression
686
+ # create basic arraylist
687
+ @method.new java::util::ArrayList
688
+ @method.dup
689
+ @method.ldc_int node.children ? node.children.size : 0
690
+ @method.invokespecial java::util::ArrayList, "<init>", [@method.void, @method.int]
691
+
692
+ # elements, as expressions
693
+ # TODO: ensure they're all reference types!
694
+ node.children.each do |n|
695
+ @method.dup
696
+ n.compile(self, true)
697
+ # TODO this feels like it should be in the node.compile itself
698
+ if n.inferred_type!.primitive?
699
+ n.inferred_type.box(@method)
700
+ end
701
+ @method.invokeinterface java::util::List, "add", [@method.boolean, @method.object]
702
+ @method.pop
703
+ end
704
+
705
+ # make it unmodifiable
706
+ @method.invokestatic java::util::Collections, "unmodifiableList", [java::util::List, java::util::List]
707
+ else
708
+ # elements, as non-expressions
709
+ # TODO: ensure they're all reference types!
710
+ node.children.each do |n|
711
+ n.compile(self, true)
712
+ # TODO this feels like it should be in the node.compile itself
713
+ if n.inferred_type.primitive?
714
+ n.inferred_type.box(@method)
715
+ end
716
+ end
717
+ end
718
+ end
719
+
720
+ def null
721
+ @method.aconst_null
722
+ end
723
+
724
+ def binding_reference
725
+ @method.aload(@method.local('$binding'))
726
+ end
727
+
728
+ def real_self
729
+ method.aload(0)
730
+ end
731
+
732
+ def line(num)
733
+ @method.line(num - 1) if @method
734
+ end
735
+
736
+ def print(print_node)
737
+ @method.getstatic System, "out", PrintStream
738
+ print_node.parameters.each {|param| param.compile(self, true)}
739
+ params = print_node.parameters.map {|param| param.inferred_type.jvm_type}
740
+ method_name = print_node.println ? "println" : "print"
741
+ method = find_method(PrintStream.java_class, method_name, params, false)
742
+ if (method)
743
+ @method.invokevirtual(
744
+ PrintStream,
745
+ method_name,
746
+ [method.return_type, *method.parameter_types])
747
+ else
748
+ log "Could not find a match for #{PrintStream}.#{method_name}(#{params})"
749
+ fail "Could not compile"
750
+ end
751
+ end
752
+
753
+ def return(return_node)
754
+ return_node.value.compile(self, true) if return_node.value
755
+ handle_ensures(find_ensures(Mirah::AST::MethodDefinition))
756
+ return_node.inferred_type.return(@method)
757
+ end
758
+
759
+ def _raise(exception)
760
+ exception.compile(self, true)
761
+ @method.athrow
762
+ end
763
+
764
+ def rescue(rescue_node, expression)
765
+ start = @method.label.set!
766
+ body_end = @method.label
767
+ done = @method.label
768
+ rescue_node.body.compile(self, expression && rescue_node.else_node.nil?) if rescue_node.body
769
+ body_end.set!
770
+ rescue_node.else_node.compile(self, expression) if rescue_node.else_node
771
+ return if start.label.offset == body_end.label.offset
772
+ @method.goto(done)
773
+ rescue_node.clauses.each do |clause|
774
+ target = @method.label.set!
775
+ if clause.name
776
+ @method.astore(declare_local(clause.static_scope, clause.name, clause.type))
777
+ else
778
+ @method.pop
779
+ end
780
+ declare_locals(clause.static_scope)
781
+ clause.body.compile(self, expression)
782
+ @method.goto(done)
783
+ clause.types.each do |type|
784
+ @method.trycatch(start, body_end, target, type)
785
+ end
786
+ end
787
+ done.set!
788
+ end
789
+
790
+ def handle_ensures(nodes)
791
+ nodes.each do |ensure_node|
792
+ ensure_node.clause.compile(self, false)
793
+ end
794
+ end
795
+
796
+ def ensure(node, expression)
797
+ node.state = @method.label # Save the ensure target for JumpNodes
798
+ start = @method.label.set!
799
+ body_end = @method.label
800
+ done = @method.label
801
+ push_jump_scope(node) do
802
+ node.body.compile(self, expression) # First compile the body
803
+ end
804
+ body_end.set!
805
+ handle_ensures([node]) # run the ensure clause
806
+ @method.goto(done) # and continue on after the exception handler
807
+ target = @method.label.set! # Finally, create the exception handler
808
+ @method.trycatch(start, body_end, target, nil)
809
+ handle_ensures([node])
810
+ @method.athrow
811
+ done.set!
812
+ end
813
+
814
+ def empty_array(type, size)
815
+ size.compile(self, true)
816
+ type.newarray(@method)
817
+ end
818
+
819
+ class ClosureCompiler < JVMBytecode
820
+ def initialize(file, type, parent)
821
+ @file = file
822
+ @type = type
823
+ @jump_scope = []
824
+ @parent = parent
825
+ end
826
+
827
+ def prepare_binding(scope)
828
+ if scope.has_binding?
829
+ type = scope.binding_type
830
+ @binding = @parent.get_binding(type)
831
+ @method.aload 0
832
+ @method.getfield(@class, 'binding', @binding)
833
+ type.store(@method, @method.local('$binding', type))
834
+ end
835
+ begin
836
+ yield
837
+ ensure
838
+ if scope.has_binding?
839
+ @binding = nil
840
+ end
841
+ end
842
+ end
843
+
844
+ def declared_captures
845
+ @parent.declared_captures(@binding)
846
+ end
847
+ end
848
+ end
849
+ end
850
+ end
851
+ end