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