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