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,387 @@
|
|
1
|
+
require 'duby/jvm/types'
|
2
|
+
|
3
|
+
module Duby
|
4
|
+
class JVM::Types::Type
|
5
|
+
def to_source
|
6
|
+
"#{name}#{'[]' if array?}"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module JavaSource
|
11
|
+
JVMTypes ||= Duby::JVM::Types
|
12
|
+
|
13
|
+
class Builder
|
14
|
+
attr_accessor :package, :classes, :filename, :compiler
|
15
|
+
|
16
|
+
def initialize(filename, compiler)
|
17
|
+
@filename = filename
|
18
|
+
@classes = []
|
19
|
+
@compiler = compiler
|
20
|
+
end
|
21
|
+
|
22
|
+
def public_class(name, superclass=nil, *interfaces)
|
23
|
+
cls = ClassBuilder.new(self, name, superclass, interfaces)
|
24
|
+
@classes << cls
|
25
|
+
cls
|
26
|
+
end
|
27
|
+
|
28
|
+
def public_interface(name, *interfaces)
|
29
|
+
cls = InterfaceBuilder.new(self, name, interfaces)
|
30
|
+
@classes << cls
|
31
|
+
cls
|
32
|
+
end
|
33
|
+
|
34
|
+
def generate
|
35
|
+
@classes.each do |cls|
|
36
|
+
yield cls.filename, cls
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Output
|
42
|
+
def initialize
|
43
|
+
@out = ""
|
44
|
+
@indent = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def puts(*lines)
|
48
|
+
lines.each do |line|
|
49
|
+
print_indent
|
50
|
+
@out << line.to_s
|
51
|
+
@out << "\n"
|
52
|
+
@indented = false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def print_indent
|
57
|
+
@indent ||= 0
|
58
|
+
@out << (' ' * @indent) unless @indented
|
59
|
+
@indented = true
|
60
|
+
end
|
61
|
+
|
62
|
+
def print(str)
|
63
|
+
print_indent
|
64
|
+
@out << str.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
def indent
|
68
|
+
@indent += 2
|
69
|
+
end
|
70
|
+
|
71
|
+
def dedent
|
72
|
+
@indent -= 2
|
73
|
+
end
|
74
|
+
|
75
|
+
def <<(other)
|
76
|
+
other.to_s.each_line do |line|
|
77
|
+
print_indent
|
78
|
+
print(line)
|
79
|
+
@indented = false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_s
|
84
|
+
@out
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module Helper
|
89
|
+
def puts(*args)
|
90
|
+
@out.puts(*args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def print(*args)
|
94
|
+
@out.print(*args)
|
95
|
+
end
|
96
|
+
|
97
|
+
def indent
|
98
|
+
@out.indent
|
99
|
+
end
|
100
|
+
|
101
|
+
def dedent
|
102
|
+
@out.dedent
|
103
|
+
end
|
104
|
+
|
105
|
+
def block(line='')
|
106
|
+
puts line + " {"
|
107
|
+
indent
|
108
|
+
yield
|
109
|
+
dedent
|
110
|
+
puts "}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def init_value(type)
|
114
|
+
# TODO move this to types?
|
115
|
+
case type
|
116
|
+
when JVMTypes::Boolean
|
117
|
+
'false'
|
118
|
+
when JVMTypes::PrimitiveType, JVMTypes::NarrowingType
|
119
|
+
'0'
|
120
|
+
else
|
121
|
+
'null'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def annotate(annotations)
|
126
|
+
annotations.each do |annotation|
|
127
|
+
# TODO values
|
128
|
+
puts "@#{annotation.name}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class ClassBuilder
|
134
|
+
include Helper
|
135
|
+
include Duby::Compiler::JVM::JVMLogger
|
136
|
+
attr_reader :package, :name, :superclass, :filename, :class_name, :out
|
137
|
+
attr_reader :interfaces
|
138
|
+
def initialize(builder, name, superclass, interfaces)
|
139
|
+
@builder = builder
|
140
|
+
@package = builder.package
|
141
|
+
if @package
|
142
|
+
@name = "#{@package}.#{name}"
|
143
|
+
else
|
144
|
+
@name = name
|
145
|
+
end
|
146
|
+
if name =~ %r{[/.]}
|
147
|
+
pieces = name.split(%r{[/.]})
|
148
|
+
name = pieces.pop
|
149
|
+
@package = pieces.join('.')
|
150
|
+
end
|
151
|
+
@class_name = name
|
152
|
+
@superclass = superclass || JVMTypes::Object
|
153
|
+
@interfaces = interfaces
|
154
|
+
@filename = "#{name}.java"
|
155
|
+
@filename = "#{package.tr('.', '/')}/#{@filename}" if @package
|
156
|
+
@out = Output.new
|
157
|
+
@stopped = false
|
158
|
+
@methods = []
|
159
|
+
@fields = {}
|
160
|
+
start
|
161
|
+
end
|
162
|
+
|
163
|
+
def compiler
|
164
|
+
@builder.compiler
|
165
|
+
end
|
166
|
+
|
167
|
+
def start
|
168
|
+
puts "// Generated from #{@builder.filename}"
|
169
|
+
puts "package #{package};" if package
|
170
|
+
end
|
171
|
+
|
172
|
+
def finish_declaration
|
173
|
+
return if @declaration_finished
|
174
|
+
@declaration_finished = true
|
175
|
+
print "public class #{class_name} extends #{superclass.name}"
|
176
|
+
unless @interfaces.empty?
|
177
|
+
print " implements "
|
178
|
+
@interfaces.each_with_index do |interface, index|
|
179
|
+
print ', ' unless index == 0
|
180
|
+
print interface.to_source
|
181
|
+
end
|
182
|
+
end
|
183
|
+
puts " {"
|
184
|
+
indent
|
185
|
+
end
|
186
|
+
|
187
|
+
def stop
|
188
|
+
finish_declaration
|
189
|
+
return if @stopped
|
190
|
+
@methods.each do |method|
|
191
|
+
@out << method.out
|
192
|
+
end
|
193
|
+
log "Class #{name} complete (#{@out.to_s.size})"
|
194
|
+
@stopped = true
|
195
|
+
dedent
|
196
|
+
puts "}"
|
197
|
+
log "Class #{name} complete (#{@out.to_s.size})"
|
198
|
+
end
|
199
|
+
|
200
|
+
def main
|
201
|
+
public_static_method('main', JVMTypes::Void, [],
|
202
|
+
[JVMTypes::String.array_type, 'argv'])
|
203
|
+
end
|
204
|
+
|
205
|
+
def declare_field(name, type, static, annotations=[])
|
206
|
+
finish_declaration
|
207
|
+
return if @fields[name]
|
208
|
+
static = static ? 'static' : ''
|
209
|
+
annotate(annotations)
|
210
|
+
puts "private #{static} #{type.to_source} #{name};"
|
211
|
+
@fields[name] = true
|
212
|
+
end
|
213
|
+
|
214
|
+
def public_method(name, type, exceptions, *args)
|
215
|
+
finish_declaration
|
216
|
+
@methods << MethodBuilder.new(self,
|
217
|
+
:name => name,
|
218
|
+
:return => type,
|
219
|
+
:args => args,
|
220
|
+
:exceptions => exceptions)
|
221
|
+
@methods[-1]
|
222
|
+
end
|
223
|
+
|
224
|
+
def public_static_method(name, type, exceptions, *args)
|
225
|
+
finish_declaration
|
226
|
+
@methods << MethodBuilder.new(self,
|
227
|
+
:name => name,
|
228
|
+
:return => type,
|
229
|
+
:args => args,
|
230
|
+
:static => true,
|
231
|
+
:exceptions => exceptions)
|
232
|
+
@methods[-1]
|
233
|
+
end
|
234
|
+
|
235
|
+
def public_constructor(exceptions, *args)
|
236
|
+
finish_declaration
|
237
|
+
@methods << MethodBuilder.new(self,
|
238
|
+
:name => class_name,
|
239
|
+
:args => args,
|
240
|
+
:exceptions => exceptions)
|
241
|
+
@methods[-1]
|
242
|
+
end
|
243
|
+
|
244
|
+
def generate
|
245
|
+
stop
|
246
|
+
@out.to_s
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
class InterfaceBuilder < ClassBuilder
|
251
|
+
def initialize(builder, name, interfaces)
|
252
|
+
super(builder, name, nil, interfaces)
|
253
|
+
end
|
254
|
+
|
255
|
+
def finish_declaration
|
256
|
+
return if @declaration_finished
|
257
|
+
@declaration_finished = true
|
258
|
+
print "public interface #{class_name}"
|
259
|
+
unless @interfaces.empty?
|
260
|
+
print " extends "
|
261
|
+
@interfaces.each_with_index do |interface, index|
|
262
|
+
print ', ' unless index == 0
|
263
|
+
print interface.to_source
|
264
|
+
end
|
265
|
+
end
|
266
|
+
puts " {"
|
267
|
+
indent
|
268
|
+
end
|
269
|
+
|
270
|
+
def public_method(name, type, exceptions, *args)
|
271
|
+
finish_declaration
|
272
|
+
@methods << MethodBuilder.new(self,
|
273
|
+
:name => name,
|
274
|
+
:return => type,
|
275
|
+
:args => args,
|
276
|
+
:abstract => true,
|
277
|
+
:exceptions => exceptions)
|
278
|
+
@methods[-1]
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
class MethodBuilder
|
283
|
+
include Helper
|
284
|
+
|
285
|
+
attr_accessor :name, :type, :out
|
286
|
+
|
287
|
+
def initialize(cls, options)
|
288
|
+
@class = cls
|
289
|
+
@compiler = cls.compiler
|
290
|
+
@out = Output.new
|
291
|
+
@name = options[:name]
|
292
|
+
@type = options[:return]
|
293
|
+
@typename = @type && @type.to_source
|
294
|
+
@locals = {}
|
295
|
+
@args = options[:args].map do |arg|
|
296
|
+
unless arg.kind_of? Array
|
297
|
+
arg = [arg.inferred_type, arg.name]
|
298
|
+
end
|
299
|
+
@locals[arg[1]] = arg[0]
|
300
|
+
arg
|
301
|
+
end
|
302
|
+
@static = options[:static] && ' static'
|
303
|
+
@abstract = options[:abstract] && ' abstract'
|
304
|
+
@exceptions = options[:exceptions] || []
|
305
|
+
@temps = 0
|
306
|
+
end
|
307
|
+
|
308
|
+
def start
|
309
|
+
print "public#{@static}#{@abstract} #{@typename} #{@name}("
|
310
|
+
@args.each_with_index do |(type, name), i|
|
311
|
+
print ', ' unless i == 0
|
312
|
+
print "#{type.to_source} #{name}"
|
313
|
+
end
|
314
|
+
print ')'
|
315
|
+
unless @exceptions.empty?
|
316
|
+
print ' throws '
|
317
|
+
@exceptions.each_with_index do |exception, i|
|
318
|
+
print ', ' unless i == 0
|
319
|
+
print exception.name
|
320
|
+
end
|
321
|
+
end
|
322
|
+
if @abstract
|
323
|
+
puts ";"
|
324
|
+
def self.puts(*args); end
|
325
|
+
def self.print(*args); end
|
326
|
+
else
|
327
|
+
puts " {"
|
328
|
+
end
|
329
|
+
indent
|
330
|
+
end
|
331
|
+
|
332
|
+
def stop
|
333
|
+
dedent
|
334
|
+
puts "}"
|
335
|
+
end
|
336
|
+
|
337
|
+
def declare_local(type, name)
|
338
|
+
unless @locals[name]
|
339
|
+
print "#{type.to_source} #{name} = "
|
340
|
+
if block_given?
|
341
|
+
yield self
|
342
|
+
else
|
343
|
+
print init_value(type)
|
344
|
+
end
|
345
|
+
puts ';'
|
346
|
+
@locals[name] = type
|
347
|
+
end
|
348
|
+
name
|
349
|
+
end
|
350
|
+
|
351
|
+
def local?(name)
|
352
|
+
!!@locals[name]
|
353
|
+
end
|
354
|
+
|
355
|
+
def tmp(type)
|
356
|
+
@temps += 1
|
357
|
+
declare_local(type, "temp$#{@temps}")
|
358
|
+
end
|
359
|
+
|
360
|
+
def label
|
361
|
+
@temps += 1
|
362
|
+
"label#{@temps}"
|
363
|
+
end
|
364
|
+
|
365
|
+
def push_int(value)
|
366
|
+
print value
|
367
|
+
end
|
368
|
+
|
369
|
+
def ldc_float(value)
|
370
|
+
print "(float)#{value}"
|
371
|
+
end
|
372
|
+
|
373
|
+
def ldc_double(value)
|
374
|
+
print value
|
375
|
+
end
|
376
|
+
|
377
|
+
def method_missing(name, *args)
|
378
|
+
if name.to_s =~ /.const_(m)?(\d)/
|
379
|
+
print '-' if $1
|
380
|
+
print $2
|
381
|
+
else
|
382
|
+
super
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
class Duby::Compiler::JavaSource
|
2
|
+
class SimpleWhileLoop
|
3
|
+
attr_reader :compiler, :loop
|
4
|
+
def initialize(loop, compiler)
|
5
|
+
@loop = loop
|
6
|
+
@compiler = compiler
|
7
|
+
end
|
8
|
+
|
9
|
+
def break
|
10
|
+
compiler.method.puts "break;"
|
11
|
+
end
|
12
|
+
|
13
|
+
def next
|
14
|
+
compiler.method.puts "continue;"
|
15
|
+
end
|
16
|
+
|
17
|
+
def redo
|
18
|
+
raise "#{self.class.name} doesn't support redo"
|
19
|
+
end
|
20
|
+
|
21
|
+
def compile(expression)
|
22
|
+
prepare
|
23
|
+
@loop.init.compile(compiler, false) if @loop.init?
|
24
|
+
@start.call
|
25
|
+
compiler.method.block do
|
26
|
+
@loop.pre.compile(compiler, false) if @loop.pre?
|
27
|
+
compile_body
|
28
|
+
@loop.post.compile(compiler, false) if @loop.post?
|
29
|
+
end
|
30
|
+
if @end_check
|
31
|
+
@end_check.call
|
32
|
+
compiler.method.puts ';'
|
33
|
+
end
|
34
|
+
if expression
|
35
|
+
compiler.method.puts "#{compiler.lvalue}null;"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def compile_body
|
40
|
+
loop.body.compile(compiler, false)
|
41
|
+
end
|
42
|
+
|
43
|
+
def prepare
|
44
|
+
predicate = loop.condition.predicate.precompile(compiler)
|
45
|
+
negative = loop.negative ? '!' : ''
|
46
|
+
check = lambda do
|
47
|
+
compiler.method.print "while (#{negative}"
|
48
|
+
predicate.compile(compiler, true)
|
49
|
+
compiler.method.print ')'
|
50
|
+
end
|
51
|
+
if loop.check_first
|
52
|
+
@start = check
|
53
|
+
else
|
54
|
+
@start = lambda {compiler.method.print 'do'}
|
55
|
+
@end_check = check
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module Redoable
|
61
|
+
def compile_with_redo(block)
|
62
|
+
@redo = compiler.method.tmp(JVMTypes::Boolean)
|
63
|
+
compiler.method.puts "#{@inner}:"
|
64
|
+
compiler.method.block "do" do
|
65
|
+
compiler.method.puts "#{@redo} = false;"
|
66
|
+
block.compile(compiler, false)
|
67
|
+
end
|
68
|
+
compiler.method.puts "while (#{@redo});"
|
69
|
+
end
|
70
|
+
|
71
|
+
def break
|
72
|
+
compiler.method.puts "break #{@outer};"
|
73
|
+
end
|
74
|
+
|
75
|
+
def next
|
76
|
+
compiler.method.puts "break #{@inner};"
|
77
|
+
end
|
78
|
+
|
79
|
+
def redo
|
80
|
+
compiler.method.puts "#{@redo} = true;"
|
81
|
+
compiler.method.puts "continue #{@inner};"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class ComplexWhileLoop < SimpleWhileLoop
|
86
|
+
include Redoable
|
87
|
+
def prepare
|
88
|
+
super
|
89
|
+
@outer = compiler.method.label
|
90
|
+
@inner = compiler.method.label
|
91
|
+
@complex_predicate = !loop.condition.predicate.expr?(compiler)
|
92
|
+
super_start = @start
|
93
|
+
@start = lambda do
|
94
|
+
compiler.method.puts "#{@outer}:"
|
95
|
+
super_start.call
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def compile_body
|
100
|
+
if @loop.redo?
|
101
|
+
compile_with_redo(@loop.body)
|
102
|
+
else
|
103
|
+
compiler.method.puts "#{@inner}:"
|
104
|
+
compiler.method.block do
|
105
|
+
loop.body.compile(compiler, false)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|