duby 0.0.2-java → 0.0.3-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +7 -0
- data/README.txt +18 -7
- data/Rakefile +72 -0
- data/examples/ant/example-build.xml +7 -0
- data/examples/appengine/Rakefile +8 -67
- data/examples/appengine/Readme +4 -3
- data/examples/appengine/lib/duby/appengine_tasks.rb +173 -0
- data/examples/appengine/lib/duby/plugin/datastore.rb +92 -31
- data/examples/appengine/lib/duby_task.rb +61 -0
- data/examples/appengine/src/com/ribrdb/DubyApp.duby +32 -6
- data/examples/appengine/src/com/ribrdb/list.dhtml +2 -2
- data/examples/appengine/{config.ru → src/config.ru} +0 -0
- data/examples/bintrees.duby +66 -0
- data/examples/dynamic.duby +17 -0
- data/examples/fib.duby +3 -11
- data/examples/fields.duby +3 -3
- data/examples/fractal.duby +1 -3
- data/examples/sort_closure.duby +7 -0
- data/examples/swing.duby +11 -11
- data/javalib/duby-bootstrap.jar +0 -0
- data/javalib/dynalang-invoke-0.1.jar +0 -0
- data/lib/duby.rb +168 -35
- data/lib/duby/ast.rb +224 -27
- data/lib/duby/ast/call.rb +85 -25
- data/lib/duby/ast/class.rb +112 -28
- data/lib/duby/ast/flow.rb +65 -44
- data/lib/duby/ast/intrinsics.rb +223 -21
- data/lib/duby/ast/literal.rb +67 -16
- data/lib/duby/ast/local.rb +36 -40
- data/lib/duby/ast/method.rb +83 -67
- data/lib/duby/ast/structure.rb +105 -23
- data/lib/duby/compiler.rb +83 -28
- data/lib/duby/env.rb +33 -0
- data/lib/duby/jvm/base.rb +210 -0
- data/lib/duby/jvm/compiler.rb +293 -219
- data/lib/duby/jvm/method_lookup.rb +77 -67
- data/lib/duby/jvm/source_compiler.rb +250 -157
- data/lib/duby/jvm/source_generator/builder.rb +53 -49
- data/lib/duby/jvm/source_generator/loops.rb +9 -9
- data/lib/duby/jvm/source_generator/precompile.rb +35 -25
- data/lib/duby/jvm/typer.rb +19 -10
- data/lib/duby/jvm/types.rb +127 -68
- data/lib/duby/jvm/types/basic_types.rb +26 -13
- data/lib/duby/jvm/types/enumerable.rb +6 -4
- data/lib/duby/jvm/types/factory.rb +49 -13
- data/lib/duby/jvm/types/floats.rb +16 -0
- data/lib/duby/jvm/types/integers.rb +63 -2
- data/lib/duby/jvm/types/intrinsics.rb +43 -21
- data/lib/duby/jvm/types/methods.rb +326 -86
- data/lib/duby/jvm/types/number.rb +3 -0
- data/lib/duby/nbcompiler.rb +1 -1
- data/lib/duby/plugin/edb.rb +1 -1
- data/lib/duby/plugin/java.rb +10 -1
- data/lib/duby/transform.rb +134 -46
- data/lib/duby/typer.rb +75 -50
- data/test/test_ast.rb +106 -106
- data/test/test_compilation.rb +46 -32
- data/test/test_env.rb +42 -0
- data/test/test_java_typer.rb +35 -51
- data/test/test_javac_compiler.rb +4 -1
- data/test/test_jvm_compiler.rb +564 -133
- data/test/test_typer.rb +68 -92
- metadata +37 -21
- data/examples/README +0 -16
- data/lib/duby/c/compiler.rb +0 -134
- data/lib/duby/old/compiler_old.rb +0 -845
- data/lib/duby/old/declaration.rb +0 -72
- data/lib/duby/old/mapper.rb +0 -72
- data/lib/duby/old/signature.rb +0 -52
- data/lib/duby/old/typer_old.rb +0 -163
- data/lib/duby/plugin/math.rb +0 -84
- data/test/test_math_plugin.rb +0 -87
@@ -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
|
-
|
56
|
-
by_name = all_methods
|
42
|
+
by_name = mapped_type.unmeta.declared_constructors
|
57
43
|
elsif meta
|
58
|
-
|
44
|
+
by_name = mapped_type.declared_class_methods(name)
|
59
45
|
else
|
60
|
-
|
46
|
+
by_name = []
|
61
47
|
cls = mapped_type
|
62
48
|
while cls
|
63
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
50
|
-
|
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
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
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
|
-
|
61
|
+
def annotate(node, annotations)
|
62
|
+
node.annotate(annotations)
|
80
63
|
end
|
81
64
|
|
82
|
-
def
|
83
|
-
|
84
|
-
args
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
272
|
-
|
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
|
362
|
-
|
363
|
-
|
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.
|
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
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
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
|
-
|
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
|
-
|
542
|
-
node.children.each do |
|
543
|
-
@method.print ", "
|
544
|
-
|
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 |
|
553
|
-
|
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
|
-
|
579
|
-
|
580
|
-
|
581
|
-
@
|
582
|
-
|
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
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
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
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
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
|