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
@@ -3,19 +3,8 @@ module Duby
3
3
  module MethodLookup
4
4
  # dummy log; it's expected the inclusion target will have it
5
5
  def log(msg); end
6
-
7
- # def jvm_type(type)
8
- # return type if type.kind_of? Java::JavaClass
9
- # return type.jvm_type
10
- # end
11
- #
12
- # def convert_params(params)
13
- # params.map {|param| jvm_type(param)}
14
- # end
15
6
 
16
7
  def find_method(mapped_type, name, mapped_params, meta)
17
- # mapped_type = jvm_type(mapped_type)
18
- # mapped_params = convert_params(mapped_params)
19
8
  raise ArgumentError if mapped_params.any? {|p| p.nil?}
20
9
  if name == 'new'
21
10
  if meta
@@ -34,64 +23,66 @@ module Duby
34
23
  end
35
24
  rescue NameError
36
25
  # exact args failed, do a deeper search
37
- log "No exact match for #{mapped_type.name}.#{name}(#{mapped_params.map(&:name)})"
26
+ log "No exact match for #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})"
38
27
 
39
28
  method = find_jls(mapped_type, name, mapped_params, meta, constructor)
40
-
29
+
41
30
  unless method
42
- log "Failed to locate method #{mapped_type.name}.#{name}(#{mapped_params.map(&:name)})"
31
+ log "Failed to locate method #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})"
43
32
  return nil
44
33
  end
45
34
  end
46
35
 
47
- log "Found method #{method.declaring_class.name}.#{name}(#{method.argument_types.map(&:name)}) from #{mapped_type.name}"
36
+ log "Found method #{method.declaring_class.name}.#{name}(#{method.argument_types.map(&:name).join ', '}) from #{mapped_type.name}"
48
37
  return method
49
38
  end
50
-
39
+
51
40
  def find_jls(mapped_type, name, mapped_params, meta, constructor)
52
- # mapped_type = jvm_type(mapped_type)
53
- # mapped_params = convert_params(mapped_params)
54
41
  if constructor
55
- all_methods = mapped_type.unmeta.declared_constructors
56
- by_name = all_methods
42
+ by_name = mapped_type.unmeta.declared_constructors
57
43
  elsif meta
58
- all_methods = mapped_type.declared_class_methods
44
+ by_name = mapped_type.declared_class_methods(name)
59
45
  else
60
- all_methods = []
46
+ by_name = []
61
47
  cls = mapped_type
62
48
  while cls
63
- all_methods += cls.declared_instance_methods
49
+ by_name += cls.declared_instance_methods(name)
64
50
  cls = cls.superclass
65
51
  end
66
52
  end
67
- # filter by name, if we haven't already got a by_name list
68
- by_name ||= all_methods.select {|m| m.name == name && mapped_params.size <= m.argument_types.size}
69
53
  # filter by arity
70
54
  by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size}
71
55
 
72
56
  phase1_methods = phase1(mapped_params, by_name_and_arity)
73
57
 
74
58
  if phase1_methods.size > 1
75
- raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{phase1_methods}"
59
+ method_list = phase1_methods.map do |m|
60
+
61
+ "#{m.name}(#{m.parameter_types.map(&:name).join(', ')})"
62
+ end.join("\n")
63
+ raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{method_list}"
76
64
  end
77
65
 
78
66
  phase1_methods[0] ||
79
67
  phase2(mapped_params, by_name) ||
80
- phase3(mapped_params, by_name)
68
+ phase3(mapped_params, by_name) ||
69
+ field_lookup(mapped_params, mapped_type, meta, name) ||
70
+ inner_class(mapped_params, mapped_type, meta, name)
81
71
  end
82
-
72
+
83
73
  def phase1(mapped_params, potentials)
84
74
  log "Beginning JLS phase 1 search with params (#{mapped_params.map(&:name)})"
85
-
75
+
86
76
  # cycle through methods looking for more specific matches; gather matches of equal specificity
87
77
  methods = potentials.inject([]) do |currents, potential|
88
78
  method_params = potential.argument_types
89
-
79
+ raise "Bad arguments for method #{potential.declaring_class}.#{potential.name}" unless method_params.all?
80
+
90
81
  # exact match always wins; duplicates not possible
91
82
  if each_is_exact(mapped_params, method_params)
92
83
  return [potential]
