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
@@ -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