duby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/examples/swing.duby
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
import javax.swing.JFrame
|
2
|
+
import javax.swing.JButton
|
3
|
+
import java.awt.event.ActionListener
|
4
|
+
|
5
|
+
frame = JFrame.new "Welcome to Duby"
|
6
|
+
frame.setSize 300, 300
|
7
|
+
frame.setVisible true
|
8
|
+
|
9
|
+
button = JButton.new "Press me"
|
10
|
+
frame.add button
|
11
|
+
frame.show
|
12
|
+
|
13
|
+
class AL; implements ActionListener
|
14
|
+
def initialize; end
|
15
|
+
def actionPerformed(event)
|
16
|
+
JButton(event.getSource).setText "Duby Rocks!"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
button.addActionListener AL.new
|
data/examples/tak.duby
ADDED
Binary file
|
data/lib/duby.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'duby/transform'
|
3
|
+
require 'duby/ast'
|
4
|
+
require 'duby/typer'
|
5
|
+
require 'duby/compiler'
|
6
|
+
begin
|
7
|
+
require 'bitescript'
|
8
|
+
rescue LoadError
|
9
|
+
$: << File.dirname(__FILE__) + '/../../bitescript/lib'
|
10
|
+
require 'bitescript'
|
11
|
+
end
|
12
|
+
require 'duby/jvm/compiler'
|
13
|
+
require 'duby/jvm/typer'
|
14
|
+
Dir[File.dirname(__FILE__) + "/duby/plugin/*"].each {|file| require "#{file}" if file =~ /\.rb$/}
|
15
|
+
require 'jruby'
|
16
|
+
|
17
|
+
module Duby
|
18
|
+
VERSION = '0.0.1'
|
19
|
+
|
20
|
+
def self.run(*args)
|
21
|
+
DubyImpl.new.run(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.compile(*args)
|
25
|
+
DubyImpl.new.compile(*args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.parse(*args)
|
29
|
+
DubyImpl.new.parse(*args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class DubyImpl
|
34
|
+
def run(*args)
|
35
|
+
ast = parse(*args)
|
36
|
+
|
37
|
+
main_cls = nil
|
38
|
+
compile_ast(ast) do |outfile, builder|
|
39
|
+
bytes = builder.generate
|
40
|
+
name = builder.class_name.gsub(/\//, '.')
|
41
|
+
cls = JRuby.runtime.jruby_class_loader.define_class(name, bytes.to_java_bytes)
|
42
|
+
proxy_cls = JavaUtilities.get_proxy_class(name)
|
43
|
+
# TODO: using first main; find correct one
|
44
|
+
if proxy_cls.respond_to? :main
|
45
|
+
main_cls ||= proxy_cls
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if main_cls
|
50
|
+
main_cls.main(args.to_java(:string))
|
51
|
+
else
|
52
|
+
puts "No main found"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def compile(*args)
|
57
|
+
process_flags!(args)
|
58
|
+
|
59
|
+
expand_files(args).each do |duby_file|
|
60
|
+
if duby_file == '-e'
|
61
|
+
@filename = '-e'
|
62
|
+
next
|
63
|
+
elsif @filename == '-e'
|
64
|
+
ast = parse('-e', duby_file)
|
65
|
+
else
|
66
|
+
ast = parse(duby_file)
|
67
|
+
end
|
68
|
+
exit 1 if @error
|
69
|
+
|
70
|
+
compile_ast(ast) do |filename, builder|
|
71
|
+
filename = "#{@dest}#{filename}"
|
72
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
73
|
+
bytes = builder.generate
|
74
|
+
File.open(filename, 'w') {|f| f.write(bytes)}
|
75
|
+
end
|
76
|
+
@filename = nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse(*args)
|
81
|
+
process_flags!(args)
|
82
|
+
@filename = args.shift
|
83
|
+
|
84
|
+
if @filename == '-e'
|
85
|
+
@filename = 'dash_e'
|
86
|
+
src = args[0]
|
87
|
+
else
|
88
|
+
src = File.read(@filename)
|
89
|
+
end
|
90
|
+
Duby::AST.type_factory = Duby::JVM::Types::TypeFactory.new(@filename)
|
91
|
+
ast = Duby::AST.parse_ruby(src, @filename)
|
92
|
+
@transformer = Duby::Transform::Transformer.new
|
93
|
+
ast = @transformer.transform(ast, nil)
|
94
|
+
@transformer.errors.each do |ex|
|
95
|
+
raise ex.cause || ex if @verbose
|
96
|
+
puts "#@filename:#{ex.position.start_line+1}: #{ex.message}"
|
97
|
+
end
|
98
|
+
@error = @transformer.errors.size > 0
|
99
|
+
ast
|
100
|
+
end
|
101
|
+
|
102
|
+
def compile_ast(ast, &block)
|
103
|
+
typer = Duby::Typer::JVM.new(@filename)
|
104
|
+
typer.infer(ast)
|
105
|
+
begin
|
106
|
+
typer.resolve(true)
|
107
|
+
ensure
|
108
|
+
typer.errors.each do |ex|
|
109
|
+
puts ex.message
|
110
|
+
puts ex.backtrace if @verbose
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
compiler = @compiler_class.new(@filename)
|
115
|
+
ast.compile(compiler, false)
|
116
|
+
compiler.generate(&block)
|
117
|
+
end
|
118
|
+
|
119
|
+
def process_flags!(args)
|
120
|
+
while args.length > 0
|
121
|
+
case args[0]
|
122
|
+
when '-V'
|
123
|
+
Duby::Typer.verbose = true
|
124
|
+
Duby::AST.verbose = true
|
125
|
+
Duby::Compiler::JVM.verbose = true
|
126
|
+
@verbose = true
|
127
|
+
args.shift
|
128
|
+
when '-java'
|
129
|
+
require 'duby/jvm/source_compiler'
|
130
|
+
@compiler_class = Duby::Compiler::JavaSource
|
131
|
+
args.shift
|
132
|
+
when '-d'
|
133
|
+
args.shift
|
134
|
+
@dest = File.join(args.shift, '')
|
135
|
+
when '-p'
|
136
|
+
args.shift
|
137
|
+
plugin = args.shift
|
138
|
+
require "duby/plugin/#{plugin}"
|
139
|
+
when '-I'
|
140
|
+
args.shift
|
141
|
+
$: << args.shift
|
142
|
+
else
|
143
|
+
break
|
144
|
+
end
|
145
|
+
end
|
146
|
+
@compiler_class ||= Duby::Compiler::JVM
|
147
|
+
end
|
148
|
+
|
149
|
+
def expand_files(files)
|
150
|
+
expanded = []
|
151
|
+
files.each do |filename|
|
152
|
+
if File.directory?(filename)
|
153
|
+
Dir[File.join(filename, '*')].each do |child|
|
154
|
+
if File.directory?(child)
|
155
|
+
files << child
|
156
|
+
elsif child =~ /\.duby$/
|
157
|
+
expanded << child
|
158
|
+
end
|
159
|
+
end
|
160
|
+
else
|
161
|
+
expanded << filename
|
162
|
+
end
|
163
|
+
end
|
164
|
+
expanded
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
if __FILE__ == $0
|
169
|
+
Duby.run(ARGV[0], *ARGV[1..-1])
|
170
|
+
end
|
data/lib/duby/ast.rb
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
require 'duby/transform'
|
2
|
+
|
3
|
+
module Duby
|
4
|
+
module AST
|
5
|
+
class << self
|
6
|
+
attr_accessor :verbose
|
7
|
+
end
|
8
|
+
|
9
|
+
# The top of the AST class hierarchy, this represents an abstract AST node.
|
10
|
+
# It provides accessors for _children_, an array of all child nodes,
|
11
|
+
# _parent_, a reference to this node's parent (nil if none), and _newline_,
|
12
|
+
# whether this node represents a new line.
|
13
|
+
class Node
|
14
|
+
attr_accessor :children
|
15
|
+
attr_accessor :parent
|
16
|
+
attr_accessor :position
|
17
|
+
attr_accessor :newline
|
18
|
+
attr_accessor :inferred_type
|
19
|
+
|
20
|
+
def initialize(parent, position, children = [])
|
21
|
+
@parent = parent
|
22
|
+
@newline = false
|
23
|
+
@inferred_type = nil
|
24
|
+
@resolved = false
|
25
|
+
@position = position
|
26
|
+
if block_given?
|
27
|
+
@children = yield(self) || []
|
28
|
+
else
|
29
|
+
@children = children
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def line_number
|
34
|
+
if @position
|
35
|
+
@position.start_line + 1
|
36
|
+
else
|
37
|
+
0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def log(message)
|
42
|
+
puts "* [AST] [#{simple_name}] " + message if AST.verbose
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect(indent = 0)
|
46
|
+
indent_str = ' ' * indent
|
47
|
+
str = indent_str + to_s
|
48
|
+
children.each do |child|
|
49
|
+
if child
|
50
|
+
if ::Array === child
|
51
|
+
child.each {|ary_child|
|
52
|
+
str << "\n#{ary_child.inspect(indent + 1)}"
|
53
|
+
}
|
54
|
+
elsif ::Hash === child
|
55
|
+
str << "\n#{indent_str} #{child.inspect}"
|
56
|
+
else
|
57
|
+
str << "\n#{child.inspect(indent + 1)}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
str
|
62
|
+
end
|
63
|
+
|
64
|
+
def simple_name
|
65
|
+
self.class.name.split("::")[-1]
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s; simple_name; end
|
69
|
+
|
70
|
+
def [](index) children[index] end
|
71
|
+
|
72
|
+
def each(&b) children.each(&b) end
|
73
|
+
|
74
|
+
def resolved!
|
75
|
+
log "#{to_s} resolved!"
|
76
|
+
@resolved = true
|
77
|
+
end
|
78
|
+
|
79
|
+
def resolved?; @resolved end
|
80
|
+
|
81
|
+
def resolve_if(typer)
|
82
|
+
unless resolved?
|
83
|
+
@inferred_type = yield
|
84
|
+
@inferred_type ? resolved! : typer.defer(self)
|
85
|
+
end
|
86
|
+
@inferred_type
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class ErrorNode < Node
|
91
|
+
def initialize(parent, error)
|
92
|
+
super(parent, error.position)
|
93
|
+
@error = error
|
94
|
+
@inferred_type = TypeReference::ErrorType
|
95
|
+
@resolved = true
|
96
|
+
end
|
97
|
+
|
98
|
+
def infer(typer)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
module Named
|
103
|
+
attr_accessor :name
|
104
|
+
|
105
|
+
def to_s
|
106
|
+
"#{super}(#{name})"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
module Typed
|
111
|
+
attr_accessor :type
|
112
|
+
end
|
113
|
+
|
114
|
+
module Valued
|
115
|
+
include Typed
|
116
|
+
attr_accessor :value
|
117
|
+
end
|
118
|
+
|
119
|
+
module Literal
|
120
|
+
include Typed
|
121
|
+
attr_accessor :literal
|
122
|
+
|
123
|
+
def to_s
|
124
|
+
"#{super}(#{literal.inspect})"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
module Scoped
|
129
|
+
def scope
|
130
|
+
@scope ||= begin
|
131
|
+
scope = parent
|
132
|
+
raise "No parent for #{self.class.name} at #{line_number}" if scope.nil?
|
133
|
+
scope = scope.parent until scope.class.include?(Scope)
|
134
|
+
scope
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
module ClassScoped
|
140
|
+
def scope
|
141
|
+
@scope ||= begin
|
142
|
+
scope = parent
|
143
|
+
scope = scope.parent until scope.nil? || ClassDefinition === scope
|
144
|
+
scope
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
module Scope; end
|
150
|
+
|
151
|
+
class Colon2 < Node; end
|
152
|
+
|
153
|
+
class Constant < Node
|
154
|
+
include Named
|
155
|
+
def initialize(parent, position, name)
|
156
|
+
@name = name
|
157
|
+
super(parent, position, [])
|
158
|
+
end
|
159
|
+
|
160
|
+
def infer(typer)
|
161
|
+
@inferred_type ||= begin
|
162
|
+
typer.type_reference(name, false, true)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class Self < Node; end
|
168
|
+
|
169
|
+
class VoidType < Node; end
|
170
|
+
|
171
|
+
class TypeReference < Node
|
172
|
+
include Named
|
173
|
+
attr_accessor :array
|
174
|
+
alias array? array
|
175
|
+
attr_accessor :meta
|
176
|
+
alias meta? meta
|
177
|
+
|
178
|
+
def initialize(name, array = false, meta = false, position=nil)
|
179
|
+
super(nil, position)
|
180
|
+
@name = name
|
181
|
+
@array = array
|
182
|
+
@meta = meta
|
183
|
+
end
|
184
|
+
|
185
|
+
def to_s
|
186
|
+
"Type(#{name}#{array? ? ' array' : ''}#{meta? ? ' meta' : ''})"
|
187
|
+
end
|
188
|
+
|
189
|
+
def ==(other)
|
190
|
+
to_s == other.to_s
|
191
|
+
end
|
192
|
+
|
193
|
+
def eql?(other)
|
194
|
+
self == other
|
195
|
+
end
|
196
|
+
|
197
|
+
def hash
|
198
|
+
to_s.hash
|
199
|
+
end
|
200
|
+
|
201
|
+
def is_parent(other)
|
202
|
+
# default behavior now is to disallow any polymorphic types
|
203
|
+
self == other
|
204
|
+
end
|
205
|
+
|
206
|
+
def compatible?(other)
|
207
|
+
# default behavior is only exact match right now
|
208
|
+
self == other ||
|
209
|
+
error? || other.error? ||
|
210
|
+
unreachable? || other.unreachable?
|
211
|
+
end
|
212
|
+
|
213
|
+
def iterable?
|
214
|
+
array?
|
215
|
+
end
|
216
|
+
|
217
|
+
def component_type
|
218
|
+
AST.type(name) if array?
|
219
|
+
end
|
220
|
+
|
221
|
+
def narrow(other)
|
222
|
+
# only exact match allowed for now, so narrowing is a noop
|
223
|
+
if error? || unreachable?
|
224
|
+
other
|
225
|
+
else
|
226
|
+
self
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def unmeta
|
231
|
+
TypeReference.new(name, array, false)
|
232
|
+
end
|
233
|
+
|
234
|
+
def meta
|
235
|
+
TypeReference.new(name, array, true)
|
236
|
+
end
|
237
|
+
|
238
|
+
def error?
|
239
|
+
name == :error
|
240
|
+
end
|
241
|
+
|
242
|
+
def unreachable?
|
243
|
+
name == :unreachable
|
244
|
+
end
|
245
|
+
|
246
|
+
def primitive?
|
247
|
+
true
|
248
|
+
end
|
249
|
+
|
250
|
+
NoType = TypeReference.new(:notype)
|
251
|
+
NullType = TypeReference.new(:null)
|
252
|
+
ErrorType = TypeReference.new(:error)
|
253
|
+
UnreachableType = TypeReference.new(:unreachable)
|
254
|
+
end
|
255
|
+
|
256
|
+
class TypeDefinition < TypeReference
|
257
|
+
attr_accessor :superclass, :interfaces
|
258
|
+
|
259
|
+
def initialize(name, superclass, interfaces)
|
260
|
+
super(name, false)
|
261
|
+
|
262
|
+
@superclass = superclass
|
263
|
+
@interfaces = interfaces
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def self.type_factory
|
268
|
+
Thread.current[:ast_type_factory]
|
269
|
+
end
|
270
|
+
|
271
|
+
def self.type_factory=(factory)
|
272
|
+
Thread.current[:ast_type_factory] = factory
|
273
|
+
end
|
274
|
+
|
275
|
+
# Shortcut method to construct type references
|
276
|
+
def self.type(typesym, array = false, meta = false)
|
277
|
+
factory = type_factory
|
278
|
+
if factory
|
279
|
+
factory.type(typesym, array, meta)
|
280
|
+
else
|
281
|
+
TypeReference.new(typesym, array, meta)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def self.no_type
|
286
|
+
factory = type_factory
|
287
|
+
if factory
|
288
|
+
factory.no_type
|
289
|
+
else
|
290
|
+
TypeReference::NoType
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def self.error_type
|
295
|
+
TypeReference::ErrorType
|
296
|
+
end
|
297
|
+
|
298
|
+
def self.unreachable_type
|
299
|
+
TypeReference::UnreachableType
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.fixnum(parent, position, literal)
|
303
|
+
factory = type_factory
|
304
|
+
if factory
|
305
|
+
factory.fixnum(parent, position, literal)
|
306
|
+
else
|
307
|
+
Fixnum.new(parent, position, literal)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def self.float(parent, position, literal)
|
312
|
+
factory = type_factory
|
313
|
+
if factory
|
314
|
+
factory.float(parent, position, literal)
|
315
|
+
else
|
316
|
+
Float.new(parent, position, literal)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def self.defmacro(name, &block)
|
321
|
+
@macros ||= {}
|
322
|
+
raise "Conflicting macros for #{name}" if @macros[name]
|
323
|
+
@macros[name] = block
|
324
|
+
end
|
325
|
+
|
326
|
+
def self.macro(name)
|
327
|
+
@macros[name]
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
require 'duby/ast/local'
|
333
|
+
require 'duby/ast/call'
|
334
|
+
require 'duby/ast/flow'
|
335
|
+
require 'duby/ast/literal'
|
336
|
+
require 'duby/ast/method'
|
337
|
+
require 'duby/ast/class'
|
338
|
+
require 'duby/ast/structure'
|
339
|
+
require 'duby/ast/type'
|
340
|
+
require 'duby/ast/intrinsics'
|