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,28 @@
|
|
1
|
+
import javax.servlet.http.HttpServlet
|
2
|
+
import com.google.appengine.ext.duby.db.Model
|
3
|
+
|
4
|
+
class Post < Model
|
5
|
+
def initialize; end
|
6
|
+
|
7
|
+
property title, String
|
8
|
+
property body, Text
|
9
|
+
end
|
10
|
+
|
11
|
+
class DubyApp < HttpServlet
|
12
|
+
def_edb(list, 'com/ribrdb/list.dhtml')
|
13
|
+
|
14
|
+
def doGet(request, response)
|
15
|
+
returns :void
|
16
|
+
@posts = Post.all.run
|
17
|
+
response.getWriter.write(list)
|
18
|
+
end
|
19
|
+
|
20
|
+
def doPost(request, response)
|
21
|
+
post = Post.new
|
22
|
+
post.title = request.getParameter('title')
|
23
|
+
post.body = Text.new(request.getParameter('body'))
|
24
|
+
post.save
|
25
|
+
doGet(request, response)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<title>Posts</title>
|
2
|
+
<body>
|
3
|
+
<h1>All Posts:</h1>
|
4
|
+
<% for post in @posts %>
|
5
|
+
<h2><%= post.title %></h2>
|
6
|
+
<p><%= post.body.getValue %></p>
|
7
|
+
<% end %>
|
8
|
+
<hr>
|
9
|
+
<h1>New Post:</h1>
|
10
|
+
<form method=post>
|
11
|
+
Title: <input type=text name=title><br>
|
12
|
+
Body: <textarea name=body></textarea><br>
|
13
|
+
<input type=submit>
|
14
|
+
</form>
|
15
|
+
</body>
|
data/examples/edb.duby
ADDED
data/examples/fib.duby
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
import "java.lang.System"
|
2
|
+
|
3
|
+
def fib(a:int)
|
4
|
+
if a < 2
|
5
|
+
a
|
6
|
+
else
|
7
|
+
fib(a - 1) + fib(a - 2)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def bench(times:int)
|
12
|
+
while times > 0
|
13
|
+
time_start = System.currentTimeMillis
|
14
|
+
puts "fib(45):"
|
15
|
+
puts fib(45)
|
16
|
+
time_total = System.currentTimeMillis - time_start
|
17
|
+
puts "Total time:"
|
18
|
+
puts time_total
|
19
|
+
times -= 1
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
bench 10
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import 'java.util.ArrayList'
|
2
|
+
|
3
|
+
class Bar
|
4
|
+
def initialize
|
5
|
+
@a = ArrayList
|
6
|
+
end
|
7
|
+
|
8
|
+
def list=(a:ArrayList)
|
9
|
+
@a = a
|
10
|
+
end
|
11
|
+
|
12
|
+
def foo
|
13
|
+
puts @a
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
b = Bar.new
|
18
|
+
list = ArrayList.new
|
19
|
+
list.add('hello')
|
20
|
+
list.add('world')
|
21
|
+
b.list = list
|
22
|
+
b.foo
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import java.lang.System
|
2
|
+
|
3
|
+
def run
|
4
|
+
puts "Rendering"
|
5
|
+
y = -39.0
|
6
|
+
while y <= 39.0
|
7
|
+
puts
|
8
|
+
x = -39.0
|
9
|
+
while x <= 39.0
|
10
|
+
i = iterate(x/40.0,y/40.0)
|
11
|
+
if (i == 0)
|
12
|
+
print "*"
|
13
|
+
else
|
14
|
+
print " "
|
15
|
+
end
|
16
|
+
x += 1
|
17
|
+
end
|
18
|
+
y += 1
|
19
|
+
end
|
20
|
+
puts
|
21
|
+
end
|
22
|
+
|
23
|
+
def iterate(x:double,y:double)
|
24
|
+
cr = y-0.5
|
25
|
+
ci = x
|
26
|
+
zi = 0.0
|
27
|
+
zr = 0.0
|
28
|
+
i = 0
|
29
|
+
|
30
|
+
result = 0
|
31
|
+
while true
|
32
|
+
i += 1
|
33
|
+
temp = zr * zi
|
34
|
+
zr2 = zr * zr
|
35
|
+
zi2 = zi * zi
|
36
|
+
zr = zr2 - zi2 + cr
|
37
|
+
zi = temp + temp + ci
|
38
|
+
if (zi2 + zr2 > 16)
|
39
|
+
result = i
|
40
|
+
break
|
41
|
+
end
|
42
|
+
if (i > 1000)
|
43
|
+
result = 0
|
44
|
+
break
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
i = 0
|
52
|
+
while i < 10
|
53
|
+
start = System.currentTimeMillis
|
54
|
+
run
|
55
|
+
puts "Time: " + (System.currentTimeMillis - start) / 1000.0
|
56
|
+
i += 1
|
57
|
+
end
|
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
data/examples/test.edb
ADDED
Binary file
|
data/lib/duby.rb
ADDED
@@ -0,0 +1,168 @@
|
|
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
|
+
def self.run(*args)
|
19
|
+
DubyImpl.new.run(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.compile(*args)
|
23
|
+
DubyImpl.new.compile(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.parse(*args)
|
27
|
+
DubyImpl.new.parse(*args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DubyImpl
|
32
|
+
def run(*args)
|
33
|
+
ast = parse(*args)
|
34
|
+
|
35
|
+
main_cls = nil
|
36
|
+
compile_ast(ast) do |outfile, builder|
|
37
|
+
bytes = builder.generate
|
38
|
+
name = builder.class_name.gsub(/\//, '.')
|
39
|
+
cls = JRuby.runtime.jruby_class_loader.define_class(name, bytes.to_java_bytes)
|
40
|
+
proxy_cls = JavaUtilities.get_proxy_class(name)
|
41
|
+
# TODO: using first main; find correct one
|
42
|
+
if proxy_cls.respond_to? :main
|
43
|
+
main_cls ||= proxy_cls
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if main_cls
|
48
|
+
main_cls.main(args.to_java(:string))
|
49
|
+
else
|
50
|
+
puts "No main found"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def compile(*args)
|
55
|
+
process_flags!(args)
|
56
|
+
|
57
|
+
expand_files(args).each do |duby_file|
|
58
|
+
if duby_file == '-e'
|
59
|
+
@filename = '-e'
|
60
|
+
next
|
61
|
+
elsif @filename == '-e'
|
62
|
+
ast = parse('-e', duby_file)
|
63
|
+
else
|
64
|
+
ast = parse(duby_file)
|
65
|
+
end
|
66
|
+
exit 1 if @error
|
67
|
+
|
68
|
+
compile_ast(ast) do |filename, builder|
|
69
|
+
filename = "#{@dest}#{filename}"
|
70
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
71
|
+
bytes = builder.generate
|
72
|
+
File.open(filename, 'w') {|f| f.write(bytes)}
|
73
|
+
end
|
74
|
+
@filename = nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse(*args)
|
79
|
+
process_flags!(args)
|
80
|
+
@filename = args.shift
|
81
|
+
|
82
|
+
if @filename == '-e'
|
83
|
+
@filename = 'dash_e'
|
84
|
+
src = args[0]
|
85
|
+
else
|
86
|
+
src = File.read(@filename)
|
87
|
+
end
|
88
|
+
Duby::AST.type_factory = Duby::JVM::Types::TypeFactory.new(@filename)
|
89
|
+
ast = Duby::AST.parse_ruby(src, @filename)
|
90
|
+
@transformer = Duby::Transform::Transformer.new
|
91
|
+
ast = @transformer.transform(ast, nil)
|
92
|
+
@transformer.errors.each do |ex|
|
93
|
+
raise ex.cause || ex if @verbose
|
94
|
+
puts "#@filename:#{ex.position.start_line+1}: #{ex.message}"
|
95
|
+
end
|
96
|
+
@error = @transformer.errors.size > 0
|
97
|
+
ast
|
98
|
+
end
|
99
|
+
|
100
|
+
def compile_ast(ast, &block)
|
101
|
+
typer = Duby::Typer::JVM.new(@filename, @transformer)
|
102
|
+
typer.infer(ast)
|
103
|
+
begin
|
104
|
+
typer.resolve(true)
|
105
|
+
ensure
|
106
|
+
typer.errors.each do |ex|
|
107
|
+
puts ex.message
|
108
|
+
puts ex.backtrace if @verbose
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
compiler = @compiler_class.new(@filename)
|
113
|
+
ast.compile(compiler, false)
|
114
|
+
compiler.generate(&block)
|
115
|
+
end
|
116
|
+
|
117
|
+
def process_flags!(args)
|
118
|
+
while args.length > 0
|
119
|
+
case args[0]
|
120
|
+
when '-V'
|
121
|
+
Duby::Typer.verbose = true
|
122
|
+
Duby::AST.verbose = true
|
123
|
+
Duby::Compiler::JVM.verbose = true
|
124
|
+
@verbose = true
|
125
|
+
args.shift
|
126
|
+
when '-java'
|
127
|
+
require 'duby/jvm/source_compiler'
|
128
|
+
@compiler_class = Duby::Compiler::JavaSource
|
129
|
+
args.shift
|
130
|
+
when '-d'
|
131
|
+
args.shift
|
132
|
+
@dest = File.join(args.shift, '')
|
133
|
+
when '-p'
|
134
|
+
args.shift
|
135
|
+
plugin = args.shift
|
136
|
+
require "duby/plugin/#{plugin}"
|
137
|
+
when '-I'
|
138
|
+
args.shift
|
139
|
+
$: << args.shift
|
140
|
+
else
|
141
|
+
break
|
142
|
+
end
|
143
|
+
end
|
144
|
+
@compiler_class ||= Duby::Compiler::JVM
|
145
|
+
end
|
146
|
+
|
147
|
+
def expand_files(files)
|
148
|
+
expanded = []
|
149
|
+
files.each do |filename|
|
150
|
+
if File.directory?(filename)
|
151
|
+
Dir[File.join(filename, '*')].each do |child|
|
152
|
+
if File.directory?(child)
|
153
|
+
files << child
|
154
|
+
elsif child =~ /\.duby$/
|
155
|
+
expanded << child
|
156
|
+
end
|
157
|
+
end
|
158
|
+
else
|
159
|
+
expanded << filename
|
160
|
+
end
|
161
|
+
end
|
162
|
+
expanded
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
if __FILE__ == $0
|
167
|
+
Duby.run(ARGV[0], *ARGV[1..-1])
|
168
|
+
end
|
data/lib/duby/ast.rb
ADDED
@@ -0,0 +1,386 @@
|
|
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
|
+
|
89
|
+
def self.===(other)
|
90
|
+
super || (other.kind_of?(NodeProxy) && (self === other.__getobj__))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class ErrorNode < Node
|
95
|
+
def initialize(parent, error)
|
96
|
+
super(parent, error.position)
|
97
|
+
@error = error
|
98
|
+
@inferred_type = TypeReference::ErrorType
|
99
|
+
@resolved = true
|
100
|
+
end
|
101
|
+
|
102
|
+
def infer(typer)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
module Named
|
107
|
+
attr_accessor :name
|
108
|
+
|
109
|
+
def to_s
|
110
|
+
"#{super}(#{name})"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
module Typed
|
115
|
+
attr_accessor :type
|
116
|
+
end
|
117
|
+
|
118
|
+
module Valued
|
119
|
+
include Typed
|
120
|
+
attr_accessor :value
|
121
|
+
end
|
122
|
+
|
123
|
+
module Literal
|
124
|
+
include Typed
|
125
|
+
attr_accessor :literal
|
126
|
+
|
127
|
+
def to_s
|
128
|
+
"#{super}(#{literal.inspect})"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module Scoped
|
133
|
+
def scope
|
134
|
+
@scope ||= begin
|
135
|
+
scope = parent
|
136
|
+
raise "No parent for #{self.class.name} at #{line_number}" if scope.nil?
|
137
|
+
scope = scope.parent until scope.class.include?(Scope)
|
138
|
+
scope
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
module ClassScoped
|
144
|
+
def scope
|
145
|
+
@scope ||= begin
|
146
|
+
scope = parent
|
147
|
+
scope = scope.parent until scope.nil? || ClassDefinition === scope
|
148
|
+
scope
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
module Annotated
|
154
|
+
attr_accessor :annotations
|
155
|
+
|
156
|
+
def annotation(name)
|
157
|
+
name = name.to_s
|
158
|
+
annotations.find {|a| a.name == name}
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
module Scope; end
|
163
|
+
|
164
|
+
class Colon2 < Node; end
|
165
|
+
|
166
|
+
class Constant < Node
|
167
|
+
include Named
|
168
|
+
def initialize(parent, position, name)
|
169
|
+
@name = name
|
170
|
+
super(parent, position, [])
|
171
|
+
end
|
172
|
+
|
173
|
+
def infer(typer)
|
174
|
+
@inferred_type ||= begin
|
175
|
+
typer.type_reference(name, false, true)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class Self < Node
|
181
|
+
def infer(typer)
|
182
|
+
@inferred_type ||= typer.self_type
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class VoidType < Node; end
|
187
|
+
|
188
|
+
class Annotation < Node
|
189
|
+
def initialize(parent, position, klass)
|
190
|
+
super(parent, position)
|
191
|
+
@class = klass
|
192
|
+
@values = []
|
193
|
+
end
|
194
|
+
|
195
|
+
def name
|
196
|
+
@class.name
|
197
|
+
end
|
198
|
+
|
199
|
+
def type
|
200
|
+
@class
|
201
|
+
end
|
202
|
+
|
203
|
+
def []=(name, value)
|
204
|
+
# TODO support annotation arguments
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
class TypeReference < Node
|
209
|
+
include Named
|
210
|
+
attr_accessor :array
|
211
|
+
alias array? array
|
212
|
+
attr_accessor :meta
|
213
|
+
alias meta? meta
|
214
|
+
|
215
|
+
def initialize(name, array = false, meta = false, position=nil)
|
216
|
+
super(nil, position)
|
217
|
+
@name = name
|
218
|
+
@array = array
|
219
|
+
@meta = meta
|
220
|
+
end
|
221
|
+
|
222
|
+
def to_s
|
223
|
+
"Type(#{name}#{array? ? ' array' : ''}#{meta? ? ' meta' : ''})"
|
224
|
+
end
|
225
|
+
|
226
|
+
def ==(other)
|
227
|
+
to_s == other.to_s
|
228
|
+
end
|
229
|
+
|
230
|
+
def eql?(other)
|
231
|
+
self == other
|
232
|
+
end
|
233
|
+
|
234
|
+
def hash
|
235
|
+
to_s.hash
|
236
|
+
end
|
237
|
+
|
238
|
+
def is_parent(other)
|
239
|
+
# default behavior now is to disallow any polymorphic types
|
240
|
+
self == other
|
241
|
+
end
|
242
|
+
|
243
|
+
def compatible?(other)
|
244
|
+
# default behavior is only exact match right now
|
245
|
+
self == other ||
|
246
|
+
error? || other.error? ||
|
247
|
+
unreachable? || other.unreachable?
|
248
|
+
end
|
249
|
+
|
250
|
+
def iterable?
|
251
|
+
array?
|
252
|
+
end
|
253
|
+
|
254
|
+
def component_type
|
255
|
+
AST.type(name) if array?
|
256
|
+
end
|
257
|
+
|
258
|
+
def narrow(other)
|
259
|
+
# only exact match allowed for now, so narrowing is a noop
|
260
|
+
if error? || unreachable?
|
261
|
+
other
|
262
|
+
else
|
263
|
+
self
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def unmeta
|
268
|
+
TypeReference.new(name, array, false)
|
269
|
+
end
|
270
|
+
|
271
|
+
def meta
|
272
|
+
TypeReference.new(name, array, true)
|
273
|
+
end
|
274
|
+
|
275
|
+
def error?
|
276
|
+
name == :error
|
277
|
+
end
|
278
|
+
|
279
|
+
def unreachable?
|
280
|
+
name == :unreachable
|
281
|
+
end
|
282
|
+
|
283
|
+
def block?
|
284
|
+
name == :block
|
285
|
+
end
|
286
|
+
|
287
|
+
def primitive?
|
288
|
+
true
|
289
|
+
end
|
290
|
+
|
291
|
+
NoType = TypeReference.new(:notype)
|
292
|
+
NullType = TypeReference.new(:null)
|
293
|
+
ErrorType = TypeReference.new(:error)
|
294
|
+
UnreachableType = TypeReference.new(:unreachable)
|
295
|
+
BlockType = TypeReference.new(:block)
|
296
|
+
end
|
297
|
+
|
298
|
+
class TypeDefinition < TypeReference
|
299
|
+
attr_accessor :superclass, :interfaces
|
300
|
+
|
301
|
+
def initialize(name, superclass, interfaces)
|
302
|
+
super(name, false)
|
303
|
+
|
304
|
+
@superclass = superclass
|
305
|
+
@interfaces = interfaces
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def self.type_factory
|
310
|
+
Thread.current[:ast_type_factory]
|
311
|
+
end
|
312
|
+
|
313
|
+
def self.type_factory=(factory)
|
314
|
+
Thread.current[:ast_type_factory] = factory
|
315
|
+
end
|
316
|
+
|
317
|
+
# Shortcut method to construct type references
|
318
|
+
def self.type(typesym, array = false, meta = false)
|
319
|
+
factory = type_factory
|
320
|
+
if factory
|
321
|
+
factory.type(typesym, array, meta)
|
322
|
+
else
|
323
|
+
TypeReference.new(typesym, array, meta)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.no_type
|
328
|
+
factory = type_factory
|
329
|
+
if factory
|
330
|
+
factory.no_type
|
331
|
+
else
|
332
|
+
TypeReference::NoType
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def self.error_type
|
337
|
+
TypeReference::ErrorType
|
338
|
+
end
|
339
|
+
|
340
|
+
def self.unreachable_type
|
341
|
+
TypeReference::UnreachableType
|
342
|
+
end
|
343
|
+
|
344
|
+
def self.block_type
|
345
|
+
TypeReference::BlockType
|
346
|
+
end
|
347
|
+
|
348
|
+
def self.fixnum(parent, position, literal)
|
349
|
+
factory = type_factory
|
350
|
+
if factory
|
351
|
+
factory.fixnum(parent, position, literal)
|
352
|
+
else
|
353
|
+
Fixnum.new(parent, position, literal)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def self.float(parent, position, literal)
|
358
|
+
factory = type_factory
|
359
|
+
if factory
|
360
|
+
factory.float(parent, position, literal)
|
361
|
+
else
|
362
|
+
Float.new(parent, position, literal)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def self.defmacro(name, &block)
|
367
|
+
@macros ||= {}
|
368
|
+
raise "Conflicting macros for #{name}" if @macros[name]
|
369
|
+
@macros[name] = block
|
370
|
+
end
|
371
|
+
|
372
|
+
def self.macro(name)
|
373
|
+
@macros[name]
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
require 'duby/ast/local'
|
379
|
+
require 'duby/ast/call'
|
380
|
+
require 'duby/ast/flow'
|
381
|
+
require 'duby/ast/literal'
|
382
|
+
require 'duby/ast/method'
|
383
|
+
require 'duby/ast/class'
|
384
|
+
require 'duby/ast/structure'
|
385
|
+
require 'duby/ast/type'
|
386
|
+
require 'duby/ast/intrinsics'
|