93
84
  end
94
-
85
+
95
86
  # otherwise, check for potential match and compare to current
96
87
  # TODO: missing ambiguity check; picks last method of equal specificity
97
88
  if each_is_exact_or_subtype_or_convertible(mapped_params, method_params)
@@ -111,42 +102,85 @@ module Duby
111
102
  currents = [potential]
112
103
  end
113
104
  end
114
-
105
+
115
106
  currents
116
107
  end
117
108
 
118
109
  methods
119
110
  end
120
-
111
+
121
112
  def is_more_specific?(potential, current)
122
113
  each_is_exact_or_subtype_or_convertible(potential, current)
123
114
  end
124
-
115
+
125
116
  def phase2(mapped_params, potentials)
126
117
  nil
127
118
  end
128
-
119
+
129
120
  def phase3(mapped_params, potentials)
130
121
  nil
131
122
  end
132
-
123
+
124
+ def field_lookup(mapped_params, mapped_type, meta, name)
125
+ log("Attempting #{meta ? 'static' : 'instance'} field lookup for '#{name}' on class #{mapped_type}")
126
+ # if we get to this point, the potentials do not match, so we ignore them
127
+
128
+
129
+ # search for a field of the given name
130
+ if name =~ /_set$/
131
+ # setter
132
+ setter = true
133
+ name = name[0..-5]
134
+ field = mapped_type.field_setter(name)
135
+ else
136
+ # getter
137
+ setter = false
138
+
139
+ # field accesses don't take arguments
140
+ return if mapped_params.size > 0
141
+ field = mapped_type.field_getter(name)
142
+ end
143
+
144
+ return nil unless field
145
+
146
+ if (meta && !field.static?) ||
147
+ (!meta && field.static?)
148
+ field == nil
149
+ end
150
+
151
+ # check accessibility
152
+ # TODO: protected field access check appropriate to current type
153
+ if setter
154
+ raise "cannot set final field '#{name}' on class #{mapped_type}" if field.final?
155
+ end
156
+ raise "cannot access field '#{name}' on class #{mapped_type}" unless field.public?
157
+
158
+ field
159
+ end
160
+
161
+ def inner_class(params, type, meta, name)
162
+ return unless params.size == 0 && meta
163
+ log("Attempting inner class lookup for '#{name}' on #{type}")
164
+ type.inner_class_getter(name)
165
+ end
166
+
133
167
  def each_is_exact(incoming, target)
134
168
  incoming.each_with_index do |in_type, i|
135
169
  target_type = target[i]
136
-
170
+
137
171
  # exact match
138
172
  return false unless target_type == in_type
139
173
  end
140
174
  return true
141
175
  end
142
-
176
+
143
177
  def each_is_exact_or_subtype_or_convertible(incoming, target)
144
178
  incoming.each_with_index do |in_type, i|
145
179
  target_type = target[i]
146
-
180
+
147
181
  # exact match
148
182
  next if target_type == in_type
149
-
183
+
150
184
  # primitive is safely convertible
151
185
  if target_type.primitive?
152
186
  if in_type.primitive?
@@ -154,39 +188,15 @@ module Duby
154
188
  end
155
189
  return false
156
190
  end
157
-
191
+
158
192
  # object type is assignable
159
193
  return false unless target_type.assignable_from? in_type
160
194
  end
161
195
  return true
162
196
  end
163
-
164
- BOOLEAN = Java::boolean.java_class
165
- BYTE = Java::byte.java_class
166
- SHORT = Java::short.java_class
167
- CHAR = Java::char.java_class
168
- INT = Java::int.java_class
169
- LONG = Java::long.java_class
170
- FLOAT = Java::float.java_class
171
- DOUBLE = Java::double.java_class
172
-
173
- PrimitiveConversions = {
174
- BOOLEAN => [BOOLEAN],
175
- BYTE => [BYTE, SHORT, CHAR, INT, LONG, FLOAT, DOUBLE],
176
- SHORT => [SHORT, INT, LONG, FLOAT, DOUBLE],
177
- CHAR => [CHAR, INT, LONG, FLOAT, DOUBLE],
178
- INT => [INT, LONG, FLOAT, DOUBLE],
179
- LONG => [LONG, DOUBLE],
180
- FLOAT => [FLOAT, DOUBLE],
181
- DOUBLE => [DOUBLE]
182
- }
183
-
197
+
184
198
  def primitive_convertible?(in_type, target_type)
