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
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'
|