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.
Files changed (72) hide show
  1. data/History.txt +7 -0
  2. data/README.txt +18 -7
  3. data/Rakefile +72 -0
  4. data/examples/ant/example-build.xml +7 -0
  5. data/examples/appengine/Rakefile +8 -67
  6. data/examples/appengine/Readme +4 -3
  7. data/examples/appengine/lib/duby/appengine_tasks.rb +173 -0
  8. data/examples/appengine/lib/duby/plugin/datastore.rb +92 -31
  9. data/examples/appengine/lib/duby_task.rb +61 -0
  10. data/examples/appengine/src/com/ribrdb/DubyApp.duby +32 -6
  11. data/examples/appengine/src/com/ribrdb/list.dhtml +2 -2
  12. data/examples/appengine/{config.ru → src/config.ru} +0 -0
  13. data/examples/bintrees.duby +66 -0
  14. data/examples/dynamic.duby +17 -0
  15. data/examples/fib.duby +3 -11
  16. data/examples/fields.duby +3 -3
  17. data/examples/fractal.duby +1 -3
  18. data/examples/sort_closure.duby +7 -0
  19. data/examples/swing.duby +11 -11
  20. data/javalib/duby-bootstrap.jar +0 -0
  21. data/javalib/dynalang-invoke-0.1.jar +0 -0
  22. data/lib/duby.rb +168 -35
  23. data/lib/duby/ast.rb +224 -27
  24. data/lib/duby/ast/call.rb +85 -25
  25. data/lib/duby/ast/class.rb +112 -28
  26. data/lib/duby/ast/flow.rb +65 -44
  27. data/lib/duby/ast/intrinsics.rb +223 -21
  28. data/lib/duby/ast/literal.rb +67 -16
  29. data/lib/duby/ast/local.rb +36 -40
  30. data/lib/duby/ast/method.rb +83 -67
  31. data/lib/duby/ast/structure.rb +105 -23
  32. data/lib/duby/compiler.rb +83 -28
  33. data/lib/duby/env.rb +33 -0
  34. data/lib/duby/jvm/base.rb +210 -0
  35. data/lib/duby/jvm/compiler.rb +293 -219
  36. data/lib/duby/jvm/method_lookup.rb +77 -67
  37. data/lib/duby/jvm/source_compiler.rb +250 -157
  38. data/lib/duby/jvm/source_generator/builder.rb +53 -49
  39. data/lib/duby/jvm/source_generator/loops.rb +9 -9
  40. data/lib/duby/jvm/source_generator/precompile.rb +35 -25
  41. data/lib/duby/jvm/typer.rb +19 -10
  42. data/lib/duby/jvm/types.rb +127 -68
  43. data/lib/duby/jvm/types/basic_types.rb +26 -13
  44. data/lib/duby/jvm/types/enumerable.rb +6 -4
  45. data/lib/duby/jvm/types/factory.rb +49 -13
  46. data/lib/duby/jvm/types/floats.rb +16 -0
  47. data/lib/duby/jvm/types/integers.rb +63 -2
  48. data/lib/duby/jvm/types/intrinsics.rb +43 -21
  49. data/lib/duby/jvm/types/methods.rb +326 -86
  50. data/lib/duby/jvm/types/number.rb +3 -0
  51. data/lib/duby/nbcompiler.rb +1 -1
  52. data/lib/duby/plugin/edb.rb +1 -1
  53. data/lib/duby/plugin/java.rb +10 -1
  54. data/lib/duby/transform.rb +134 -46
  55. data/lib/duby/typer.rb +75 -50
  56. data/test/test_ast.rb +106 -106
  57. data/test/test_compilation.rb +46 -32
  58. data/test/test_env.rb +42 -0
  59. data/test/test_java_typer.rb +35 -51
  60. data/test/test_javac_compiler.rb +4 -1
  61. data/test/test_jvm_compiler.rb +564 -133
  62. data/test/test_typer.rb +68 -92
  63. metadata +37 -21
  64. data/examples/README +0 -16
  65. data/lib/duby/c/compiler.rb +0 -134
  66. data/lib/duby/old/compiler_old.rb +0 -845
  67. data/lib/duby/old/declaration.rb +0 -72
  68. data/lib/duby/old/mapper.rb +0 -72
  69. data/lib/duby/old/signature.rb +0 -52
  70. data/lib/duby/old/typer_old.rb +0 -163
  71. data/lib/duby/plugin/math.rb +0 -84
  72. data/test/test_math_plugin.rb +0 -87
@@ -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
- @filename = File.basename(filename)
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 compile(ast, expression = false)
66
- ast.compile(self, expression)
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 define_main(body)
96
- if body.class != AST::ClassDefinition
97
- @class = @type.define(@file)
98
- with :method => @class.main do
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
- body.compile(self, false)
94
+ def finish_main
95
+ @method.returnvoid
96
+ end
107
97
 
108
- @method.returnvoid
109
- @method.stop
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
- name, signature, args = node.name, node.signature, node.arguments.args
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
- method_body(method, args, node.body, signature[:return])
143
-
144
- arg_types_for_opt = []
145
- args_for_opt = []
146
- if args
147
- args.each do |arg|
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
- signature[:return].return(@method)
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
- @method.stop
178
- end
179
- end
180
- arg_types_for_opt << arg.inferred_type
181
- args_for_opt << arg
182
- end
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
- log "Method #{name}(#{arg_types}) complete!" end
146
+ return_type.return(@method)
187
147
  end
188
-
148
+
189
149
  def constructor(node)
190
150
  push_jump_scope(node) do
191
- args = node.arguments.args || []
192
- arg_types = args.map { |arg| arg.inferred_type }
193
- exceptions = node.signature[:throws]
194
- method = @class.public_constructor(exceptions, *arg_types)
195
- annotate(method, node.annotations)
196
- method_body(method, args, node.body, Types::Void) do
197
- method.aload 0
198
- if node.delegate_args
199
- if node.calls_super
200
- delegate_class = @type.superclass
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
- delegate_class = @type
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, body, return_type)
220
- with :method => method do
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
- expression = return_type != Types::Void
232
- body.compile(self, expression) if body
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 define_class(class_def, expression)
241
- with(:type => class_def.inferred_type,
242
- :class => class_def.inferred_type.define(@file),
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.children[last].compile(self, expression)
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
- builder.annotate(annotation.type.jvm_type) do |visitor|
502
- # todo values
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 declare_local(name, type)
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 |node|
656
+ node.children.each do |n|
603
657
  @method.dup
604
- node.compile(self, true)
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 |node|
615
- node.compile(self, false)
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 with(vars)
734
- orig_values = {}
735
- begin
736
- vars.each do |name, new_value|
737
- name = "@#{name}"
738
- orig_values[name] = instance_variable_get name
739
- instance_variable_set name, new_value
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
- yield
742
- ensure
743
- orig_values.each do |name, value|
744
- instance_variable_set name, value
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