duby 0.0.2-java → 0.0.3-java

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