duby 0.0.2-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 +8 -0
- data/README.txt +39 -0
- data/Rakefile +13 -0
- data/bin/duby +9 -0
- data/bin/dubyc +9 -0
- data/bin/dubyp +9 -0
- data/examples/README +16 -0
- data/examples/appengine/Rakefile +72 -0
- data/examples/appengine/Readme +27 -0
- data/examples/appengine/config.ru +7 -0
- data/examples/appengine/lib/duby/plugin/datastore.rb +171 -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/appengine/src/com/ribrdb/list.dhtml +15 -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/fractal.duby +57 -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/examples/test.edb +9 -0
- data/javalib/JRubyParser.jar +0 -0
- data/lib/duby.rb +168 -0
- data/lib/duby/ast.rb +386 -0
- data/lib/duby/ast/call.rb +145 -0
- data/lib/duby/ast/class.rb +154 -0
- data/lib/duby/ast/flow.rb +332 -0
- data/lib/duby/ast/intrinsics.rb +56 -0
- data/lib/duby/ast/literal.rb +97 -0
- data/lib/duby/ast/local.rb +92 -0
- data/lib/duby/ast/method.rb +244 -0
- data/lib/duby/ast/structure.rb +62 -0
- data/lib/duby/ast/type.rb +93 -0
- data/lib/duby/c/compiler.rb +134 -0
- data/lib/duby/compiler.rb +282 -0
- data/lib/duby/jvm/compiler.rb +766 -0
- data/lib/duby/jvm/method_lookup.rb +193 -0
- data/lib/duby/jvm/source_compiler.rb +605 -0
- data/lib/duby/jvm/source_generator/builder.rb +387 -0
- data/lib/duby/jvm/source_generator/loops.rb +110 -0
- data/lib/duby/jvm/source_generator/precompile.rb +170 -0
- data/lib/duby/jvm/source_generator/typer.rb +11 -0
- data/lib/duby/jvm/typer.rb +131 -0
- data/lib/duby/jvm/types.rb +331 -0
- data/lib/duby/jvm/types/basic_types.rb +19 -0
- data/lib/duby/jvm/types/boolean.rb +11 -0
- data/lib/duby/jvm/types/enumerable.rb +63 -0
- data/lib/duby/jvm/types/factory.rb +155 -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 +230 -0
- data/lib/duby/jvm/types/literals.rb +82 -0
- data/lib/duby/jvm/types/methods.rb +381 -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 +1028 -0
- data/lib/duby/typer.rb +369 -0
- data/test/TestUser.class +0 -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 +58 -0
- data/test/test_jvm_compiler.rb +1770 -0
- data/test/test_math_plugin.rb +87 -0
- data/test/test_typer.rb +246 -0
- metadata +156 -0
@@ -0,0 +1,1028 @@
|
|
1
|
+
require 'jruby'
|
2
|
+
|
3
|
+
module Duby
|
4
|
+
module Transform
|
5
|
+
class Error < StandardError
|
6
|
+
attr_reader :position, :cause
|
7
|
+
def initialize(msg, position, cause=nil)
|
8
|
+
super(msg)
|
9
|
+
@position = position
|
10
|
+
@position = position.position if position.respond_to? :position
|
11
|
+
@cause = cause
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Transformer
|
16
|
+
attr_reader :errors
|
17
|
+
def initialize
|
18
|
+
@errors = []
|
19
|
+
@tmp_count = 0
|
20
|
+
@annotations = []
|
21
|
+
@scopes = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def annotations
|
25
|
+
result, @annotations = @annotations, []
|
26
|
+
return result
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_annotation(annotation)
|
30
|
+
@annotations << annotation
|
31
|
+
Duby::AST::Noop.new(annotation.parent, annotation.position)
|
32
|
+
end
|
33
|
+
|
34
|
+
def tmp
|
35
|
+
"__xform_tmp_#{@tmp_count += 1}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform(node, parent)
|
39
|
+
begin
|
40
|
+
scope = node.getScope if node.respond_to? :getScope
|
41
|
+
if scope
|
42
|
+
@scopes << scope
|
43
|
+
end
|
44
|
+
begin
|
45
|
+
node.transform(self, parent)
|
46
|
+
ensure
|
47
|
+
if scope
|
48
|
+
@scopes.pop
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rescue Error => ex
|
52
|
+
@errors << ex
|
53
|
+
Duby::AST::ErrorNode.new(parent, ex)
|
54
|
+
rescue Exception => ex
|
55
|
+
error = Error.new(ex.message, node.position, ex)
|
56
|
+
@errors << error
|
57
|
+
Duby::AST::ErrorNode.new(parent, error)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def captured?(node)
|
62
|
+
depth = node.depth
|
63
|
+
scope = @scopes[-1]
|
64
|
+
while depth > 0
|
65
|
+
depth -= 1
|
66
|
+
scope = scope.enclosing_scope
|
67
|
+
end
|
68
|
+
scope.isCaptured(node.index)
|
69
|
+
end
|
70
|
+
|
71
|
+
def eval(src, filename='-', parent=nil, *vars)
|
72
|
+
unless vars.empty?
|
73
|
+
src = "#{vars.join ','} = [];begin;#{src};end"
|
74
|
+
end
|
75
|
+
node = Duby::AST.parse_ruby(src, filename)
|
76
|
+
duby_node = transform(node, nil).body
|
77
|
+
unless vars.empty?
|
78
|
+
# We have
|
79
|
+
# (Script (Body ({vars} (NewlineNode (BeginNode ({src}))))))
|
80
|
+
duby_node = duby_node.children[1]
|
81
|
+
end
|
82
|
+
duby_node.parent = parent
|
83
|
+
duby_node
|
84
|
+
end
|
85
|
+
|
86
|
+
def expand(fvcall, parent)
|
87
|
+
result = yield self, fvcall, parent
|
88
|
+
unless result.kind_of?(AST::Node)
|
89
|
+
raise Error.new('Invalid macro result', fvcall.position)
|
90
|
+
end
|
91
|
+
result
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
TransformError = Transform::Error
|
96
|
+
|
97
|
+
module AST
|
98
|
+
begin
|
99
|
+
Parser = org.jrubyparser.Parser
|
100
|
+
rescue NameError
|
101
|
+
$CLASSPATH << File.dirname(__FILE__) + '/../../javalib/JRubyParser.jar'
|
102
|
+
Parser = org.jrubyparser.Parser
|
103
|
+
end
|
104
|
+
java_import org.jrubyparser.parser.ParserConfiguration
|
105
|
+
java_import org.jrubyparser.CompatVersion
|
106
|
+
java_import java.io.StringReader
|
107
|
+
|
108
|
+
def parse(src, filename='-', raise_errors=false, transformer=nil)
|
109
|
+
ast = parse_ruby(src, filename)
|
110
|
+
transformer ||= Transform::Transformer.new
|
111
|
+
ast = transformer.transform(ast, nil)
|
112
|
+
if raise_errors
|
113
|
+
transformer.errors.each do |e|
|
114
|
+
raise e.cause || e
|
115
|
+
end
|
116
|
+
end
|
117
|
+
ast
|
118
|
+
end
|
119
|
+
module_function :parse
|
120
|
+
|
121
|
+
def parse_ruby(src, filename='-')
|
122
|
+
raise ArgumentError if src.nil?
|
123
|
+
parser = Parser.new
|
124
|
+
config = ParserConfiguration.new(0, CompatVersion::RUBY1_9, true)
|
125
|
+
begin
|
126
|
+
parser.parse(filename, StringReader.new(src), config)
|
127
|
+
rescue => ex
|
128
|
+
if ex.cause.respond_to? :position
|
129
|
+
position = ex.cause.position
|
130
|
+
puts "#{position.file}:#{position.start_line + 1}: #{ex.message}"
|
131
|
+
end
|
132
|
+
raise ex
|
133
|
+
end
|
134
|
+
end
|
135
|
+
module_function :parse_ruby
|
136
|
+
|
137
|
+
JRubyAst = org.jrubyparser.ast
|
138
|
+
|
139
|
+
module CallOpAssignment
|
140
|
+
def call_op_assignment(transformer, parent, name, args)
|
141
|
+
set_args = JRubyAst::ListNode.new(position)
|
142
|
+
set_args.add_all(args)
|
143
|
+
set_args.add(value_node)
|
144
|
+
|
145
|
+
first = JRubyAst::CallNode.new(position, receiver_node, name, args)
|
146
|
+
second = JRubyAst::AttrAssignNode.new(position, receiver_node,
|
147
|
+
"#{name}=", set_args)
|
148
|
+
|
149
|
+
if operator_name == '||'
|
150
|
+
klass = JRubyAst::OrNode
|
151
|
+
elsif operator_name == '&&'
|
152
|
+
klass = JRubyAst::AndNode
|
153
|
+
else
|
154
|
+
raise "Unknown OpAsgn operator #{operator_name}"
|
155
|
+
end
|
156
|
+
transformer.transform(klass.new(position, first, second), parent)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# reload
|
161
|
+
module JRubyAst
|
162
|
+
class Node
|
163
|
+
def transform(transformer, parent)
|
164
|
+
# default behavior is to raise, to expose missing nodes
|
165
|
+
raise TransformError.new("Unsupported syntax: #{self}", position)
|
166
|
+
end
|
167
|
+
|
168
|
+
def [](ix)
|
169
|
+
self.child_nodes[ix]
|
170
|
+
end
|
171
|
+
|
172
|
+
def inspect(indent = 0)
|
173
|
+
s = ' '*indent + self.class.name.split('::').last
|
174
|
+
|
175
|
+
if self.respond_to?(:name)
|
176
|
+
s << " |#{self.name}|"
|
177
|
+
end
|
178
|
+
if self.respond_to?(:value)
|
179
|
+
s << " ==#{self.value.inspect}"
|
180
|
+
end
|
181
|
+
|
182
|
+
if self.respond_to?(:index)
|
183
|
+
s << " &#{self.index.inspect}"
|
184
|
+
end
|
185
|
+
|
186
|
+
if self.respond_to?(:depth)
|
187
|
+
s << " >#{self.depth.inspect}"
|
188
|
+
end
|
189
|
+
|
190
|
+
[:receiver_node, :args_node, :var_node, :head_node, :value_node, :iter_node, :body_node, :next_node, :condition, :then_body, :else_body].each do |mm|
|
191
|
+
if self.respond_to?(mm)
|
192
|
+
begin
|
193
|
+
s << "\n#{self.send(mm).inspect(indent+2)}" if self.send(mm)
|
194
|
+
rescue
|
195
|
+
s << "\n#{' '*(indent+2)}#{self.send(mm).inspect}" if self.send(mm)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
if org::jruby::ast::ListNode === self
|
201
|
+
(0...self.size).each do |n|
|
202
|
+
begin
|
203
|
+
s << "\n#{self.get(n).inspect(indent+2)}" if self.get(n)
|
204
|
+
rescue
|
205
|
+
s << "\n#{' '*(indent+2)}#{self.get(n).inspect}" if self.get(n)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
s
|
210
|
+
end
|
211
|
+
|
212
|
+
def signature(parent)
|
213
|
+
nil
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
class ListNode
|
218
|
+
include Enumerable
|
219
|
+
|
220
|
+
def each(&block)
|
221
|
+
child_nodes.each(&block)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
class ArgsNode
|
226
|
+
def args
|
227
|
+
has_typed = optional &&
|
228
|
+
optional.child_nodes.all? {|n| n.kind_of? TypedArgumentNode}
|
229
|
+
if has_typed
|
230
|
+
optional
|
231
|
+
else
|
232
|
+
pre
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def transform(transformer, parent)
|
237
|
+
Arguments.new(parent, position) do |args_node|
|
238
|
+
arg_list = args.child_nodes.map do |node|
|
239
|
+
if !node.respond_to?(:type_node) || node.type_node.respond_to?(:type_reference)
|
240
|
+
RequiredArgument.new(args_node, node.position, node.name)
|
241
|
+
else
|
242
|
+
OptionalArgument.new(args_node, node.position, node.name) {|opt_arg| [transformer.transform(node, opt_arg)]}
|
243
|
+
end
|
244
|
+
# argument nodes will have type soon
|
245
|
+
#RequiredArgument.new(args_node, node.name, node.type)
|
246
|
+
end if args
|
247
|
+
|
248
|
+
# TODO optional arguments.
|
249
|
+
opt_list = optional.child_nodes.map do |node|
|
250
|
+
OptionalArgument.new(args_node, node.position) {|opt_arg| [transformer.transform(node, opt_arg)]}
|
251
|
+
end if false && optional
|
252
|
+
|
253
|
+
rest_arg = RestArgument.new(args_node, rest.position, rest.name) if rest
|
254
|
+
|
255
|
+
block_arg = BlockArgument.new(args_node, block.position, block.name) if block
|
256
|
+
|
257
|
+
[arg_list, opt_list, rest_arg, block_arg]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
class ArrayNode
|
263
|
+
def transform(transformer, parent)
|
264
|
+
Array.new(parent, position) do |array|
|
265
|
+
child_nodes.map {|child| transformer.transform(child, array)}
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
class AttrAssignNode
|
271
|
+
def transform(transformer, parent)
|
272
|
+
case name
|
273
|
+
when '[]='
|
274
|
+
Call.new(parent, position, name) do |call|
|
275
|
+
[
|
276
|
+
transformer.transform(receiver_node, call),
|
277
|
+
args_node ? args_node.child_nodes.map {|arg| transformer.transform(arg, call)} : [],
|
278
|
+
nil
|
279
|
+
]
|
280
|
+
end
|
281
|
+
else
|
282
|
+
new_name = name[0..-2] + '_set'
|
283
|
+
Call.new(parent, position, new_name) do |call|
|
284
|
+
[
|
285
|
+
transformer.transform(receiver_node, call),
|
286
|
+
args_node ? args_node.child_nodes.map {|arg| transformer.transform(arg, call)} : [],
|
287
|
+
nil
|
288
|
+
]
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
class BeginNode
|
295
|
+
def transform(transformer, parent)
|
296
|
+
transformer.transform(body_node, parent)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
class BlockNode
|
301
|
+
def transform(transformer, parent)
|
302
|
+
Body.new(parent, position) do |body|
|
303
|
+
child_nodes.map {|child| transformer.transform(child, body)}
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
class BreakNode
|
309
|
+
def transform(transformer, parent)
|
310
|
+
# TODO support 'break value'?
|
311
|
+
Break.new(parent, position)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
class ClassNode
|
316
|
+
def transform(transformer, parent)
|
317
|
+
ClassDefinition.new(parent, position,
|
318
|
+
cpath.name,
|
319
|
+
transformer.annotations) do |class_def|
|
320
|
+
[
|
321
|
+
super_node ? super_node.type_reference(class_def) : nil,
|
322
|
+
body_node ? transformer.transform(body_node, class_def) : nil
|
323
|
+
]
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
class GlobalVarNode
|
329
|
+
def transform(transformer, parent)
|
330
|
+
classname = name[1..-1]
|
331
|
+
annotation = Annotation.new(parent, position, AST.type(classname))
|
332
|
+
transformer.add_annotation(annotation)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
class CallNode
|
337
|
+
def transform(transformer, parent)
|
338
|
+
if annotation?
|
339
|
+
return transformer.add_annotation(annotation(transformer, parent))
|
340
|
+
end
|
341
|
+
|
342
|
+
actual_name = name
|
343
|
+
case actual_name
|
344
|
+
when '[]'
|
345
|
+
# could be array instantiation
|
346
|
+
case receiver_node
|
347
|
+
when VCallNode
|
348
|
+
case receiver_node.name
|
349
|
+
when 'boolean', 'byte', 'short', 'char', 'int', 'long', 'float', 'double'
|
350
|
+
return EmptyArray.new(parent, position, AST::type(receiver_node.name)) do |array|
|
351
|
+
transformer.transform(args_node.get(0), array)
|
352
|
+
end
|
353
|
+
# TODO look for imported, lower case class names
|
354
|
+
end
|
355
|
+
when ConstNode
|
356
|
+
return EmptyArray.new(parent, position, AST::type(receiver_node.name)) do |array|
|
357
|
+
transformer.transform(args_node.get(0), array)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
when /=$/
|
361
|
+
if name.size > 2 || name =~ /^\w/
|
362
|
+
actual_name = name[0..-2] + '_set'
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
Call.new(parent, position, actual_name) do |call|
|
367
|
+
[
|
368
|
+
transformer.transform(receiver_node, call),
|
369
|
+
args_node ? args_node.child_nodes.map {|arg| transformer.transform(arg, call)} : [],
|
370
|
+
iter_node ? transformer.transform(iter_node, call) : nil
|
371
|
+
]
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def type_reference(parent)
|
376
|
+
if name == "[]"
|
377
|
+
# array type, top should be a constant; find the rest
|
378
|
+
array = true
|
379
|
+
elements = []
|
380
|
+
else
|
381
|
+
array = false
|
382
|
+
elements = [name]
|
383
|
+
end
|
384
|
+
|
385
|
+
receiver = receiver_node
|
386
|
+
|
387
|
+
loop do
|
388
|
+
case receiver
|
389
|
+
when ConstNode
|
390
|
+
elements << receiver_node.name
|
391
|
+
break
|
392
|
+
when CallNode
|
393
|
+
elements.unshift(receiver.name)
|
394
|
+
receiver = receiver.receiver_node
|
395
|
+
when SymbolNode
|
396
|
+
elements.unshift(receiver.name)
|
397
|
+
break
|
398
|
+
when VCallNode
|
399
|
+
elements.unshift(receiver.name)
|
400
|
+
break
|
401
|
+
when GlobalVarNode
|
402
|
+
elements.unshift(receiver.name[1..-1])
|
403
|
+
break
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# join and load
|
408
|
+
class_name = elements.join(".")
|
409
|
+
AST::type(class_name, array)
|
410
|
+
end
|
411
|
+
|
412
|
+
def annotation(transformer, parent)
|
413
|
+
if name == '[]'
|
414
|
+
annotation = receiver_node.annotation(transformer, parent)
|
415
|
+
value = args_node[0]
|
416
|
+
case value
|
417
|
+
when HashNode
|
418
|
+
values = value.list_node
|
419
|
+
(0..(values.size / 2)).each do |i|
|
420
|
+
name = values.get(2 * i).name
|
421
|
+
value = values.get(2 * i + 1)
|
422
|
+
annotation[name] = transformer.transform(value, annotation)
|
423
|
+
end
|
424
|
+
when nil
|
425
|
+
# ignore an empty argument list
|
426
|
+
else
|
427
|
+
annotation['value'] = transformer.transform(value, annotation)
|
428
|
+
end
|
429
|
+
annotation
|
430
|
+
else
|
431
|
+
klass = type_reference(parent)
|
432
|
+
Annotation.new(parent, position, klass)
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def annotation?
|
437
|
+
if name == '[]'
|
438
|
+
receiver = receiver_node
|
439
|
+
else
|
440
|
+
receiver = self
|
441
|
+
end
|
442
|
+
receiver = receiver.receiver_node while CallNode === receiver
|
443
|
+
GlobalVarNode === receiver
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
class Colon2Node
|
448
|
+
end
|
449
|
+
|
450
|
+
class ConstNode
|
451
|
+
def transform(transformer, parent)
|
452
|
+
Constant.new(parent, position, name)
|
453
|
+
end
|
454
|
+
|
455
|
+
def type_reference(parent)
|
456
|
+
AST::type(name, false, false)
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
class DefnNode
|
461
|
+
def transform(transformer, parent)
|
462
|
+
actual_name = name
|
463
|
+
if name =~ /=$/
|
464
|
+
actual_name = name[0..-2] + '_set'
|
465
|
+
end
|
466
|
+
if name == 'initialize'
|
467
|
+
klass = ConstructorDefinition
|
468
|
+
else
|
469
|
+
klass = MethodDefinition
|
470
|
+
end
|
471
|
+
klass.new(parent,
|
472
|
+
position,
|
473
|
+
actual_name,
|
474
|
+
transformer.annotations) do |defn|
|
475
|
+
signature = {:return => nil}
|
476
|
+
|
477
|
+
if args_node && args_node.args
|
478
|
+
args_node.args.child_nodes.each do |arg|
|
479
|
+
if arg.respond_to?(:type_node) && arg.type_node.respond_to?(:type_reference)
|
480
|
+
signature[arg.name.intern] =
|
481
|
+
arg.type_node.type_reference(parent)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
if body_node
|
486
|
+
for node in body_node.child_nodes
|
487
|
+
sig = node.signature(defn)
|
488
|
+
break unless sig
|
489
|
+
signature.update(sig) if sig.kind_of? ::Hash
|
490
|
+
end
|
491
|
+
end
|
492
|
+
[
|
493
|
+
signature,
|
494
|
+
args_node ? transformer.transform(args_node, defn) : nil,
|
495
|
+
body_node ? transformer.transform(body_node, defn) : nil
|
496
|
+
]
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
class DefsNode
|
502
|
+
def transform(transformer, parent)
|
503
|
+
actual_name = name
|
504
|
+
if name =~ /=$/
|
505
|
+
actual_name = name[0..-2] + '_set'
|
506
|
+
end
|
507
|
+
StaticMethodDefinition.new(parent,
|
508
|
+
position,
|
509
|
+
actual_name,
|
510
|
+
transformer.annotations) do |defn|
|
511
|
+
signature = {:return => nil}
|
512
|
+
if args_node && args_node.args
|
513
|
+
args_node.args.child_nodes.each do |arg|
|
514
|
+
if arg.respond_to? :type_node
|
515
|
+
signature[arg.name.intern] =
|
516
|
+
arg.type_node.type_reference(parent)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
if body_node
|
521
|
+
for node in body_node.child_nodes
|
522
|
+
sig = node.signature(defn)
|
523
|
+
break unless sig
|
524
|
+
signature.update(sig) if sig.kind_of? ::Hash
|
525
|
+
end
|
526
|
+
end
|
527
|
+
[
|
528
|
+
signature,
|
529
|
+
args_node ? transformer.transform(args_node, defn) : nil,
|
530
|
+
body_node ? transformer.transform(body_node, defn) : nil
|
531
|
+
]
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
class FalseNode
|
537
|
+
def transform(transformer, parent)
|
538
|
+
Boolean.new(parent, position, false)
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
class FCallNode
|
543
|
+
def signature(parent)
|
544
|
+
case name
|
545
|
+
when "returns"
|
546
|
+
@declaration = true
|
547
|
+
{:return => args_node.get(0).type_reference(parent)}
|
548
|
+
when "throws"
|
549
|
+
@declaration = true
|
550
|
+
exceptions = args_node.child_nodes.map do |node|
|
551
|
+
node.type_reference(parent)
|
552
|
+
end
|
553
|
+
{:throws => exceptions}
|
554
|
+
else
|
555
|
+
nil
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
def transform(transformer, parent)
|
560
|
+
@declaration ||= false
|
561
|
+
|
562
|
+
if @declaration
|
563
|
+
return Noop.new(parent, position)
|
564
|
+
end
|
565
|
+
|
566
|
+
macro = AST.macro(name)
|
567
|
+
if macro
|
568
|
+
transformer.expand(self, parent, ¯o)
|
569
|
+
else
|
570
|
+
FunctionalCall.new(parent, position, name) do |call|
|
571
|
+
[
|
572
|
+
args_node ? args_node.child_nodes.map {|arg| transformer.transform(arg, call)} : [],
|
573
|
+
iter_node ? transformer.transform(iter_node, call) : nil
|
574
|
+
]
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
def type_reference(parent)
|
580
|
+
AST::type(name)
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
class FixnumNode
|
585
|
+
def transform(transformer, parent)
|
586
|
+
AST::fixnum(parent, position, value)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
class FloatNode
|
591
|
+
def transform(transformer, parent)
|
592
|
+
AST::float(parent, position, value)
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
class HashNode
|
597
|
+
def transform(transformer, parent)
|
598
|
+
@declaration ||= false
|
599
|
+
|
600
|
+
if @declaration
|
601
|
+
Noop.new(parent, position)
|
602
|
+
else
|
603
|
+
super
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
# Create a signature definition using a literal hash syntax
|
608
|
+
def signature(parent)
|
609
|
+
# flag this as a declaration, so it transforms to a noop
|
610
|
+
@declaration = true
|
611
|
+
|
612
|
+
arg_types = {:return => nil}
|
613
|
+
|
614
|
+
list = list_node.child_nodes.to_a
|
615
|
+
list.each_index do |index|
|
616
|
+
if index % 2 == 0
|
617
|
+
if SymbolNode === list[index] && list[index].name == 'return'
|
618
|
+
arg_types[:return] = list[index + 1].type_reference(parent)
|
619
|
+
else
|
620
|
+
arg_types[list[index].name.intern] = list[index + 1].type_reference(parent)
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
624
|
+
return arg_types
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
class IfNode
|
629
|
+
def transform(transformer, parent)
|
630
|
+
If.new(parent, position) do |iff|
|
631
|
+
[
|
632
|
+
Condition.new(iff, condition.position) {|cond| [transformer.transform(condition, cond)]},
|
633
|
+
then_body ? transformer.transform(then_body, iff) : nil,
|
634
|
+
else_body ? transformer.transform(else_body, iff) : nil
|
635
|
+
]
|
636
|
+
end
|
637
|
+
end
|
638
|
+
end
|
639
|
+
|
640
|
+
class AndNode
|
641
|
+
def transform(transformer, parent)
|
642
|
+
If.new(parent, position) do |iff|
|
643
|
+
[
|
644
|
+
Condition.new(iff, first_node.position) {|cond| [transformer.transform(first_node, cond)]},
|
645
|
+
transformer.transform(second_node, iff),
|
646
|
+
nil
|
647
|
+
]
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
class OpAsgnAndNode
|
653
|
+
def transform(transformer, parent)
|
654
|
+
transformer.transform(
|
655
|
+
AndNode.new(position, first_node, second_node), parent)
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
class OrNode
|
660
|
+
def transform(transformer, parent)
|
661
|
+
Body.new(parent, position) do |block|
|
662
|
+
temp = transformer.tmp
|
663
|
+
[
|
664
|
+
LocalAssignment.new(block, first_node.position, temp) do |l|
|
665
|
+
[transformer.transform(first_node, l)]
|
666
|
+
end,
|
667
|
+
If.new(parent, position) do |iff|
|
668
|
+
[
|
669
|
+
Condition.new(iff, first_node.position) do |cond|
|
670
|
+
[Local.new(cond, first_node.position, temp)]
|
671
|
+
end,
|
672
|
+
Local.new(iff, first_node.position, temp),
|
673
|
+
transformer.transform(second_node, iff)
|
674
|
+
]
|
675
|
+
end
|
676
|
+
]
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
class OpAsgnOrNode
|
682
|
+
def transform(transformer, parent)
|
683
|
+
transformer.transform(
|
684
|
+
OrNode.new(position, first_node, second_node), parent)
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
class OpAsgnNode
|
689
|
+
include CallOpAssignment
|
690
|
+
def transform(transformer, parent)
|
691
|
+
call_op_assignment(transformer, parent,
|
692
|
+
variable_name, ListNode.new(position))
|
693
|
+
end
|
694
|
+
end
|
695
|
+
|
696
|
+
class OpElementAsgnNode
|
697
|
+
include CallOpAssignment
|
698
|
+
def transform(transformer, parent)
|
699
|
+
Body.new(parent, position) do |block|
|
700
|
+
temps = []
|
701
|
+
arg_init = args_node.map do |arg|
|
702
|
+
temps << transformer.tmp
|
703
|
+
LocalAssignment.new(block, arg.position, temps[-1]) do |l|
|
704
|
+
[transformer.transform(arg, l)]
|
705
|
+
end
|
706
|
+
end
|
707
|
+
args = ListNode.new(position)
|
708
|
+
args_node.zip(temps) do |arg, temp_name|
|
709
|
+
args.add(LocalVarNode.new(arg.position, 0, temp_name))
|
710
|
+
end
|
711
|
+
arg_init + [call_op_assignment(transformer, parent, '[]', args)]
|
712
|
+
end
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
class RescueNode
|
717
|
+
def transform(transformer, parent)
|
718
|
+
Rescue.new(parent, position) do |node|
|
719
|
+
[
|
720
|
+
transformer.transform(body_node, node),
|
721
|
+
rescue_node ? transformer.transform(rescue_node, node) : []
|
722
|
+
]
|
723
|
+
end
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
class RescueBodyNode
|
728
|
+
def transform(transformer, parent)
|
729
|
+
children = if opt_rescue_node
|
730
|
+
transformer.transform(opt_rescue_node, parent)
|
731
|
+
else
|
732
|
+
[]
|
733
|
+
end
|
734
|
+
[
|
735
|
+
RescueClause.new(parent, position) do |clause|
|
736
|
+
exceptions = if exception_nodes
|
737
|
+
exception_nodes.map {|e| e.type_reference(clause)}
|
738
|
+
else
|
739
|
+
[AST.type('java.lang.Exception')]
|
740
|
+
end
|
741
|
+
[
|
742
|
+
exceptions,
|
743
|
+
transformer.transform(body_node, clause)
|
744
|
+
]
|
745
|
+
end,
|
746
|
+
*children
|
747
|
+
]
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
class EnsureNode
|
752
|
+
def transform(transformer, parent)
|
753
|
+
Ensure.new(parent, position) do |node|
|
754
|
+
child_nodes.map {|c| transformer.transform(c, node)}
|
755
|
+
end
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
class NilImplicitNode
|
760
|
+
def transform(transformer, parent)
|
761
|
+
Noop.new(parent, position)
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
class NilNode
|
766
|
+
def transform(transformer, parent)
|
767
|
+
Null.new(parent, position)
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
class InstAsgnNode
|
772
|
+
def transform(transformer, parent)
|
773
|
+
case value_node
|
774
|
+
when SymbolNode, ConstNode
|
775
|
+
FieldDeclaration.new(parent, position,
|
776
|
+
name, transformer.annotations) do |field_decl|
|
777
|
+
[value_node.type_reference(field_decl)]
|
778
|
+
end
|
779
|
+
else
|
780
|
+
FieldAssignment.new(parent, position, name, transformer.annotations) {|field| [transformer.transform(value_node, field)]}
|
781
|
+
end
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
class InstVarNode
|
786
|
+
def transform(transformer, parent)
|
787
|
+
Field.new(parent, position, name, transformer.annotations)
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
class LocalAsgnNode
|
792
|
+
def transform(transformer, parent)
|
793
|
+
captured = transformer.captured?(self)
|
794
|
+
case value_node
|
795
|
+
when SymbolNode, ConstNode
|
796
|
+
LocalDeclaration.new(parent, position, name, captured) {|local_decl| [value_node.type_reference(local_decl)]}
|
797
|
+
when JRubyAst::GlobalVarNode
|
798
|
+
real_parent = parent
|
799
|
+
real_parent = parent.parent if Body === real_parent
|
800
|
+
if value_node.name == '$!' && RescueClause === real_parent
|
801
|
+
real_parent.name = name
|
802
|
+
Noop.new(parent, position)
|
803
|
+
else
|
804
|
+
raise "Illegal global variable"
|
805
|
+
end
|
806
|
+
else
|
807
|
+
LocalAssignment.new(parent, position, name, captured) {|local| [transformer.transform(value_node, local)]}
|
808
|
+
end
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
class LocalVarNode
|
813
|
+
def transform(transformer, parent)
|
814
|
+
Local.new(parent, position, name, transformer.captured?(self))
|
815
|
+
end
|
816
|
+
end
|
817
|
+
|
818
|
+
class ModuleNode
|
819
|
+
end
|
820
|
+
|
821
|
+
class NewlineNode
|
822
|
+
def transform(transformer, parent)
|
823
|
+
actual = transformer.transform(next_node, parent)
|
824
|
+
actual.newline = true
|
825
|
+
actual
|
826
|
+
end
|
827
|
+
|
828
|
+
# newlines are bypassed during signature transformation
|
829
|
+
def signature(parent)
|
830
|
+
next_node.signature(parent)
|
831
|
+
end
|
832
|
+
end
|
833
|
+
|
834
|
+
class NextNode
|
835
|
+
def transform(transformer, parent)
|
836
|
+
# TODO support 'next value'?
|
837
|
+
Next.new(parent, position)
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
class NotNode
|
842
|
+
def transform(transformer, parent)
|
843
|
+
Not.new(parent, position) {|nott| [transformer.transform(condition_node, nott)]}
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
847
|
+
class RedoNode
|
848
|
+
def transform(transformer, parent)
|
849
|
+
Redo.new(parent, position)
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
class ReturnNode
|
854
|
+
def transform(transformer, parent)
|
855
|
+
Return.new(parent, position) do |ret|
|
856
|
+
[transformer.transform(value_node, ret)]
|
857
|
+
end
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
861
|
+
class RootNode
|
862
|
+
def getScope
|
863
|
+
getStaticScope
|
864
|
+
end
|
865
|
+
|
866
|
+
def transform(transformer, parent)
|
867
|
+
Script.new(parent, position) {|script| [transformer.transform(child_nodes[0], script)]}
|
868
|
+
end
|
869
|
+
end
|
870
|
+
|
871
|
+
class SelfNode
|
872
|
+
end
|
873
|
+
|
874
|
+
class StrNode
|
875
|
+
def transform(transformer, parent)
|
876
|
+
String.new(parent, position, value)
|
877
|
+
end
|
878
|
+
|
879
|
+
def type_reference(parent)
|
880
|
+
AST::type(value)
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
class SymbolNode
|
885
|
+
def type_reference(parent)
|
886
|
+
AST::type(name)
|
887
|
+
end
|
888
|
+
end
|
889
|
+
|
890
|
+
class TrueNode
|
891
|
+
def transform(transformer, parent)
|
892
|
+
Boolean.new(parent, position, true)
|
893
|
+
end
|
894
|
+
end
|
895
|
+
|
896
|
+
class TypedArgumentNode
|
897
|
+
def transform(transformer, parent)
|
898
|
+
type_node.transform(transformer, parent)
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
class VCallNode
|
903
|
+
def transform(transformer, parent)
|
904
|
+
if name == 'raise'
|
905
|
+
Raise.new(parent, position) do
|
906
|
+
[]
|
907
|
+
end
|
908
|
+
elsif name == 'null'
|
909
|
+
Null.new(parent, position)
|
910
|
+
else
|
911
|
+
macro = AST.macro(name)
|
912
|
+
if macro
|
913
|
+
transformer.expand(self, parent, ¯o)
|
914
|
+
else
|
915
|
+
FunctionalCall.new(parent, position, name) do |call|
|
916
|
+
[
|
917
|
+
[],
|
918
|
+
nil
|
919
|
+
]
|
920
|
+
end
|
921
|
+
end
|
922
|
+
end
|
923
|
+
end
|
924
|
+
|
925
|
+
def type_reference(parent)
|
926
|
+
AST::type name
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
930
|
+
class WhileNode
|
931
|
+
def transform(transformer, parent)
|
932
|
+
Loop.new(parent, position, evaluate_at_start, false) do |loop|
|
933
|
+
[
|
934
|
+
Condition.new(loop, condition_node.position) {|cond| [transformer.transform(condition_node, cond)]},
|
935
|
+
transformer.transform(body_node, loop)
|
936
|
+
]
|
937
|
+
end
|
938
|
+
end
|
939
|
+
end
|
940
|
+
|
941
|
+
class UntilNode
|
942
|
+
def transform(transformer, parent)
|
943
|
+
Loop.new(parent, position, evaluate_at_start, true) do |loop|
|
944
|
+
[
|
945
|
+
Condition.new(loop, condition_node.position) {|cond| [transformer.transform(condition_node, cond)]},
|
946
|
+
transformer.transform(body_node, loop)
|
947
|
+
]
|
948
|
+
end
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
class DVarNode
|
953
|
+
def transform(transformer, parent)
|
954
|
+
# TODO does this need to be handled specially?
|
955
|
+
Local.new(parent, position, name, transformer.captured?(self))
|
956
|
+
end
|
957
|
+
end
|
958
|
+
|
959
|
+
class DAsgnNode
|
960
|
+
def transform(transformer, parent)
|
961
|
+
captured = transformer.captured?(self)
|
962
|
+
case value_node
|
963
|
+
when SymbolNode, ConstNode
|
964
|
+
LocalDeclaration.new(parent, position, name, captured) {|local_decl| [value_node.type_reference(local_decl)]}
|
965
|
+
else
|
966
|
+
LocalAssignment.new(parent, position, name, captured) {|local| [transformer.transform(value_node, local)]}
|
967
|
+
end
|
968
|
+
end
|
969
|
+
end
|
970
|
+
|
971
|
+
class IterNode
|
972
|
+
def transform(transformer, parent)
|
973
|
+
Block.new(parent, position) do |block|
|
974
|
+
[
|
975
|
+
transformer.transform(var_node, block),
|
976
|
+
transformer.transform(body_node, block)
|
977
|
+
]
|
978
|
+
end
|
979
|
+
end
|
980
|
+
end
|
981
|
+
|
982
|
+
class ForNode
|
983
|
+
def transform(transformer, parent)
|
984
|
+
Call.new(parent, position, 'each') do |each|
|
985
|
+
[
|
986
|
+
transformer.transform(iter_node, each),
|
987
|
+
[],
|
988
|
+
Block.new(each, body_node.position) do |block|
|
989
|
+
[
|
990
|
+
Arguments.new(block, var_node.position) do |args|
|
991
|
+
[
|
992
|
+
# TODO support for multiple assignment?
|
993
|
+
[RequiredArgument.new(args,
|
994
|
+
var_node.position,
|
995
|
+
var_node.name)
|
996
|
+
]
|
997
|
+
]
|
998
|
+
end,
|
999
|
+
transformer.transform(body_node, block)
|
1000
|
+
]
|
1001
|
+
end
|
1002
|
+
]
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
class SuperNode
|
1008
|
+
def transform(transformer, parent)
|
1009
|
+
Super.new(parent, position) do
|
1010
|
+
[args_node ? args_node.map {|arg| transformer.transform(arg, parent)} : []]
|
1011
|
+
end
|
1012
|
+
end
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
class ZSuperNode
|
1016
|
+
def transform(transformer, parent)
|
1017
|
+
Super.new(parent, position)
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
class SelfNode
|
1022
|
+
def transform(transformer, parent)
|
1023
|
+
Self.new(parent, position)
|
1024
|
+
end
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
end
|
1028
|
+
end
|