duby 0.0.2-java → 0.0.3-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 +7 -0
- data/README.txt +18 -7
- data/Rakefile +72 -0
- data/examples/ant/example-build.xml +7 -0
- data/examples/appengine/Rakefile +8 -67
- data/examples/appengine/Readme +4 -3
- data/examples/appengine/lib/duby/appengine_tasks.rb +173 -0
- data/examples/appengine/lib/duby/plugin/datastore.rb +92 -31
- data/examples/appengine/lib/duby_task.rb +61 -0
- data/examples/appengine/src/com/ribrdb/DubyApp.duby +32 -6
- data/examples/appengine/src/com/ribrdb/list.dhtml +2 -2
- data/examples/appengine/{config.ru → src/config.ru} +0 -0
- data/examples/bintrees.duby +66 -0
- data/examples/dynamic.duby +17 -0
- data/examples/fib.duby +3 -11
- data/examples/fields.duby +3 -3
- data/examples/fractal.duby +1 -3
- data/examples/sort_closure.duby +7 -0
- data/examples/swing.duby +11 -11
- data/javalib/duby-bootstrap.jar +0 -0
- data/javalib/dynalang-invoke-0.1.jar +0 -0
- data/lib/duby.rb +168 -35
- data/lib/duby/ast.rb +224 -27
- data/lib/duby/ast/call.rb +85 -25
- data/lib/duby/ast/class.rb +112 -28
- data/lib/duby/ast/flow.rb +65 -44
- data/lib/duby/ast/intrinsics.rb +223 -21
- data/lib/duby/ast/literal.rb +67 -16
- data/lib/duby/ast/local.rb +36 -40
- data/lib/duby/ast/method.rb +83 -67
- data/lib/duby/ast/structure.rb +105 -23
- data/lib/duby/compiler.rb +83 -28
- data/lib/duby/env.rb +33 -0
- data/lib/duby/jvm/base.rb +210 -0
- data/lib/duby/jvm/compiler.rb +293 -219
- data/lib/duby/jvm/method_lookup.rb +77 -67
- data/lib/duby/jvm/source_compiler.rb +250 -157
- data/lib/duby/jvm/source_generator/builder.rb +53 -49
- data/lib/duby/jvm/source_generator/loops.rb +9 -9
- data/lib/duby/jvm/source_generator/precompile.rb +35 -25
- data/lib/duby/jvm/typer.rb +19 -10
- data/lib/duby/jvm/types.rb +127 -68
- data/lib/duby/jvm/types/basic_types.rb +26 -13
- data/lib/duby/jvm/types/enumerable.rb +6 -4
- data/lib/duby/jvm/types/factory.rb +49 -13
- data/lib/duby/jvm/types/floats.rb +16 -0
- data/lib/duby/jvm/types/integers.rb +63 -2
- data/lib/duby/jvm/types/intrinsics.rb +43 -21
- data/lib/duby/jvm/types/methods.rb +326 -86
- data/lib/duby/jvm/types/number.rb +3 -0
- data/lib/duby/nbcompiler.rb +1 -1
- data/lib/duby/plugin/edb.rb +1 -1
- data/lib/duby/plugin/java.rb +10 -1
- data/lib/duby/transform.rb +134 -46
- data/lib/duby/typer.rb +75 -50
- data/test/test_ast.rb +106 -106
- data/test/test_compilation.rb +46 -32
- data/test/test_env.rb +42 -0
- data/test/test_java_typer.rb +35 -51
- data/test/test_javac_compiler.rb +4 -1
- data/test/test_jvm_compiler.rb +564 -133
- data/test/test_typer.rb +68 -92
- metadata +37 -21
- data/examples/README +0 -16
- data/lib/duby/c/compiler.rb +0 -134
- data/lib/duby/old/compiler_old.rb +0 -845
- data/lib/duby/old/declaration.rb +0 -72
- data/lib/duby/old/mapper.rb +0 -72
- data/lib/duby/old/signature.rb +0 -52
- data/lib/duby/old/typer_old.rb +0 -163
- data/lib/duby/plugin/math.rb +0 -84
- data/test/test_math_plugin.rb +0 -87
data/lib/duby/jvm/compiler.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'duby'
|
2
|
+
require 'duby/jvm/base'
|
2
3
|
require 'duby/jvm/method_lookup'
|
3
4
|
require 'duby/jvm/types'
|
4
5
|
require 'duby/typer'
|
@@ -15,9 +16,9 @@ module Duby
|
|
15
16
|
attr_accessor :target
|
16
17
|
end
|
17
18
|
end
|
18
|
-
|
19
|
+
|
19
20
|
module Compiler
|
20
|
-
class JVM
|
21
|
+
class JVM < JVMCompilerBase
|
21
22
|
java_import java.lang.System
|
22
23
|
java_import java.io.PrintStream
|
23
24
|
include Duby::JVM::MethodLookup
|
@@ -29,46 +30,39 @@ module Duby
|
|
29
30
|
def log(message)
|
30
31
|
puts "* [#{name}] #{message}" if JVM.verbose
|
31
32
|
end
|
33
|
+
|
34
|
+
def classname_from_filename(filename)
|
35
|
+
basename = File.basename(filename, '.duby')
|
36
|
+
basename.split(/_/).map{|x| x[0...1].upcase + x[1..-1]}.join
|
37
|
+
end
|
32
38
|
end
|
33
39
|
|
34
40
|
module JVMLogger
|
35
41
|
def log(message); JVM.log(message); end
|
36
42
|
end
|
37
|
-
include JVMLogger
|
38
43
|
|
39
44
|
class ImplicitSelf
|
40
45
|
attr_reader :inferred_type
|
41
|
-
|
46
|
+
|
42
47
|
def initialize(type)
|
43
48
|
@inferred_type = type
|
44
49
|
end
|
45
|
-
|
50
|
+
|
46
51
|
def compile(compiler, expression)
|
47
52
|
compiler.compile_self if expression
|
48
53
|
end
|
49
54
|
end
|
50
|
-
|
51
|
-
attr_accessor :filename, :src, :method, :static, :class
|
52
55
|
|
53
56
|
def initialize(filename)
|
54
|
-
|
55
|
-
@src = ""
|
56
|
-
@static = true
|
57
|
-
classname = File.basename(filename, '.duby')
|
57
|
+
super
|
58
58
|
BiteScript.bytecode_version = BiteScript::JAVA1_5
|
59
59
|
@file = BiteScript::FileBuilder.new(@filename)
|
60
60
|
AST.type_factory.define_types(@file)
|
61
|
-
@type = AST::type(classname)
|
62
61
|
@jump_scope = []
|
63
62
|
end
|
64
63
|
|
65
|
-
def
|
66
|
-
|
67
|
-
log "Compilation successful!"
|
68
|
-
end
|
69
|
-
|
70
|
-
def toplevel_class
|
71
|
-
@class = @type.define(@file)
|
64
|
+
def output_type
|
65
|
+
"classes"
|
72
66
|
end
|
73
67
|
|
74
68
|
def push_jump_scope(node)
|
@@ -80,7 +74,7 @@ module Duby
|
|
80
74
|
@jump_scope.pop
|
81
75
|
end
|
82
76
|
end
|
83
|
-
|
77
|
+
|
84
78
|
def find_ensures(before)
|
85
79
|
found = []
|
86
80
|
@jump_scope.reverse_each do |scope|
|
@@ -92,132 +86,99 @@ module Duby
|
|
92
86
|
found
|
93
87
|
end
|
94
88
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
log "Starting main method"
|
100
|
-
|
101
|
-
@method.start
|
102
|
-
|
103
|
-
# declare argv variable
|
104
|
-
@method.local('argv', AST.type('string', true))
|
89
|
+
def begin_main
|
90
|
+
# declare argv variable
|
91
|
+
@method.local('argv', AST.type('string', true))
|
92
|
+
end
|
105
93
|
|
106
|
-
|
94
|
+
def finish_main
|
95
|
+
@method.returnvoid
|
96
|
+
end
|
107
97
|
|
108
|
-
|
109
|
-
|
98
|
+
def prepare_binding(scope)
|
99
|
+
if scope.has_binding?
|
100
|
+
type = scope.binding_type
|
101
|
+
@binding = @bindings[type]
|
102
|
+
@method.new type
|
103
|
+
@method.dup
|
104
|
+
@method.invokespecial type, "<init>", [@method.void]
|
105
|
+
type.store(@method, @method.local('$binding', type))
|
106
|
+
end
|
107
|
+
begin
|
108
|
+
yield
|
109
|
+
ensure
|
110
|
+
if scope.has_binding?
|
111
|
+
@binding.stop
|
112
|
+
@binding = nil
|
110
113
|
end
|
111
|
-
@class.stop
|
112
|
-
else
|
113
|
-
body.compile(self, false)
|
114
114
|
end
|
115
|
-
|
116
|
-
log "Main method complete!"
|
117
115
|
end
|
118
|
-
|
116
|
+
|
119
117
|
def define_method(node)
|
120
118
|
push_jump_scope(node) do
|
121
|
-
|
122
|
-
arg_types = if args
|
123
|
-
args.map { |arg| arg.inferred_type }
|
124
|
-
else
|
125
|
-
[]
|
126
|
-
end
|
127
|
-
return_type = signature[:return]
|
128
|
-
exceptions = signature[:throws]
|
129
|
-
|
130
|
-
with :static => @static || node.static? do
|
131
|
-
if @static
|
132
|
-
method = @class.public_static_method(name.to_s, exceptions, return_type, *arg_types)
|
133
|
-
else
|
134
|
-
method = @class.public_method(name.to_s, exceptions, return_type, *arg_types)
|
135
|
-
end
|
136
|
-
|
137
|
-
annotate(method, node.annotations)
|
138
|
-
|
119
|
+
super(node, true) do |method, arg_types|
|
139
120
|
return if @class.interface?
|
140
121
|
|
141
|
-
log "Starting new method #{name}(#{arg_types})"
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
if AST::OptionalArgument === arg
|
149
|
-
if @static
|
150
|
-
method = @class.public_static_method(name.to_s, exceptions, return_type, *arg_types_for_opt)
|
151
|
-
else
|
152
|
-
method = @class.public_method(name.to_s, exceptions, return_type, *arg_types_for_opt)
|
153
|
-
end
|
154
|
-
|
155
|
-
with :method => method do
|
156
|
-
log "Starting new method #{name}(#{arg_types_for_opt})"
|
157
|
-
|
158
|
-
@method.start unless started
|
159
|
-
|
160
|
-
# declare all args so they get their values
|
161
|
-
|
162
|
-
expression = signature[:return] != Types::Void
|
163
|
-
|
164
|
-
@method.aload(0) unless @static
|
165
|
-
args_for_opt.each {|req_arg| @method.local(req_arg.name, req_arg.inferred_type)}
|
166
|
-
arg.children[0].compile(self, true)
|
167
|
-
|
168
|
-
# invoke the next one in the chain
|
169
|
-
if @static
|
170
|
-
@method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
|
171
|
-
else
|
172
|
-
@method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
|
173
|
-
end
|
122
|
+
log "Starting new #{node.static? ? 'static ' : ''}method #{node.name}(#{arg_types})"
|
123
|
+
args = node.arguments.args
|
124
|
+
method_body(method, args, node, node.signature[:return])
|
125
|
+
log "Method #{node.name}(#{arg_types}) complete!"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
174
129
|
|
175
|
-
|
130
|
+
def define_optarg_chain(name, arg, return_type,
|
131
|
+
args_for_opt, arg_types_for_opt)
|
132
|
+
# declare all args so they get their values
|
133
|
+
@method.aload(0) unless @static
|
134
|
+
args_for_opt.each do |req_arg|
|
135
|
+
req_arg.inferred_type.load(@method, @method.local(req_arg.name, req_arg.inferred_type))
|
136
|
+
end
|
137
|
+
arg.children[0].value.compile(self, true)
|
176
138
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
end
|
184
|
-
end
|
139
|
+
# invoke the next one in the chain
|
140
|
+
if @static
|
141
|
+
@method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
|
142
|
+
else
|
143
|
+
@method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
|
144
|
+
end
|
185
145
|
|
186
|
-
|
146
|
+
return_type.return(@method)
|
187
147
|
end
|
188
|
-
|
148
|
+
|
189
149
|
def constructor(node)
|
190
150
|
push_jump_scope(node) do
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
151
|
+
super(node, true) do |method, args|
|
152
|
+
method_body(method, args, node, Types::Void) do
|
153
|
+
method.aload 0
|
154
|
+
if node.delegate_args
|
155
|
+
if node.calls_super
|
156
|
+
delegate_class = @type.superclass
|
157
|
+
else
|
158
|
+
delegate_class = @type
|
159
|
+
end
|
160
|
+
delegate_types = node.delegate_args.map do |arg|
|
161
|
+
arg.inferred_type
|
162
|
+
end
|
163
|
+
constructor = delegate_class.constructor(*delegate_types)
|
164
|
+
node.delegate_args.each do |arg|
|
165
|
+
arg.compile(self, true)
|
166
|
+
end
|
167
|
+
method.invokespecial(
|
168
|
+
delegate_class, "<init>",
|
169
|
+
[@method.void, *constructor.argument_types])
|
201
170
|
else
|
202
|
-
|
171
|
+
method.invokespecial @class.superclass, "<init>", [@method.void]
|
203
172
|
end
|
204
|
-
delegate_types = node.delegate_args.map {|arg| arg.inferred_type}
|
205
|
-
constructor = delegate_class.constructor(*delegate_types)
|
206
|
-
node.delegate_args.each do |arg|
|
207
|
-
arg.compile(self, true)
|
208
|
-
end
|
209
|
-
method.invokespecial(
|
210
|
-
delegate_class, "<init>",
|
211
|
-
[@method.void, *constructor.argument_types])
|
212
|
-
else
|
213
|
-
method.invokespecial @class.superclass, "<init>", [@method.void]
|
214
173
|
end
|
215
174
|
end
|
216
175
|
end
|
217
176
|
end
|
218
177
|
|
219
|
-
def method_body(method, args,
|
220
|
-
|
178
|
+
def method_body(method, args, node, return_type)
|
179
|
+
body = node.body
|
180
|
+
with(:method => method,
|
181
|
+
:declared_locals => {}) do
|
221
182
|
|
222
183
|
method.start
|
223
184
|
|
@@ -225,36 +186,32 @@ module Duby
|
|
225
186
|
if args
|
226
187
|
args.each {|arg| @method.local(arg.name, arg.inferred_type)}
|
227
188
|
end
|
228
|
-
|
229
189
|
yield if block_given?
|
230
190
|
|
231
|
-
|
232
|
-
|
191
|
+
prepare_binding(node) do
|
192
|
+
expression = return_type != Types::Void
|
193
|
+
body.compile(self, expression) if body
|
194
|
+
end
|
233
195
|
|
234
196
|
return_type.return(@method)
|
235
|
-
|
197
|
+
|
236
198
|
@method.stop
|
237
199
|
end
|
238
200
|
end
|
239
201
|
|
240
|
-
def
|
241
|
-
|
242
|
-
|
243
|
-
:static => false) do
|
244
|
-
annotate(@class, class_def.annotations)
|
245
|
-
class_def.body.compile(self, false) if class_def.body
|
246
|
-
@class.stop
|
247
|
-
end
|
202
|
+
def define_closure(class_def, expression)
|
203
|
+
compiler = ClosureCompiler.new(@file, @type, self)
|
204
|
+
compiler.define_class(class_def, expression)
|
248
205
|
end
|
249
|
-
|
206
|
+
|
250
207
|
def declare_argument(name, type)
|
251
208
|
# declare local vars for arguments here
|
252
209
|
end
|
253
|
-
|
210
|
+
|
254
211
|
def branch(iff, expression)
|
255
212
|
elselabel = @method.label
|
256
213
|
donelabel = @method.label
|
257
|
-
|
214
|
+
|
258
215
|
# this is ugly...need a better way to abstract the idea of compiling a
|
259
216
|
# conditional branch while still fitting into JVM opcodes
|
260
217
|
predicate = iff.condition.predicate
|
@@ -314,7 +271,7 @@ module Duby
|
|
314
271
|
|
315
272
|
@redo_label.set!
|
316
273
|
loop.body.compile(self, false)
|
317
|
-
|
274
|
+
|
318
275
|
if loop.check_first && !loop.post?
|
319
276
|
@method.goto(@next_label)
|
320
277
|
else
|
@@ -328,9 +285,9 @@ module Duby
|
|
328
285
|
jump_if(predicate, pre_label)
|
329
286
|
end
|
330
287
|
end
|
331
|
-
|
288
|
+
|
332
289
|
@break_label.set!
|
333
|
-
|
290
|
+
|
334
291
|
# loops always evaluate to null
|
335
292
|
@method.aconst_null if expression
|
336
293
|
end
|
@@ -341,29 +298,29 @@ module Duby
|
|
341
298
|
handle_ensures(find_ensures(Duby::AST::Loop))
|
342
299
|
@method.goto(@break_label)
|
343
300
|
end
|
344
|
-
|
301
|
+
|
345
302
|
def next(node)
|
346
303
|
handle_ensures(find_ensures(Duby::AST::Loop))
|
347
304
|
@method.goto(@next_label)
|
348
305
|
end
|
349
|
-
|
306
|
+
|
350
307
|
def redo(node)
|
351
308
|
handle_ensures(find_ensures(Duby::AST::Loop))
|
352
309
|
@method.goto(@redo_label)
|
353
310
|
end
|
354
|
-
|
311
|
+
|
355
312
|
def jump_if(predicate, target)
|
356
313
|
raise "Expected boolean, found #{predicate.inferred_type}" unless predicate.inferred_type == Types::Boolean
|
357
314
|
predicate.compile(self, true)
|
358
315
|
@method.ifne(target)
|
359
316
|
end
|
360
|
-
|
317
|
+
|
361
318
|
def jump_if_not(predicate, target)
|
362
319
|
raise "Expected boolean, found #{predicate.inferred_type}" unless predicate.inferred_type == Types::Boolean
|
363
320
|
predicate.compile(self, true)
|
364
321
|
@method.ifeq(target)
|
365
322
|
end
|
366
|
-
|
323
|
+
|
367
324
|
def call(call, expression)
|
368
325
|
target = call.target.inferred_type
|
369
326
|
params = call.parameters.map do |param|
|
@@ -376,7 +333,7 @@ module Duby
|
|
376
333
|
raise "Missing method #{target}.#{call.name}(#{params.join ', '})"
|
377
334
|
end
|
378
335
|
end
|
379
|
-
|
336
|
+
|
380
337
|
def self_call(fcall, expression)
|
381
338
|
return cast(fcall, expression) if fcall.cast?
|
382
339
|
type = @type
|
@@ -389,7 +346,7 @@ module Duby
|
|
389
346
|
method = type.get_method(fcall.name, params)
|
390
347
|
unless method
|
391
348
|
target = static ? @class.name : 'self'
|
392
|
-
|
349
|
+
|
393
350
|
raise NameError, "No method %s.%s(%s)" %
|
394
351
|
[target, fcall.name, params.join(', ')]
|
395
352
|
end
|
@@ -415,7 +372,7 @@ module Duby
|
|
415
372
|
def cast(fcall, expression)
|
416
373
|
# casting operation, not a call
|
417
374
|
castee = fcall.parameters[0]
|
418
|
-
|
375
|
+
|
419
376
|
# TODO move errors to inference phase
|
420
377
|
source_type_name = castee.inferred_type.name
|
421
378
|
target_type_name = fcall.inferred_type.name
|
@@ -465,31 +422,27 @@ module Duby
|
|
465
422
|
end
|
466
423
|
end
|
467
424
|
end
|
468
|
-
|
425
|
+
|
469
426
|
def body(body, expression)
|
470
|
-
# all except the last element in a body of code is treated as a statement
|
471
|
-
i, last = 0, body.children.size - 1
|
472
|
-
while i < last
|
473
|
-
body.children[i].compile(self, false)
|
474
|
-
i += 1
|
475
|
-
end
|
476
427
|
# last element is an expression only if the body is an expression
|
477
|
-
body
|
428
|
+
super(body, expression) do |last|
|
429
|
+
last.compile(self, expression)
|
430
|
+
end
|
478
431
|
end
|
479
|
-
|
480
|
-
def local(name, type)
|
481
|
-
type.load(@method, @method.local(name, type))
|
432
|
+
|
433
|
+
def local(scope, name, type)
|
434
|
+
type.load(@method, @method.local(scoped_local_name(name, scope), type))
|
482
435
|
end
|
483
436
|
|
484
|
-
def local_assign(name, type, expression, value)
|
485
|
-
declare_local(name, type)
|
486
|
-
|
437
|
+
def local_assign(scope, name, type, expression, value)
|
438
|
+
declare_local(scope, name, type)
|
439
|
+
|
487
440
|
value.compile(self, true)
|
488
|
-
|
441
|
+
|
489
442
|
# if expression, dup the value we're assigning
|
490
443
|
@method.dup if expression
|
491
|
-
|
492
|
-
type.store(@method, @method.local(name, type))
|
444
|
+
|
445
|
+
type.store(@method, @method.local(scoped_local_name(name, scope), type))
|
493
446
|
end
|
494
447
|
|
495
448
|
def declared_locals
|
@@ -498,24 +451,81 @@ module Duby
|
|
498
451
|
|
499
452
|
def annotate(builder, annotations)
|
500
453
|
annotations.each do |annotation|
|
501
|
-
|
502
|
-
|
454
|
+
type = annotation.type
|
455
|
+
type = type.jvm_type if type.respond_to?(:jvm_type)
|
456
|
+
builder.annotate(type, annotation.runtime?) do |visitor|
|
457
|
+
annotation.values.each do |name, value|
|
458
|
+
annotation_value(visitor, name, value)
|
459
|
+
end
|
503
460
|
end
|
504
461
|
end
|
505
462
|
end
|
506
463
|
|
507
|
-
def
|
464
|
+
def annotation_value(builder, name, value)
|
465
|
+
case value
|
466
|
+
when Duby::AST::Annotation
|
467
|
+
type = value.type
|
468
|
+
type = type.jvm_type if type.respond_to?(:jvm_type)
|
469
|
+
builder.annotation(name, type) do |child|
|
470
|
+
value.values.each do |name, value|
|
471
|
+
annotation_value(child, name, value)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
when ::Array
|
475
|
+
builder.array(name) do |array|
|
476
|
+
value.each do |item|
|
477
|
+
annotation_value(array, nil, item)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
else
|
481
|
+
builder.value(name, value)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
def declare_local(scope, name, type)
|
508
486
|
# TODO confirm types are compatible
|
487
|
+
name = scoped_local_name(name, scope)
|
509
488
|
unless declared_locals[name]
|
510
489
|
declared_locals[name] = type
|
511
490
|
index = @method.local(name, type)
|
512
491
|
end
|
513
492
|
end
|
514
493
|
|
515
|
-
def local_declare(name, type)
|
516
|
-
declare_local(name, type)
|
494
|
+
def local_declare(scope, name, type)
|
495
|
+
declare_local(scope, name, type)
|
517
496
|
type.init_value(@method)
|
518
|
-
type.store(@method, @method.local(name, type))
|
497
|
+
type.store(@method, @method.local(scoped_local_name(name, scope), type))
|
498
|
+
end
|
499
|
+
|
500
|
+
def get_binding(type)
|
501
|
+
@bindings[type]
|
502
|
+
end
|
503
|
+
|
504
|
+
def declared_captures(binding=nil)
|
505
|
+
@captured_locals[binding || @binding]
|
506
|
+
end
|
507
|
+
|
508
|
+
def captured_local_declare(scope, name, type)
|
509
|
+
unless declared_captures[name]
|
510
|
+
declared_captures[name] = type
|
511
|
+
# default should be fine, but I don't think bitescript supports it.
|
512
|
+
@binding.protected_field(name, type)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
def captured_local(scope, name, type)
|
517
|
+
captured_local_declare(scope, name, type)
|
518
|
+
binding_reference
|
519
|
+
@method.getfield(scope.binding_type, name, type)
|
520
|
+
end
|
521
|
+
|
522
|
+
def captured_local_assign(node, expression)
|
523
|
+
scope, name, type = node.containing_scope, node.name, node.inferred_type
|
524
|
+
captured_local_declare(scope, name, type)
|
525
|
+
binding_reference
|
526
|
+
node.value.compile(self, true)
|
527
|
+
@method.dup_x2 if expression
|
528
|
+
@method.putfield(scope.binding_type, name, type)
|
519
529
|
end
|
520
530
|
|
521
531
|
def field(name, type, annotations)
|
@@ -527,7 +537,7 @@ module Duby
|
|
527
537
|
|
528
538
|
# load self object unless static
|
529
539
|
method.aload 0 unless static
|
530
|
-
|
540
|
+
|
531
541
|
if static
|
532
542
|
@method.getstatic(@class, name, type)
|
533
543
|
else
|
@@ -562,7 +572,7 @@ module Duby
|
|
562
572
|
name = name[1..-1]
|
563
573
|
|
564
574
|
real_type = declared_fields[name] || type
|
565
|
-
|
575
|
+
|
566
576
|
declare_field(name, real_type, annotations)
|
567
577
|
|
568
578
|
method.aload 0 unless static
|
@@ -580,15 +590,59 @@ module Duby
|
|
580
590
|
@method.putfield(@class, name, real_type)
|
581
591
|
end
|
582
592
|
end
|
583
|
-
|
593
|
+
|
584
594
|
def string(value)
|
585
595
|
@method.ldc(value)
|
586
596
|
end
|
587
597
|
|
598
|
+
def build_string(nodes, expression)
|
599
|
+
if expression
|
600
|
+
# could probably be more efficient with non-default constructor
|
601
|
+
builder_class = Duby::AST.type('java.lang.StringBuilder')
|
602
|
+
@method.new builder_class
|
603
|
+
@method.dup
|
604
|
+
@method.invokespecial builder_class, "<init>", [@method.void]
|
605
|
+
|
606
|
+
nodes.each do |node|
|
607
|
+
node.compile(self, true)
|
608
|
+
method = find_method(builder_class, "append", [node.inferred_type], false)
|
609
|
+
if method
|
610
|
+
@method.invokevirtual builder_class, "append", [method.return_type, *method.argument_types]
|
611
|
+
else
|
612
|
+
log "Could not find a match for #{java::lang::StringBuilder}.append(#{node.inferred_type})"
|
613
|
+
fail "Could not compile"
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
# convert to string
|
618
|
+
@method.invokevirtual java::lang::StringBuilder.java_class, "toString", [@method.string]
|
619
|
+
else
|
620
|
+
nodes.each do |node|
|
621
|
+
node.compile(self, false)
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
def to_string(body, expression)
|
627
|
+
if expression
|
628
|
+
body.compile(self, true)
|
629
|
+
body.inferred_type.box(@method) if body.inferred_type.primitive?
|
630
|
+
@method.invokevirtual @method.object, "toString", [@method.string]
|
631
|
+
else
|
632
|
+
body.compile(self, false)
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
588
636
|
def boolean(value)
|
589
637
|
value ? @method.iconst_1 : @method.iconst_0
|
590
638
|
end
|
591
639
|
|
640
|
+
def regexp(value, flags = 0)
|
641
|
+
# TODO: translate flags to Java-appropriate values
|
642
|
+
@method.ldc(value)
|
643
|
+
@method.invokestatic java::util::regex::Pattern, "compile", [java::util::regex::Pattern, @method.string]
|
644
|
+
end
|
645
|
+
|
592
646
|
def array(node, expression)
|
593
647
|
if expression
|
594
648
|
# create basic arraylist
|
@@ -599,9 +653,13 @@ module Duby
|
|
599
653
|
|
600
654
|
# elements, as expressions
|
601
655
|
# TODO: ensure they're all reference types!
|
602
|
-
node.children.each do |
|
656
|
+
node.children.each do |n|
|
603
657
|
@method.dup
|
604
|
-
|
658
|
+
n.compile(self, true)
|
659
|
+
# TODO this feels like it should be in the node.compile itself
|
660
|
+
if n.inferred_type.primitive?
|
661
|
+
n.inferred_type.box(@method)
|
662
|
+
end
|
605
663
|
@method.invokeinterface java::util::List, "add", [@method.boolean, @method.object]
|
606
664
|
@method.pop
|
607
665
|
end
|
@@ -611,43 +669,31 @@ module Duby
|
|
611
669
|
else
|
612
670
|
# elements, as non-expressions
|
613
671
|
# TODO: ensure they're all reference types!
|
614
|
-
node.children.each do |
|
615
|
-
|
672
|
+
node.children.each do |n|
|
673
|
+
n.compile(self, true)
|
674
|
+
# TODO this feels like it should be in the node.compile itself
|
675
|
+
if n.inferred_type.primitive?
|
676
|
+
n.inferred_type.box(@method)
|
677
|
+
end
|
616
678
|
end
|
617
679
|
end
|
618
680
|
end
|
619
|
-
|
681
|
+
|
620
682
|
def null
|
621
683
|
@method.aconst_null
|
622
684
|
end
|
623
|
-
|
685
|
+
|
686
|
+
def binding_reference
|
687
|
+
@method.aload(@method.local('$binding'))
|
688
|
+
end
|
689
|
+
|
624
690
|
def compile_self
|
625
691
|
method.aload(0)
|
626
692
|
end
|
627
|
-
|
628
|
-
def newline
|
629
|
-
# TODO: line numbering
|
630
|
-
end
|
631
|
-
|
693
|
+
|
632
694
|
def line(num)
|
633
695
|
@method.line(num) if @method
|
634
696
|
end
|
635
|
-
|
636
|
-
def generate
|
637
|
-
log "Generating classes..."
|
638
|
-
@file.generate do |filename, builder|
|
639
|
-
log " #{builder.class_name}"
|
640
|
-
if block_given?
|
641
|
-
yield filename, builder
|
642
|
-
else
|
643
|
-
File.open(filename, 'w') {|f| f.write(builder.generate)}
|
644
|
-
end
|
645
|
-
end
|
646
|
-
log "...done!"
|
647
|
-
end
|
648
|
-
|
649
|
-
def import(short, long)
|
650
|
-
end
|
651
697
|
|
652
698
|
def print(print_node)
|
653
699
|
@method.getstatic System, "out", PrintStream
|
@@ -676,7 +722,7 @@ module Duby
|
|
676
722
|
exception.compile(self, true)
|
677
723
|
@method.athrow
|
678
724
|
end
|
679
|
-
|
725
|
+
|
680
726
|
def rescue(rescue_node, expression)
|
681
727
|
start = @method.label.set!
|
682
728
|
body_end = @method.label
|
@@ -729,21 +775,49 @@ module Duby
|
|
729
775
|
size.compile(self, true)
|
730
776
|
type.newarray(@method)
|
731
777
|
end
|
732
|
-
|
733
|
-
def
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
778
|
+
|
779
|
+
def bootstrap_dynamic
|
780
|
+
# hacky, I know
|
781
|
+
unless defined? @class.bootstrapped
|
782
|
+
def @class.bootstrapped; true; end
|
783
|
+
method = @class.public_static_method("<clinit>", [], Java::void)
|
784
|
+
method.start
|
785
|
+
method.ldc org.jruby.duby.DynalangBootstrap
|
786
|
+
method.ldc "bootstrap"
|
787
|
+
method.invokestatic java.dyn.Linkage, "registerBootstrapMethod", [method.void, java.lang.Class, method.string]
|
788
|
+
method.returnvoid
|
789
|
+
method.stop
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
class ClosureCompiler < Duby::Compiler::JVM
|
794
|
+
def initialize(file, type, parent)
|
795
|
+
@file = file
|
796
|
+
@type = type
|
797
|
+
@jump_scope = []
|
798
|
+
@parent = parent
|
799
|
+
end
|
800
|
+
|
801
|
+
def prepare_binding(scope)
|
802
|
+
if scope.has_binding?
|
803
|
+
type = scope.binding_type
|
804
|
+
@binding = @parent.get_binding(type)
|
805
|
+
@method.aload 0
|
806
|
+
@method.getfield(@class, 'binding', @binding)
|
807
|
+
type.store(@method, @method.local('$binding', type))
|
740
808
|
end
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
809
|
+
begin
|
810
|
+
yield
|
811
|
+
ensure
|
812
|
+
if scope.has_binding?
|
813
|
+
@binding = nil
|
814
|
+
end
|
745
815
|
end
|
746
816
|
end
|
817
|
+
|
818
|
+
def declared_captures
|
819
|
+
@parent.declared_captures(@binding)
|
820
|
+
end
|
747
821
|
end
|
748
822
|
end
|
749
823
|
end
|
@@ -754,13 +828,13 @@ if __FILE__ == $0
|
|
754
828
|
Duby::AST.verbose = true
|
755
829
|
Duby::Compiler::JVM.verbose = true
|
756
830
|
ast = Duby::AST.parse(File.read(ARGV[0]))
|
757
|
-
|
831
|
+
|
758
832
|
typer = Duby::Typer::Simple.new(:script)
|
759
833
|
ast.infer(typer)
|
760
834
|
typer.resolve(true)
|
761
|
-
|
835
|
+
|
762
836
|
compiler = Duby::Compiler::JVM.new(ARGV[0])
|
763
837
|
compiler.compile(ast)
|
764
|
-
|
838
|
+
|
765
839
|
compiler.generate
|
766
840
|
end
|