185
- if PrimitiveConversions.include? in_type
186
- PrimitiveConversions[in_type].include?(target_type)
187
- else
188
- in_type.convertible_to?(target_type)
189
- end
199
+ in_type.convertible_to?(target_type)
190
200
  end
191
201
  end
192
202
  end
@@ -14,10 +14,9 @@ end
14
14
 
15
15
  module Duby
16
16
  module Compiler
17
- class JavaSource
17
+ class JavaSource < JVMCompilerBase
18
18
  JVMTypes = Duby::JVM::Types
19
- include Duby::Compiler::JVM::JVMLogger
20
- attr_accessor :filename, :method, :static, :class, :lvalue
19
+ attr_accessor :lvalue
21
20
 
22
21
  Operators = [
23
22
  '+', '-', '+@', '-@', '/', '%', '*', '<',
@@ -27,114 +26,104 @@ module Duby
27
26
  ArrayOps = [
28
27
  '[]', '[]=', 'length'
29
28
  ]
30
-
29
+
31
30
  ImplicitReturn = Struct.new(:value)
32
31
 
33
32
  def initialize(filename)
34
- @filename = File.basename(filename)
35
- @static = true
36
- parts = filename.split '/'
37
- classname = parts.pop.sub /[.].+/, ''
38
- package = parts.join('.') unless parts.empty?
39
-
33
+ super
40
34
  @file = Duby::JavaSource::Builder.new(filename, self)
41
- #@file.package = package
42
- @type = AST::type(classname)
43
- end
44
-
45
- def toplevel_class
46
- @class = @type.define(@file)
47
35
  end
48
36
 
49
- def generate(&block)
50
- log "Generating source files..."
51
- @file.generate do |filename, builder|
52
- log " #{builder.class_name}"
53
- if block_given?
54
- yield filename, builder
55
- else
56
- File.open(filename, 'w') {|f| f.write(builder.generate)}
57
- end
58
- end
59
- log "...done!"
37
+ def output_type
38
+ "source files"
60
39
  end
61
40
 
62
- def define_main(body)
63
- if body.class != AST::ClassDefinition
64
- @class = @type.define(@file)
65
- with :method => @class.main do
66
- log "Starting main method"
67
-
41
+ def define_method(node)
42
+ super(node, false) do |method, _|
43
+ with :method => method do
44
+ log "Starting new method #{node.name}"
68
45
  @method.start
69
46
 
70
- body.compile(self, false)
47
+ prepare_binding(node) do
48
+ unless @method.type.nil? || @method.type.void?
49
+ self.return(ImplicitReturn.new(node.body))
50
+ else
51
+ node.body.compile(self, false) if node.body
52
+ end
53
+ end
71
54
 
55
+ log "Method #{node.name} complete!"
72
56
  @method.stop
73
57
  end
74
- @class.stop
75
- else
76
- body.compile(self, false)
77
58
  end
59
+ end
78
60
 
79
- log "Main method complete!"
61
+ def annotate(node, annotations)
62
+ node.annotate(annotations)
80
63
  end
81
64
 
82
- def define_method(node)
83
- name, signature, args = node.name, node.signature, node.arguments.args
84
- args ||= []
85
- return_type = signature[:return]
86
- exceptions = signature[:throws] || []
87
- with :static => @static || node.static? do
88
- if @static
89
- method = @class.public_static_method(name.to_s, return_type, exceptions, *args)
90
- else
91
- method = @class.public_method(name.to_s, return_type, exceptions, *args)
92
- end
65
+ def define_optarg_chain(name, arg, return_type,
66
+ args_for_opt, arg_types_for_opt)
67
+ # declare all args so they get their values
68
+ @method.print "return " unless @method.type.nil? || @method.type.void?
69
+ @method.print "this." unless @static
70
+ @method.print "#{name}("
71
+ @method.print args_for_opt.map(&:name).join(', ')
72
+ @method.print ', 'if args_for_opt.size > 0
73
+ arg.children[0].value.compile(self, true)
93
74
 
75
+ # invoke the next one in the chain
76
+ @method.print ");\n"
77
+ end
78
+
79
+ def constructor(node)
80
+ super(node, false) do |method, _|
94
81
  with :method => method do
95
- log "Starting new method #{name}"
96
- @method.annotate(node.annotations)
97
82
  @method.start
83
+ if node.delegate_args
84
+ delegate = if node.calls_super
85
+ "super"
86
+ else
87
+ "this"
88
+ end
89
+ method.print "#{delegate}("
90
+ node.delegate_args.each_with_index do |arg, index|
91
+ method.print ', ' unless index == 0
92
+ raise "Invalid constructor argument #{arg}" unless arg.expr?(self)
93
+ arg.compile(self, true)
94
+ end
95
+ method.puts ");"
96
+ end
98
97
 
99
- unless @method.type.nil? || @method.type.void?
100
- self.return(ImplicitReturn.new(node.body))
101
- else
98
+ prepare_binding(node) do
102
99
  node.body.compile(self, false) if node.body
103
100
  end
104
-
105
- log "Method #{name} complete!"
106
- @method.stop
101
+ method.stop
107
102
  end
108
103
  end
109
104
  end
110
105
 
111
- def constructor(node)
112
- args = node.arguments.args || []
113
- exceptions = node.signature[:throws] || []
114
- method = @class.public_constructor(exceptions, *args)
115
- with :method => method do
116
- @method.annotate(node.annotations)
117
- @method.start
118
- if node.delegate_args
119
- delegate = if node.calls_super
120
- "super"
121
- else
122
- "this"
123
- end
124
- method.print "#{delegate}("
125
- node.delegate_args.each_with_index do |arg, index|
126
- method.print ', ' unless index == 0
127
- raise "Invalid constructor argument #{arg}" unless arg.expr?(self)
128
- arg.compile(self, true)
129
- end
130
- method.puts ");"
106
+ def prepare_binding(scope)
107
+ if scope.has_binding?
108
+ type = scope.binding_type
109
+ @binding = @bindings[type]
110
+ @method.puts "#{type.name} $binding = new #{type.name}();"
111
+ end
112
+ begin
113
+ yield
114
+ ensure
115
+ if scope.has_binding?
116
+ @binding.stop
117
+ @binding = nil
131
118
  end
132
-
133
- node.body.compile(self, false) if node.body
134
- method.stop
135
119
  end
136
120
  end
137
121
 
122
+ def define_closure(class_def, expression)
123
+ compiler = ClosureCompiler.new(@file, @type, self)
124
+ compiler.define_class(class_def, expression)
125
+ end
126
+
138
127
  def return(node)
139
128
  if @method.type.nil? || @method.type.void?
140
129
  @method.puts 'return;'
@@ -158,7 +147,7 @@ module Duby
158
147
  store_value('throw ', node)
159
148
  end
160
149
  end
161
-
150
+
162
151
  def rescue(node, expression)
163
152
  @method.block 'try' do
164
153
  maybe_store(node.body, expression)
@@ -172,7 +161,7 @@ module Duby
172
161
  end
173
162
  end
174
163
  end
175
-
164
+
176
165
  def ensure(node, expression)
177
166
  @method.block 'try' do
178
167
  maybe_store(node.body, expression)
@@ -184,19 +173,20 @@ module Duby
184
173
 
185
174
  def line(num)
186
175
  end
187
-
176
+
188
177
  def declare_local(name, type)
189
178
  @method.declare_local(type, name)
190
179
  end
191
-
180
+
192
181
  def declare_field(name, type, annotations)
193
- @class.declare_field(name, type, @static, annotations)
182
+ @class.declare_field(name, type, @static, 'private', annotations)
194
183
  end
195
184
 
196
- def local(name, type)
185
+ def local(scope, name, type)
186
+ name = scoped_local_name(name, scope)
197
187
  @method.print name
198
188
  end
199
-
189
+
200
190
  def field(name, type, annotations)
201
191
  name = name[1..-1]
202
192
  declare_field(name, type, annotations)
@@ -207,13 +197,25 @@ module Duby
207
197
  @static ? @class.class_name : 'this'
208
198
  end
209
199
 
210
- def local_assign(name, type, expression, value)
200
+ def local_assign(scope, name, type, expression, value)
201
+ simple = value.expr?(self)
211
202
  value = value.precompile(self)
203
+ name = scoped_local_name(name, scope)
212
204
  if method.local?(name)
213
- @method.print @lvalue if expression
205
+ if expression
206
+ if simple
207
+ @method.print '('
208
+ else
209
+ @method.print @lvalue
210
+ end
211
+ end
214
212
  @method.print "#{name} = "
215
213
  value.compile(self, true)
216
- @method.puts ';'
214
+ if simple && expression
215
+ @method.print ')'
216
+ else
217
+ @method.puts ';'
218
+ end
217
219
  else
218
220
  @method.declare_local(type, name) do
219
221
  value.compile(self, true)
@@ -228,18 +230,38 @@ module Duby
228
230
  name = name[1..-1]
229
231
  declare_field(name, type, annotations)
230
232
  end
231
-
232
- def local_declare(name, type)
233
+
234
+ def local_declare(scope, name, type)
235
+ name = scoped_local_name(name, scope)
233
236
  declare_local(name, type)
234
237
  end
235
-
238
+
236
239
  def field_assign(name, type, expression, value, annotations)
237
240
  name = name[1..-1]
238
241
  declare_field(name, type, annotations)
239
242
  lvalue = "#{@lvalue if expression}#{this}.#{name} = "
240
243
  store_value(lvalue, value)
241
244
  end
242
-
245
+
246
+ def captured_local_declare(scope, name, type)
247
+ unless declared_captures[name]
248
+ declared_captures[name] = type
249
+ @binding.declare_field(name, type, false, '')
250
+ end
251
+ end
252
+
253
+ def captured_local(scope, name, type)
254
+ captured_local_declare(scope, name, type)
255
+ @method.print "$binding.#{name}"
256
+ end
257
+
258
+ def captured_local_assign(node, expression)
259
+ scope, name, type = node.containing_scope, node.name, node.inferred_type
260
+ captured_local_declare(scope, name, type)
261
+ lvalue = "#{@lvalue if expression}$binding.#{name} = "
262
+ store_value(lvalue, node.value)
263
+ end
264
+
243
265
  def store_value(lvalue, value)
244
266
  if value.is_a? String
245
267
  @method.puts "#{lvalue}#{value};"
@@ -253,7 +275,7 @@ module Duby
253
275
  end
254
276
  end
255
277
  end
256
-
278
+
257
279
  def assign(name, value)
258
280
  store_value("#{name} = ", value)
259
281
  name
@@ -268,16 +290,17 @@ module Duby
268
290
  end
269
291
 
270
292
  def body(body, expression)
271
- # all except the last element in a body of code is treated as a statement
272
- i, last = 0, body.children.size - 1
273
- while i < last
274
- body.children[i].compile(self, false)
275
- i += 1
293
+ super(body, expression) do |last|
294
+ maybe_store(last, expression)
276
295
  end
277
- # last element is an expression only if the body is an expression
278
- maybe_store(body.children[last], expression)
279
296
  end
280
-
297
+
298
+ def scoped_body(scope, expression)
299
+ @method.block do
300
+ super
301
+ end
302
+ end
303
+
281
304
  def branch_expression(node)
282
305
  node.condition.compile(self, true)
283
306
  @method.print ' ? ('
@@ -294,7 +317,7 @@ module Duby
294
317
  end
295
318
  @method.print ')'
296
319
  end
297
-
320
+
298
321
  def branch(node, expression)
299
322
  if expression && node.expr?(self)
300
323
  return branch_expression(node)
@@ -319,7 +342,7 @@ module Duby
319
342
  end
320
343
  end
321
344
  end
322
-
345
+
323
346
  def loop(loop, expression)
324
347
  if loop.redo? || loop.post || !loop.condition.predicate.expr?(self)
325
348
  loop = ComplexWhileLoop.new(loop, self)
@@ -330,7 +353,7 @@ module Duby
330
353
  loop.compile(expression)
331
354
  end
332
355
  end
333
-
356
+
334
357
  def expr?(target, params)
335
358
  !([target] + params).any? {|x| x.kind_of? Duby::AST::TempValue}
336
359
  end
@@ -358,12 +381,24 @@ module Duby
358
381
  end
359
382
  end
360
383
 
361
- def compile_args(call)
362
- call.parameters.map do |param|
363
- param.precompile(self)
384
+ def precompile_nodes(nodes)
385
+ if nodes.all? {|n| n.expr?(self)}
386
+ nodes
387
+ else
388
+ nodes.map do |node|
389
+ tempval = node.precompile(self)
390
+ if node == tempval && !node.kind_of?(Duby::AST::Literal)
391
+ tempval = node.temp(self)
392
+ end
393
+ tempval
394
+ end
364
395
  end
365
396
  end
366
397
 
398
+ def compile_args(call)
399
+ precompile_nodes(call.parameters)
400
+ end
401
+
367
402
  def self_type
368
403
  type = AST::type(@class.name.tr('/', '.'))
369
404
  type = type.meta if @static
@@ -379,9 +414,9 @@ module Duby
379
414
  args = compile_args(call)
380
415
  simple = call.expr?(self)
381
416
  @method.print @lvalue if expression && !simple
382
- @method.print "(#{call.inferred_type.name})("
417
+ @method.print "((#{call.inferred_type.name})("
383
418
  args.each{|arg| arg.compile(self, true)}
384
- @method.print ")"
419
+ @method.print "))"
385
420
  @method.puts ';' unless simple && expression
386
421
  else
387
422
  method_call(this, call, compile_args(call), expression)
@@ -390,12 +425,12 @@ module Duby
390
425
 
391
426
  def call(call, expression)
392
427
  if Duby::AST::Constant === call.target
393
- target = call.target.inferred_type.name
428
+ target = call.target.inferred_type.to_source
394
429
  else
395
430
  target = call.target.precompile(self)
396
431
  end
397
432
  params = compile_args(call)
398
-
433
+
399
434
  if Operators.include? call.name
400
435
  operator(target, call.name, params, expression)
401
436
  elsif call.target.inferred_type.array? && ArrayOps.include?(call.name)
@@ -406,7 +441,7 @@ module Duby
406
441
  method_call(target, call, params, expression)
407
442
  end
408
443
  end
409
-
444
+
410
445
  def array_op(target, name, args, expression)
411
446
  simple = expr?(target, args)
412
447
  index, value = args
@@ -429,15 +464,15 @@ module Duby
429
464
  @method.puts ';'
430
465
  end
431
466
  end
432
-
467
+
433
468
  def break(node)
434
469
  @loop.break
435
470
  end
436
-
471
+
437
472
  def next(node)
438
473
  @loop.next
439
474
  end
440
-
475
+
441
476
  def redo(node)
442
477
  @loop.redo
443
478
  end
@@ -474,30 +509,46 @@ module Duby
474
509
  end
475
510
 
476
511
  end
477
-
512
+
478
513
  def method_call(target, call, params, expression)
479
514
  simple = call.expr?(self)
480
515
  method = call.method(self)
481
516
  unless simple || method.actual_return_type.void?
482
517
  @method.print @lvalue if expression
483
518
  end
519
+
520
+ # preamble
484
521
  if method.constructor?
485
522
  @method.print "new "
486
523
  target.compile(self, true)
487
524
  @method.print '('
525
+ elsif method.field?
526
+ target.compile(self, true)
527
+ @method.print ".#{method.name}"
528
+ if method.argument_types.size == 1
529
+ @method.print " = ("
530
+ end
488
531
  else
489
532
  target.compile(self, true)
490
533
  @method.print ".#{method.name}("
491
534
  end
535
+
536
+ # args
492
537
  params.each_with_index do |param, index|
493
538
  @method.print ', ' unless index == 0
494
539
  param.compile(self, true)
495
540
  end
496
- if simple && expression
497
- @method.print ')'
498
- else
499
- @method.puts ');'
541
+
542
+ # postamble
543
+ if !method.field? || (method.field? && method.argument_types.size == 1)
544
+ if simple && expression
545
+ @method.print ')'
546
+ else
547
+ @method.puts ');'
548
+ end
500
549
  end
550
+
551
+ # cleanup
501
552
  if method.actual_return_type.void? && expression
502
553
  @method.print @lvalue
503
554
  if method.static?
@@ -507,11 +558,18 @@ module Duby
507
558
  @method.puts ';'
508
559
  end
509
560
  end
510
-
511
561
  end
512
562
 
513
563
  def temp(expression, value=nil)
514
- assign(@method.tmp(expression.inferred_type), value || expression)
564
+ value ||= expression
565
+ type = value.inferred_type
566
+ if value.expr?(self)
567
+ @method.tmp(type) do
568
+ value.compile(self, true)
569
+ end
570
+ else
571
+ assign(@method.tmp(type), value)
572
+ end
515
573
  end
516
574
 
517
575
  def empty_array(type, size)
@@ -521,48 +579,82 @@ module Duby
521
579
  @method.print ']'
522
580
  end
523
581
 
524
- def import(short, long)
525
- end
526
-
527
582
  def string(value)
528
583
  @method.print value.inspect
529
584
  end
530
-
585
+
531
586
  def boolean(value)
532
587
  @method.print value ? 'true' : 'false'
533
588
  end
534
589
 
590
+ def regexp(value, flags = 0)
591
+ @method.print "java.util.regex.Pattern.compile("
592
+ @method.print value.inspect
593
+ @method.print ")"
594
+ end
595
+
535
596
  def array(node, expression)
536
597
  if expression
537
598
  # create unmodifiable list from array (simplest way to do this in Java source)
538
599
  @method.print "java.util.Collections.unmodifiableList(java.util.Arrays.asList("
539
600
 
540
601
  # elements, as expressions
541
- boolean comma = false
542
- node.children.each do |node|
543
- @method.print ", "# if comma
544
- node.compile(self, true)
602
+ comma = false
603
+ node.children.each do |n|
604
+ @method.print ", " if comma
605
+ n.compile(self, true)
545
606
  comma = true
546
607
  end
547
-
608
+
548
609
  @method.print("))")
549
610
  else
550
611
  # elements, as non-expressions
551
612
  # TODO: ensure they're all reference types!
552
- node.children.each do |node|
553
- node.compile(self, false)
613
+ node.children.each do |n|
614
+ n.compile(self, false)
554
615
  end
555
616
  end
556
617
  end
557
-
618
+
619
+ def build_string(orig_nodes, expression)
620
+ if expression
621
+ nodes = precompile_nodes(orig_nodes)
622
+ simple = nodes.equal?(orig_nodes)
623
+ if !simple
624
+ @method.print(lvalue)
625
+ end
626
+ first = true
627
+ unless nodes[0].kind_of?(Duby::AST::String)
628
+ @method.print '""'
629
+ first = false
630
+ end
631
+ nodes.each do |node|
632
+ @method.print ' + ' unless first
633
+ first = false
634
+ node.compile(self, true)
635
+ end
636
+ @method.puts ';' unless simple
637
+ else
638
+ orig_nodes.each {|n| n.compile(self, false)}
639
+ end
640
+ end
641
+
642
+ def to_string(body, expression)
643
+ body.compile(self, expression)
644
+ end
645
+
558
646
  def null
559
647
  @method.print 'null'
560
648
  end
561
-
649
+
650
+ def binding_reference
651
+ @method.print '$binding'
652
+ end
653
+
562
654
  def compile_self
563
655
  @method.print 'this'
564
656
  end
565
-
657
+
566
658
  def print(node)
567
659
  value = node.parameters[0]
568
660
  value = value && value.precompile(self)
@@ -575,30 +667,31 @@ module Duby
575
667
  @method.puts ');'
576
668
  end
577
669
 
578
- def define_class(class_def, expression)
579
- with(:class => class_def.inferred_type.define(@file),
580
- :static => false) do
581
- @class.annotate(class_def.annotations)
582
- class_def.body.compile(self, false) if class_def.body
583
-
584
- @class.stop
670
+ class ClosureCompiler < JavaSource
671
+ def initialize(file, type, parent)
672
+ @file = file
673
+ @type = type
674
+ @parent = parent
585
675
  end
586
- end
587
676
 
588
- def with(vars)
589
- orig_values = {}
590
- begin
591
- vars.each do |name, new_value|
592
- name = "@#{name}"
593
- orig_values[name] = instance_variable_get name
594
- instance_variable_set name, new_value
677
+ def prepare_binding(scope)
678
+ if scope.has_binding?
679
+ type = scope.binding_type
680
+ @binding = @parent.get_binding(type)
681
+ @method.puts("#{type.name} $binding = this.binding;")
595
682
  end
596
- yield
597
- ensure
598
- orig_values.each do |name, value|
599
- instance_variable_set name, value
683
+ begin
684
+ yield
685
+ ensure
686
+ if scope.has_binding?
687
+ @binding = nil
688
+ end
600
689
  end
601
690
  end
691
+
692
+ def declared_captures
693
+ @parent.declared_captures(@binding)
694
+ end
602
695
  end
603
696
  end
604
697
  end