duby 0.0.1
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 +4 -0
- data/Manifest.txt +68 -0
- data/README.txt +31 -0
- data/Rakefile +37 -0
- data/bin/duby +9 -0
- data/bin/dubyc +9 -0
- data/bin/dubyp +9 -0
- data/examples/appengine/src/com/google/appengine/ext/duby/db/Model.duby +132 -0
- data/examples/appengine/src/com/ribrdb/DubyApp.duby +28 -0
- data/examples/bench_fractal.duby +57 -0
- data/examples/construction.duby +8 -0
- data/examples/edb.duby +3 -0
- data/examples/fib.duby +24 -0
- data/examples/fields.duby +22 -0
- data/examples/java_thing.duby +13 -0
- data/examples/simple_class.duby +12 -0
- data/examples/swing.duby +20 -0
- data/examples/tak.duby +15 -0
- data/javalib/JRubyParser.jar +0 -0
- data/lib/duby.rb +170 -0
- data/lib/duby/ast.rb +340 -0
- data/lib/duby/ast/call.rb +73 -0
- data/lib/duby/ast/class.rb +145 -0
- data/lib/duby/ast/flow.rb +328 -0
- data/lib/duby/ast/intrinsics.rb +46 -0
- data/lib/duby/ast/literal.rb +93 -0
- data/lib/duby/ast/local.rb +77 -0
- data/lib/duby/ast/method.rb +187 -0
- data/lib/duby/ast/structure.rb +44 -0
- data/lib/duby/ast/type.rb +93 -0
- data/lib/duby/c/compiler.rb +134 -0
- data/lib/duby/compiler.rb +261 -0
- data/lib/duby/jvm/compiler.rb +684 -0
- data/lib/duby/jvm/method_lookup.rb +185 -0
- data/lib/duby/jvm/source_compiler.rb +516 -0
- data/lib/duby/jvm/source_generator/builder.rb +368 -0
- data/lib/duby/jvm/source_generator/loops.rb +132 -0
- data/lib/duby/jvm/source_generator/precompile.rb +154 -0
- data/lib/duby/jvm/source_generator/typer.rb +11 -0
- data/lib/duby/jvm/typer.rb +118 -0
- data/lib/duby/jvm/types.rb +326 -0
- data/lib/duby/jvm/types/basic_types.rb +18 -0
- data/lib/duby/jvm/types/boolean.rb +11 -0
- data/lib/duby/jvm/types/factory.rb +151 -0
- data/lib/duby/jvm/types/floats.rb +70 -0
- data/lib/duby/jvm/types/integers.rb +110 -0
- data/lib/duby/jvm/types/intrinsics.rb +157 -0
- data/lib/duby/jvm/types/literals.rb +82 -0
- data/lib/duby/jvm/types/methods.rb +344 -0
- data/lib/duby/jvm/types/number.rb +92 -0
- data/lib/duby/nbcompiler.rb +29 -0
- data/lib/duby/old/compiler_old.rb +845 -0
- data/lib/duby/old/declaration.rb +72 -0
- data/lib/duby/old/mapper.rb +72 -0
- data/lib/duby/old/signature.rb +52 -0
- data/lib/duby/old/typer_old.rb +163 -0
- data/lib/duby/plugin/edb.rb +25 -0
- data/lib/duby/plugin/java.rb +42 -0
- data/lib/duby/plugin/math.rb +84 -0
- data/lib/duby/transform.rb +908 -0
- data/lib/duby/typer.rb +359 -0
- data/test/test_ast.rb +391 -0
- data/test/test_compilation.rb +98 -0
- data/test/test_java_typer.rb +199 -0
- data/test/test_javac_compiler.rb +57 -0
- data/test/test_jvm_compiler.rb +1459 -0
- data/test/test_math_plugin.rb +87 -0
- data/test/test_typer.rb +246 -0
- metadata +155 -0
@@ -0,0 +1,185 @@
|
|
1
|
+
module Duby
|
2
|
+
module JVM
|
3
|
+
module MethodLookup
|
4
|
+
# dummy log; it's expected the inclusion target will have it
|
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
|
+
|
16
|
+
def find_method(mapped_type, name, mapped_params, meta)
|
17
|
+
# mapped_type = jvm_type(mapped_type)
|
18
|
+
# mapped_params = convert_params(mapped_params)
|
19
|
+
raise ArgumentError if mapped_params.any? {|p| p.nil?}
|
20
|
+
if name == 'new'
|
21
|
+
if meta
|
22
|
+
name = "<init>"
|
23
|
+
constructor = true
|
24
|
+
else
|
25
|
+
constructor = false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
if constructor
|
31
|
+
method = mapped_type.constructor(*mapped_params)
|
32
|
+
else
|
33
|
+
method = mapped_type.java_method(name, *mapped_params)
|
34
|
+
end
|
35
|
+
rescue NameError
|
36
|
+
unless constructor
|
37
|
+
# exact args failed, do a deeper search
|
38
|
+
log "Failed to locate method #{mapped_type}.#{name}(#{mapped_params})"
|
39
|
+
|
40
|
+
method = find_jls(mapped_type, name, mapped_params, meta)
|
41
|
+
end
|
42
|
+
unless method
|
43
|
+
log "Failed to locate method #{name}(#{mapped_params}) on #{mapped_type}"
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
log "Found method #{method.declaring_class}.#{name}(#{method.argument_types}) from #{mapped_type}"
|
49
|
+
return method
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_jls(mapped_type, name, mapped_params, meta)
|
53
|
+
# mapped_type = jvm_type(mapped_type)
|
54
|
+
# mapped_params = convert_params(mapped_params)
|
55
|
+
if meta
|
56
|
+
all_methods = mapped_type.declared_class_methods
|
57
|
+
else
|
58
|
+
all_methods = []
|
59
|
+
cls = mapped_type
|
60
|
+
while cls
|
61
|
+
all_methods += cls.declared_instance_methods
|
62
|
+
cls = cls.superclass
|
63
|
+
end
|
64
|
+
end
|
65
|
+
by_name = all_methods.select {|m| m.name == name && mapped_params.size <= m.argument_types.size}
|
66
|
+
by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size}
|
67
|
+
|
68
|
+
phase1_methods = phase1(mapped_params, by_name_and_arity)
|
69
|
+
|
70
|
+
if phase1_methods.size > 1
|
71
|
+
raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{phase1_methods}"
|
72
|
+
end
|
73
|
+
|
74
|
+
phase1_methods[0] ||
|
75
|
+
phase2(mapped_params, by_name) ||
|
76
|
+
phase3(mapped_params, by_name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def phase1(mapped_params, potentials)
|
80
|
+
# cycle through methods looking for more specific matches; gather matches of equal specificity
|
81
|
+
methods = potentials.inject([]) do |currents, potential|
|
82
|
+
method_params = potential.argument_types
|
83
|
+
|
84
|
+
# exact match always wins; duplicates not possible
|
85
|
+
return [potential] if each_is_exact(mapped_params, method_params)
|
86
|
+
|
87
|
+
# otherwise, check for potential match and compare to current
|
88
|
+
# TODO: missing ambiguity check; picks last method of equal specificity
|
89
|
+
if each_is_exact_or_subtype_or_convertible(mapped_params, method_params)
|
90
|
+
if currents.size > 0
|
91
|
+
if is_more_specific?(potential.argument_types, currents[0].argument_types)
|
92
|
+
# potential is better, dump all currents
|
93
|
+
currents = [potential]
|
94
|
+
elsif is_more_specific?(currents[0].argument_types, potential.argument_types)
|
95
|
+
# currents are better, try next potential
|
96
|
+
#next
|
97
|
+
else
|
98
|
+
# equal specificity, append to currents
|
99
|
+
currents << potential
|
100
|
+
end
|
101
|
+
else
|
102
|
+
# no previous matches, use potential
|
103
|
+
currents = [potential]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
currents
|
108
|
+
end
|
109
|
+
|
110
|
+
methods
|
111
|
+
end
|
112
|
+
|
113
|
+
def is_more_specific?(potential, current)
|
114
|
+
each_is_exact_or_subtype_or_convertible(potential, current)
|
115
|
+
end
|
116
|
+
|
117
|
+
def phase2(mapped_params, potentials)
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
121
|
+
def phase3(mapped_params, potentials)
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def each_is_exact(incoming, target)
|
126
|
+
incoming.each_with_index do |in_type, i|
|
127
|
+
target_type = target[i]
|
128
|
+
|
129
|
+
# exact match
|
130
|
+
return false unless target_type == in_type
|
131
|
+
end
|
132
|
+
return true
|
133
|
+
end
|
134
|
+
|
135
|
+
def each_is_exact_or_subtype_or_convertible(incoming, target)
|
136
|
+
incoming.each_with_index do |in_type, i|
|
137
|
+
target_type = target[i]
|
138
|
+
|
139
|
+
# exact match
|
140
|
+
next if target_type == in_type
|
141
|
+
|
142
|
+
# primitive is safely convertible
|
143
|
+
if target_type.primitive?
|
144
|
+
if in_type.primitive?
|
145
|
+
next if primitive_convertible? in_type, target_type
|
146
|
+
end
|
147
|
+
return false
|
148
|
+
end
|
149
|
+
|
150
|
+
# object type is assignable
|
151
|
+
return false unless target_type.assignable_from? in_type
|
152
|
+
end
|
153
|
+
return true
|
154
|
+
end
|
155
|
+
|
156
|
+
BOOLEAN = Java::boolean.java_class
|
157
|
+
BYTE = Java::byte.java_class
|
158
|
+
SHORT = Java::short.java_class
|
159
|
+
CHAR = Java::char.java_class
|
160
|
+
INT = Java::int.java_class
|
161
|
+
LONG = Java::long.java_class
|
162
|
+
FLOAT = Java::float.java_class
|
163
|
+
DOUBLE = Java::double.java_class
|
164
|
+
|
165
|
+
PrimitiveConversions = {
|
166
|
+
BOOLEAN => [BOOLEAN],
|
167
|
+
BYTE => [BYTE, SHORT, CHAR, INT, LONG, FLOAT, DOUBLE],
|
168
|
+
SHORT => [SHORT, INT, LONG, FLOAT, DOUBLE],
|
169
|
+
CHAR => [CHAR, INT, LONG, FLOAT, DOUBLE],
|
170
|
+
INT => [INT, LONG, FLOAT, DOUBLE],
|
171
|
+
LONG => [LONG, DOUBLE],
|
172
|
+
FLOAT => [FLOAT, DOUBLE],
|
173
|
+
DOUBLE => [DOUBLE]
|
174
|
+
}
|
175
|
+
|
176
|
+
def primitive_convertible?(in_type, target_type)
|
177
|
+
if PrimitiveConversions.include? in_type
|
178
|
+
PrimitiveConversions[in_type].include?(target_type)
|
179
|
+
else
|
180
|
+
in_type.convertible_to?(target_type)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,516 @@
|
|
1
|
+
require 'duby'
|
2
|
+
require 'duby/ast'
|
3
|
+
require 'duby/jvm/types'
|
4
|
+
require 'duby/jvm/compiler'
|
5
|
+
require 'duby/jvm/source_generator/builder'
|
6
|
+
require 'duby/jvm/source_generator/precompile'
|
7
|
+
require 'duby/jvm/source_generator/loops'
|
8
|
+
|
9
|
+
class String
|
10
|
+
def compile(compiler, expression)
|
11
|
+
compiler.method.print self if expression
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Duby
|
16
|
+
module Compiler
|
17
|
+
class JavaSource
|
18
|
+
JVMTypes = Duby::JVM::Types
|
19
|
+
include Duby::Compiler::JVM::JVMLogger
|
20
|
+
attr_accessor :filename, :method, :static, :class, :lvalue
|
21
|
+
|
22
|
+
Operators = [
|
23
|
+
'+', '-', '+@', '-@', '/', '%', '*', '<',
|
24
|
+
'<=', '==', '!=', '>=', '>',
|
25
|
+
'<<', '>>', '>>>', '|', '&', '^', '~'
|
26
|
+
]
|
27
|
+
ArrayOps = [
|
28
|
+
'[]', '[]=', 'length'
|
29
|
+
]
|
30
|
+
|
31
|
+
ImplicitReturn = Struct.new(:value)
|
32
|
+
|
33
|
+
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
|
+
|
40
|
+
@file = Duby::JavaSource::Builder.new(filename, self)
|
41
|
+
#@file.package = package
|
42
|
+
@class = @file.public_class(classname)
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate(&block)
|
46
|
+
@class.stop
|
47
|
+
log "Generating source files..."
|
48
|
+
@file.generate do |filename, builder|
|
49
|
+
log " #{builder.class_name}"
|
50
|
+
if block_given?
|
51
|
+
yield filename, builder
|
52
|
+
else
|
53
|
+
File.open(filename, 'w') {|f| f.write(builder.generate)}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
log "...done!"
|
57
|
+
end
|
58
|
+
|
59
|
+
def define_main(body)
|
60
|
+
with :method => @class.main do
|
61
|
+
log "Starting main method"
|
62
|
+
|
63
|
+
@method.start
|
64
|
+
|
65
|
+
body.compile(self, false)
|
66
|
+
|
67
|
+
@method.stop
|
68
|
+
end
|
69
|
+
|
70
|
+
log "Main method complete!"
|
71
|
+
end
|
72
|
+
|
73
|
+
def define_method(name, signature, args, body, force_static)
|
74
|
+
args = args.args || []
|
75
|
+
return_type = signature[:return]
|
76
|
+
exceptions = signature[:throws] || []
|
77
|
+
if @static || force_static
|
78
|
+
method = @class.public_static_method(name.to_s, return_type, exceptions, *args)
|
79
|
+
else
|
80
|
+
if name == "initialize"
|
81
|
+
method = @class.public_constructor(exceptions, *args)
|
82
|
+
else
|
83
|
+
method = @class.public_method(name.to_s, return_type, exceptions, *args)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
with :method => method, :static => @static || force_static do
|
88
|
+
log "Starting new method #{name}"
|
89
|
+
|
90
|
+
@method.start
|
91
|
+
|
92
|
+
unless @method.type.nil? || @method.type.void?
|
93
|
+
self.return(ImplicitReturn.new(body))
|
94
|
+
else
|
95
|
+
body.compile(self, false) if body
|
96
|
+
end
|
97
|
+
|
98
|
+
log "Method #{name} complete!"
|
99
|
+
@method.stop
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def return(node)
|
104
|
+
if @method.type.nil? || @method.type.void?
|
105
|
+
@method.puts 'return;'
|
106
|
+
return
|
107
|
+
end
|
108
|
+
if node.value.expr?(self)
|
109
|
+
@method.print 'return '
|
110
|
+
node.value.compile(self, true)
|
111
|
+
@method.puts ';'
|
112
|
+
else
|
113
|
+
store_value('return ', node.value)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def _raise(node)
|
118
|
+
if node.expr?(self)
|
119
|
+
@method.print 'throw '
|
120
|
+
node.compile(self, true)
|
121
|
+
@method.puts ';'
|
122
|
+
else
|
123
|
+
store_value('throw ', node)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def rescue(node, expression)
|
128
|
+
@method.block 'try' do
|
129
|
+
maybe_store(node.body, expression)
|
130
|
+
end
|
131
|
+
node.clauses.each do |clause|
|
132
|
+
clause.types.each do |type|
|
133
|
+
name = clause.name || 'tmp$ex'
|
134
|
+
@method.block "catch (#{type.to_source} #{name})" do
|
135
|
+
maybe_store(clause.body, expression)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def ensure(node, expression)
|
142
|
+
@method.block 'try' do
|
143
|
+
maybe_store(node.body, expression)
|
144
|
+
end
|
145
|
+
@method.block 'finally' do
|
146
|
+
node.clause.compile(self, false)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def line(num)
|
151
|
+
end
|
152
|
+
|
153
|
+
def declare_local(name, type)
|
154
|
+
@method.declare_local(type, name)
|
155
|
+
end
|
156
|
+
|
157
|
+
def declare_field(name, type)
|
158
|
+
@class.declare_field(name, type, @static)
|
159
|
+
end
|
160
|
+
|
161
|
+
def local(name, type)
|
162
|
+
@method.print name
|
163
|
+
end
|
164
|
+
|
165
|
+
def field(name, type)
|
166
|
+
name = name[1..-1]
|
167
|
+
declare_field(name, type)
|
168
|
+
@method.print "#{this}.#{name}"
|
169
|
+
end
|
170
|
+
|
171
|
+
def this
|
172
|
+
@static ? @class.class_name : 'this'
|
173
|
+
end
|
174
|
+
|
175
|
+
def local_assign(name, type, expression, value)
|
176
|
+
value = value.precompile(self)
|
177
|
+
if method.local?(name)
|
178
|
+
@method.print @lvalue if expression
|
179
|
+
@method.print "#{name} = "
|
180
|
+
value.compile(self, true)
|
181
|
+
@method.puts ';'
|
182
|
+
else
|
183
|
+
@method.declare_local(type, name) do
|
184
|
+
value.compile(self, true)
|
185
|
+
end
|
186
|
+
if expression
|
187
|
+
@method.puts "#{@lvalue}#{name};"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def field_declare(name, type)
|
193
|
+
name = name[1..-1]
|
194
|
+
declare_field(name, type)
|
195
|
+
end
|
196
|
+
|
197
|
+
def local_declare(name, type)
|
198
|
+
declare_local(name, type)
|
199
|
+
end
|
200
|
+
|
201
|
+
def field_assign(name, type, expression, value)
|
202
|
+
name = name[1..-1]
|
203
|
+
declare_field(name, type)
|
204
|
+
lvalue = "#{@lvalue if expression}#{this}.#{name} = "
|
205
|
+
store_value(lvalue, value)
|
206
|
+
end
|
207
|
+
|
208
|
+
def store_value(lvalue, value)
|
209
|
+
if value.is_a? String
|
210
|
+
@method.puts "#{lvalue}#{value};"
|
211
|
+
elsif value.expr?(self)
|
212
|
+
@method.print lvalue
|
213
|
+
value.compile(self, true)
|
214
|
+
@method.puts ';'
|
215
|
+
else
|
216
|
+
with :lvalue => lvalue do
|
217
|
+
value.compile(self, true)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def assign(name, value)
|
223
|
+
store_value("#{name} = ", value)
|
224
|
+
name
|
225
|
+
end
|
226
|
+
|
227
|
+
def maybe_store(value, expression)
|
228
|
+
if expression
|
229
|
+
store_value(@lvalue, value)
|
230
|
+
else
|
231
|
+
value.compile(self, false)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def body(body, expression)
|
236
|
+
# all except the last element in a body of code is treated as a statement
|
237
|
+
i, last = 0, body.children.size - 1
|
238
|
+
while i < last
|
239
|
+
body.children[i].compile(self, false)
|
240
|
+
i += 1
|
241
|
+
end
|
242
|
+
# last element is an expression only if the body is an expression
|
243
|
+
maybe_store(body.children[last], expression)
|
244
|
+
end
|
245
|
+
|
246
|
+
def branch_expression(node)
|
247
|
+
node.condition.compile(self, true)
|
248
|
+
@method.print ' ? ('
|
249
|
+
if node.body
|
250
|
+
node.body.compile(self, true)
|
251
|
+
else
|
252
|
+
@method.print @method.init_value(node.inferred_type)
|
253
|
+
end
|
254
|
+
@method.print ') : ('
|
255
|
+
if node.else
|
256
|
+
node.else.compile(self, true)
|
257
|
+
else
|
258
|
+
@method.print @method.init_value(node.inferred_type)
|
259
|
+
end
|
260
|
+
@method.print ')'
|
261
|
+
end
|
262
|
+
|
263
|
+
def branch(node, expression)
|
264
|
+
if expression && node.expr?(self)
|
265
|
+
return branch_expression(node)
|
266
|
+
end
|
267
|
+
predicate = node.condition.predicate.precompile(self)
|
268
|
+
@method.print 'if ('
|
269
|
+
predicate.compile(self, true)
|
270
|
+
@method.block ")" do
|
271
|
+
if node.body
|
272
|
+
maybe_store(node.body, expression)
|
273
|
+
elsif expression
|
274
|
+
store_value(@lvalue, @method.init_value(node.inferred_type))
|
275
|
+
end
|
276
|
+
end
|
277
|
+
if node.else || expression
|
278
|
+
@method.block 'else' do
|
279
|
+
if node.else
|
280
|
+
maybe_store(node.else, expression)
|
281
|
+
else
|
282
|
+
store_value(@lvalue, @method.init_value(node.inferred_type))
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def while_loop(loop, expression)
|
289
|
+
if loop.redo || !loop.condition.predicate.expr?(self)
|
290
|
+
loop = ComplexWhileLoop.new(loop, self)
|
291
|
+
else
|
292
|
+
loop = SimpleWhileLoop.new(loop, self)
|
293
|
+
end
|
294
|
+
with(:loop => loop) do
|
295
|
+
loop.compile(expression)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def for_loop(loop, expression)
|
300
|
+
if loop.redo
|
301
|
+
loop = RedoableForLoop.new(loop, self)
|
302
|
+
else
|
303
|
+
loop = SimpleForLoop.new(loop, self)
|
304
|
+
end
|
305
|
+
with(:loop => loop) do
|
306
|
+
loop.compile(expression)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def expr?(target, params)
|
311
|
+
!([target] + params).any? {|x| x.kind_of? Duby::AST::TempValue}
|
312
|
+
end
|
313
|
+
|
314
|
+
def operator(target, op, params, expression)
|
315
|
+
simple = expr?(target, params)
|
316
|
+
if expression && !simple
|
317
|
+
@method.print @lvalue
|
318
|
+
end
|
319
|
+
if params.size == 0
|
320
|
+
# unary operator
|
321
|
+
op = op[0,1]
|
322
|
+
@method.print op
|
323
|
+
target.compile(self, true)
|
324
|
+
else
|
325
|
+
@method.print '('
|
326
|
+
other = params[0]
|
327
|
+
target.compile(self, true)
|
328
|
+
@method.print " #{op} "
|
329
|
+
other.compile(self, true)
|
330
|
+
@method.print ')'
|
331
|
+
end
|
332
|
+
unless expression && simple
|
333
|
+
@method.puts ';'
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def compile_args(call)
|
338
|
+
call.parameters.map do |param|
|
339
|
+
param.precompile(self)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def self_type
|
344
|
+
type = AST::type(@class.name.tr('/', '.'))
|
345
|
+
type = type.meta if @static
|
346
|
+
type
|
347
|
+
end
|
348
|
+
|
349
|
+
def self_call(call, expression)
|
350
|
+
if call.cast?
|
351
|
+
args = compile_args(call)
|
352
|
+
simple = call.expr?(self)
|
353
|
+
@method.print @lvalue if expression && !simple
|
354
|
+
@method.print "(#{call.inferred_type.name})("
|
355
|
+
args.each{|arg| arg.compile(self, true)}
|
356
|
+
@method.print ")"
|
357
|
+
@method.puts ';' unless simple && expression
|
358
|
+
else
|
359
|
+
method_call(this, call, compile_args(call), expression)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def call(call, expression)
|
364
|
+
if Duby::AST::Constant === call.target
|
365
|
+
target = call.target.inferred_type.name
|
366
|
+
else
|
367
|
+
target = call.target.precompile(self)
|
368
|
+
end
|
369
|
+
params = compile_args(call)
|
370
|
+
|
371
|
+
if Operators.include? call.name
|
372
|
+
operator(target, call.name, params, expression)
|
373
|
+
elsif call.target.inferred_type.array? && ArrayOps.include?(call.name)
|
374
|
+
array_op(target, call.name, params, expression)
|
375
|
+
elsif call.name == 'nil?'
|
376
|
+
operator(target, '==', ['null'], expression)
|
377
|
+
else
|
378
|
+
method_call(target, call, params, expression)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def array_op(target, name, args, expression)
|
383
|
+
simple = expr?(target, args)
|
384
|
+
index, value = args
|
385
|
+
if expression && !simple
|
386
|
+
@method.print @lvalue
|
387
|
+
end
|
388
|
+
target.compile(self, true)
|
389
|
+
if name == 'length'
|
390
|
+
@method.print '.length'
|
391
|
+
else
|
392
|
+
@method.print '['
|
393
|
+
index.compile(self, true)
|
394
|
+
@method.print ']'
|
395
|
+
if name == '[]='
|
396
|
+
@method.print " = "
|
397
|
+
value.compile(self, true)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
unless simple && expression
|
401
|
+
@method.puts ';'
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def break(node)
|
406
|
+
@loop.break
|
407
|
+
end
|
408
|
+
|
409
|
+
def next(node)
|
410
|
+
@loop.next
|
411
|
+
end
|
412
|
+
|
413
|
+
def redo(node)
|
414
|
+
@loop.redo
|
415
|
+
end
|
416
|
+
|
417
|
+
def method_call(target, call, params, expression)
|
418
|
+
simple = call.expr?(self)
|
419
|
+
method = call.method(self)
|
420
|
+
unless simple || method.actual_return_type.void?
|
421
|
+
@method.print @lvalue if expression
|
422
|
+
end
|
423
|
+
if method.constructor?
|
424
|
+
@method.print "new "
|
425
|
+
target.compile(self, true)
|
426
|
+
@method.print '('
|
427
|
+
else
|
428
|
+
target.compile(self, true)
|
429
|
+
@method.print ".#{method.name}("
|
430
|
+
end
|
431
|
+
params.each_with_index do |param, index|
|
432
|
+
@method.print ', ' unless index == 0
|
433
|
+
param.compile(self, true)
|
434
|
+
end
|
435
|
+
if simple && expression
|
436
|
+
@method.print ')'
|
437
|
+
else
|
438
|
+
@method.puts ');'
|
439
|
+
end
|
440
|
+
if method.actual_return_type.void? && expression
|
441
|
+
@method.print @lvalue
|
442
|
+
if method.static?
|
443
|
+
@method.puts 'null;'
|
444
|
+
else
|
445
|
+
target.compile(self, true)
|
446
|
+
@method.puts ';'
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
end
|
451
|
+
|
452
|
+
def temp(expression, value=nil)
|
453
|
+
assign(@method.tmp(expression.inferred_type), value || expression)
|
454
|
+
end
|
455
|
+
|
456
|
+
def empty_array(type, size)
|
457
|
+
sizevar = size.precompile(self)
|
458
|
+
@method.print "#{@lvalue unless size.expr?(self)}new #{type.name}["
|
459
|
+
sizevar.compile(self, true)
|
460
|
+
@method.print ']'
|
461
|
+
end
|
462
|
+
|
463
|
+
def import(short, long)
|
464
|
+
end
|
465
|
+
|
466
|
+
def string(value)
|
467
|
+
@method.print value.inspect
|
468
|
+
end
|
469
|
+
|
470
|
+
def boolean(value)
|
471
|
+
@method.print value ? 'true' : 'false'
|
472
|
+
end
|
473
|
+
|
474
|
+
def null
|
475
|
+
@method.print 'null'
|
476
|
+
end
|
477
|
+
|
478
|
+
def print(node)
|
479
|
+
value = node.parameters[0]
|
480
|
+
value = value && value.precompile(self)
|
481
|
+
if node.println
|
482
|
+
@method.print "System.out.println("
|
483
|
+
else
|
484
|
+
@method.print "System.out.print("
|
485
|
+
end
|
486
|
+
value.compile(self, true) if value
|
487
|
+
@method.puts ');'
|
488
|
+
end
|
489
|
+
|
490
|
+
def define_class(class_def, expression)
|
491
|
+
with(:class => class_def.inferred_type.define(@file),
|
492
|
+
:static => false) do
|
493
|
+
class_def.body.compile(self, false) if class_def.body
|
494
|
+
|
495
|
+
@class.stop
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def with(vars)
|
500
|
+
orig_values = {}
|
501
|
+
begin
|
502
|
+
vars.each do |name, new_value|
|
503
|
+
name = "@#{name}"
|
504
|
+
orig_values[name] = instance_variable_get name
|
505
|
+
instance_variable_set name, new_value
|
506
|
+
end
|
507
|
+
yield
|
508
|
+
ensure
|
509
|
+
orig_values.each do |name, value|
|
510
|
+
instance_variable_set name, value
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|