mirah 0.0.7-java → 0.0.8-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 +181 -0
- data/README.txt +6 -10
- data/Rakefile +86 -9
- data/bin/mirah +2 -0
- data/bin/mirahc +2 -0
- data/bin/mirahp +2 -0
- data/{bin/dubyp → examples/interfaces.mirah} +16 -9
- data/examples/macros/square.mirah +12 -0
- data/examples/macros/square_int.mirah +12 -0
- data/examples/macros/string-each-char.mirah +14 -0
- data/examples/maven/README.txt +2 -0
- data/examples/maven/pom.xml +23 -0
- data/examples/maven/src/main/mirah/hello_mirah.mirah +9 -0
- data/examples/rosettacode/100-doors.mirah +44 -0
- data/examples/rosettacode/99-bottles-of-beer.mirah +13 -0
- data/examples/rosettacode/README.txt +9 -0
- data/examples/rosettacode/boolean-values.mirah +29 -0
- data/examples/rosettacode/comments.mirah +2 -0
- data/examples/rosettacode/copy-a-string.mirah +10 -0
- data/examples/rosettacode/count-occurrences-of-a-substring.mirah +40 -0
- data/examples/rosettacode/create-a-file.mirah +6 -0
- data/examples/rosettacode/empty-string.mirah +9 -0
- data/examples/rosettacode/factorial.mirah +10 -0
- data/examples/rosettacode/fibonacci.mirah +21 -0
- data/examples/rosettacode/file-size.mirah +5 -0
- data/examples/rosettacode/fizz-buzz.mirah +21 -0
- data/examples/rosettacode/flatten-a-list.mirah +24 -0
- data/examples/rosettacode/guess-the-number.mirah +21 -0
- data/examples/rosettacode/is-string-numeric.mirah +127 -0
- data/examples/rosettacode/palindrome.mirah +14 -0
- data/examples/rosettacode/repeat-a-string.mirah +9 -0
- data/examples/rosettacode/reverse-a-string.mirah +6 -0
- data/examples/rosettacode/rot-13.mirah +20 -0
- data/examples/rosettacode/user-input.mirah +4 -0
- data/examples/sort_closure.mirah +1 -1
- data/javalib/dynalink-0.2.jar +0 -0
- data/javalib/mirah-bootstrap.jar +0 -0
- data/lib/mirah.rb +7 -16
- data/lib/mirah/ast.rb +22 -92
- data/lib/mirah/ast/call.rb +41 -9
- data/lib/mirah/ast/class.rb +34 -6
- data/lib/mirah/ast/flow.rb +17 -5
- data/lib/mirah/ast/intrinsics.rb +50 -8
- data/lib/mirah/ast/literal.rb +7 -0
- data/lib/mirah/ast/local.rb +9 -1
- data/lib/mirah/ast/method.rb +21 -8
- data/lib/mirah/ast/scope.rb +1 -1
- data/lib/mirah/ast/structure.rb +81 -15
- data/lib/mirah/ast/type.rb +4 -0
- data/{bin/dubyc → lib/mirah/commands.rb} +4 -11
- data/lib/mirah/commands/base.rb +54 -0
- data/lib/mirah/commands/compile.rb +39 -0
- data/{examples/wiki/Rakefile → lib/mirah/commands/parse.rb} +18 -17
- data/lib/mirah/commands/run.rb +73 -0
- data/lib/mirah/compiler.rb +37 -417
- data/lib/mirah/compiler/call.rb +45 -0
- data/lib/mirah/compiler/class.rb +81 -0
- data/lib/mirah/compiler/flow.rb +109 -0
- data/lib/mirah/compiler/literal.rb +130 -0
- data/lib/mirah/compiler/local.rb +59 -0
- data/lib/mirah/compiler/method.rb +44 -0
- data/lib/mirah/compiler/structure.rb +65 -0
- data/lib/mirah/compiler/type.rb +27 -0
- data/lib/mirah/env.rb +4 -6
- data/lib/mirah/generator.rb +61 -0
- data/lib/mirah/jvm/compiler.rb +8 -867
- data/lib/mirah/jvm/compiler/base.rb +270 -0
- data/lib/mirah/jvm/compiler/java_source.rb +779 -0
- data/lib/mirah/jvm/compiler/jvm_bytecode.rb +851 -0
- data/lib/mirah/jvm/method_lookup.rb +21 -2
- data/lib/mirah/jvm/source_generator/builder.rb +10 -13
- data/lib/mirah/jvm/source_generator/loops.rb +99 -93
- data/lib/mirah/jvm/source_generator/precompile.rb +3 -2
- data/lib/mirah/jvm/typer.rb +3 -3
- data/lib/mirah/jvm/types.rb +10 -426
- data/lib/mirah/jvm/types/array_type.rb +62 -0
- data/lib/mirah/jvm/types/basic_types.rb +1 -0
- data/lib/mirah/jvm/types/dynamic_type.rb +46 -0
- data/lib/mirah/jvm/types/factory.rb +23 -5
- data/lib/mirah/jvm/types/interface_definition.rb +20 -0
- data/lib/mirah/jvm/types/intrinsics.rb +15 -3
- data/lib/mirah/jvm/types/meta_type.rb +45 -0
- data/lib/mirah/jvm/types/methods.rb +12 -5
- data/lib/mirah/jvm/types/null_type.rb +27 -0
- data/lib/mirah/jvm/types/primitive_type.rb +38 -0
- data/lib/mirah/jvm/types/source_mirror.rb +266 -0
- data/lib/mirah/jvm/types/type.rb +173 -0
- data/lib/mirah/jvm/types/type_definition.rb +55 -0
- data/lib/mirah/jvm/types/unreachable_type.rb +27 -0
- data/lib/mirah/jvm/types/void_type.rb +19 -0
- data/lib/mirah/parser.rb +90 -0
- data/lib/mirah/plugin/gwt.rb +5 -5
- data/lib/mirah/plugin/java.rb +1 -1
- data/lib/mirah/transform.rb +4 -321
- data/lib/mirah/transform/ast_ext.rb +63 -0
- data/lib/mirah/transform/error.rb +13 -0
- data/lib/mirah/transform/helper.rb +761 -0
- data/lib/mirah/transform/transformer.rb +255 -0
- data/lib/mirah/typer.rb +2 -383
- data/{bin/duby → lib/mirah/typer/base.rb} +12 -10
- data/lib/mirah/typer/simple.rb +377 -0
- data/lib/mirah/util/argument_processor.rb +114 -0
- data/lib/mirah/util/class_loader.rb +37 -0
- data/lib/mirah/util/compilation_state.rb +51 -0
- data/lib/mirah/util/process_errors.rb +33 -0
- data/lib/mirah/version.rb +1 -1
- data/lib/mirah_task.rb +3 -2
- data/test/{test_ast.rb → core/test_ast.rb} +6 -0
- data/test/{test_compilation.rb → core/test_compilation.rb} +0 -0
- data/test/{test_env.rb → core/test_env.rb} +24 -25
- data/test/{test_macros.rb → core/test_macros.rb} +2 -4
- data/test/{test_typer.rb → core/test_typer.rb} +0 -3
- data/test/jvm/bytecode_test_helper.rb +181 -0
- data/test/{test_javac_compiler.rb → jvm/javac_test_helper.rb} +38 -22
- data/test/jvm/test_enumerable.rb +304 -0
- data/test/{test_java_typer.rb → jvm/test_java_typer.rb} +2 -4
- data/test/{test_jvm_compiler.rb → jvm/test_jvm_compiler.rb} +146 -443
- data/test/jvm/test_macros.rb +147 -0
- data/test/jvm/test_main_method.rb +15 -0
- data/test/{test_gwt.rb → plugins/test_gwt.rb} +0 -2
- metadata +103 -91
- data/bin/jrubyp +0 -52
- data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +0 -339
- data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +0 -42
- data/examples/wiki/src/org/mirah/wiki/error.eduby.html +0 -2
- data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +0 -69
- data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +0 -7
- data/examples/wiki/src/org/mirah/wiki/view.eduby.html +0 -15
- data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
- data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
- data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
- data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
- data/examples/wiki/war/app.yaml +0 -21
- data/examples/wiki/war/public/favicon.ico +0 -0
- data/examples/wiki/war/public/images/appengine_duby.png +0 -0
- data/examples/wiki/war/public/images/back.gif +0 -0
- data/examples/wiki/war/public/images/dir.gif +0 -0
- data/examples/wiki/war/public/images/file.gif +0 -0
- data/examples/wiki/war/public/javascripts/prettify.js +0 -61
- data/examples/wiki/war/public/robots.txt +0 -0
- data/examples/wiki/war/public/stylesheets/main.css +0 -156
- data/examples/wiki/war/public/stylesheets/prettify.css +0 -1
- data/examples/wiki/war/public/stylesheets/sh_style.css +0 -66
- data/examples/wiki/war/public/stylesheets/source.css +0 -21
- data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
- data/examples/wiki/war/public/wmd/images/bg.png +0 -0
- data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
- data/examples/wiki/war/public/wmd/images/bold.png +0 -0
- data/examples/wiki/war/public/wmd/images/code.png +0 -0
- data/examples/wiki/war/public/wmd/images/h1.png +0 -0
- data/examples/wiki/war/public/wmd/images/hr.png +0 -0
- data/examples/wiki/war/public/wmd/images/img.png +0 -0
- data/examples/wiki/war/public/wmd/images/italic.png +0 -0
- data/examples/wiki/war/public/wmd/images/link.png +0 -0
- data/examples/wiki/war/public/wmd/images/ol.png +0 -0
- data/examples/wiki/war/public/wmd/images/redo.png +0 -0
- data/examples/wiki/war/public/wmd/images/separator.png +0 -0
- data/examples/wiki/war/public/wmd/images/ul.png +0 -0
- data/examples/wiki/war/public/wmd/images/undo.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
- data/examples/wiki/war/public/wmd/showdown.js +0 -421
- data/examples/wiki/war/public/wmd/wmd-base.js +0 -1799
- data/examples/wiki/war/public/wmd/wmd-plus.js +0 -311
- data/examples/wiki/war/public/wmd/wmd.js +0 -73
- data/examples/wiki/war/src/org/mirah/wiki/MirahWiki.duby +0 -339
- data/examples/wiki/war/src/org/mirah/wiki/edit.eduby.html +0 -42
- data/examples/wiki/war/src/org/mirah/wiki/error.eduby.html +0 -2
- data/examples/wiki/war/src/org/mirah/wiki/layout.eduby.html +0 -69
- data/examples/wiki/war/src/org/mirah/wiki/parser.eduby.html +0 -7
- data/examples/wiki/war/src/org/mirah/wiki/view.eduby.html +0 -15
- data/javalib/dynalink-0.1.jar +0 -0
- data/javalib/jsr292-mock.jar +0 -0
- data/lib/mirah/class_loader.rb +0 -35
- data/lib/mirah/compilation_state.rb +0 -28
- data/lib/mirah/impl.rb +0 -273
- data/lib/mirah/jvm/base.rb +0 -267
- data/lib/mirah/jvm/source_compiler.rb +0 -760
- data/lib/mirah/transform2.rb +0 -752
@@ -0,0 +1,255 @@
|
|
1
|
+
module Mirah
|
2
|
+
module Transform
|
3
|
+
class Transformer
|
4
|
+
begin
|
5
|
+
include Java::DubyLangCompiler.Compiler
|
6
|
+
rescue NameError
|
7
|
+
$CLASSPATH << File.dirname(__FILE__) + '/../../../javalib/mirah-bootstrap.jar'
|
8
|
+
include Java::DubyLangCompiler.Compiler
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :errors, :state
|
12
|
+
attr_accessor :filename
|
13
|
+
def initialize(state)
|
14
|
+
@errors = []
|
15
|
+
@tmp_count = 0
|
16
|
+
@annotations = []
|
17
|
+
@scopes = []
|
18
|
+
@extra_body = nil
|
19
|
+
@state = state
|
20
|
+
@helper = Mirah::Transform::Helper.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def destination
|
24
|
+
@state.destination
|
25
|
+
end
|
26
|
+
|
27
|
+
def verbose?
|
28
|
+
@state.verbose
|
29
|
+
end
|
30
|
+
|
31
|
+
def annotations
|
32
|
+
result, @annotations = @annotations, []
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_annotation(annotation)
|
37
|
+
@annotations << annotation
|
38
|
+
Mirah::AST::Noop.new(annotation.parent, annotation.position)
|
39
|
+
end
|
40
|
+
|
41
|
+
def tmp(format="__xform_tmp_%d")
|
42
|
+
format % [@tmp_count += 1]
|
43
|
+
end
|
44
|
+
|
45
|
+
class JMetaPosition
|
46
|
+
attr_accessor :start_line, :end_line, :start_offset, :end_offset, :file
|
47
|
+
attr_accessor :startpos, :endpos, :start_col, :end_col
|
48
|
+
|
49
|
+
def initialize(startpos, endpos)
|
50
|
+
@startpos = startpos
|
51
|
+
@endpos = endpos
|
52
|
+
@file = startpos.filename
|
53
|
+
@start_line = startpos.line
|
54
|
+
@start_offset = startpos.pos
|
55
|
+
@start_col = startpos.col
|
56
|
+
@end_line = endpos.line
|
57
|
+
@end_offset = endpos.pos
|
58
|
+
@end_col = endpos.col
|
59
|
+
end
|
60
|
+
|
61
|
+
def +(other)
|
62
|
+
JMetaPosition.new(@startpos, other.endpos)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def position(node)
|
67
|
+
JMetaPosition.new(node.start_position, node.end_position)
|
68
|
+
end
|
69
|
+
|
70
|
+
def camelize(name)
|
71
|
+
name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
72
|
+
end
|
73
|
+
|
74
|
+
def transform(node, parent)
|
75
|
+
return nil if node.nil?
|
76
|
+
begin
|
77
|
+
top = @extra_body.nil?
|
78
|
+
if top
|
79
|
+
@extra_body = Mirah::AST::Body.new(nil, position(node))
|
80
|
+
end
|
81
|
+
method = "transform_#{camelize(node[0])}"
|
82
|
+
result = @helper.send method, node, parent
|
83
|
+
if top
|
84
|
+
body = result.body
|
85
|
+
if body.kind_of?(Mirah::AST::Body) && @extra_body.empty?
|
86
|
+
@extra_body = body
|
87
|
+
else
|
88
|
+
result.body = @extra_body
|
89
|
+
body.parent = @extra_body
|
90
|
+
@extra_body.children.insert(0, body)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
return result
|
94
|
+
rescue Error => ex
|
95
|
+
@errors << ex
|
96
|
+
Mirah::AST::ErrorNode.new(parent, ex)
|
97
|
+
# rescue Exception => ex
|
98
|
+
# error = Error.new(ex.message, position(node), ex)
|
99
|
+
# @errors << error
|
100
|
+
# Mirah::AST::ErrorNode.new(parent, error)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def captured?(node)
|
105
|
+
depth = node.depth
|
106
|
+
scope = @scopes[-1]
|
107
|
+
while depth > 0
|
108
|
+
depth -= 1
|
109
|
+
scope = scope.enclosing_scope
|
110
|
+
end
|
111
|
+
scope.isCaptured(node.index)
|
112
|
+
end
|
113
|
+
|
114
|
+
def eval(src, filename='-', parent=nil, *vars)
|
115
|
+
node = Mirah::AST.parse_ruby(src, filename)
|
116
|
+
mirah_node = transform(node, nil).body
|
117
|
+
mirah_node.parent = parent
|
118
|
+
mirah_node
|
119
|
+
end
|
120
|
+
|
121
|
+
def dump_ast(node, call=nil)
|
122
|
+
encoded = nil
|
123
|
+
values = Mirah::AST::Unquote.extract_values do
|
124
|
+
encoded = Base64.encode64(Marshal.dump(node))
|
125
|
+
end
|
126
|
+
scope = call.scope.static_scope if call
|
127
|
+
result = Mirah::AST::Array.new(nil, node.position)
|
128
|
+
if encoded.size < 65535
|
129
|
+
result << Mirah::AST::String.new(result, node.position, encoded)
|
130
|
+
else
|
131
|
+
strings = Mirah::AST::StringConcat.new(result, node.position)
|
132
|
+
result << strings
|
133
|
+
while encoded.size >= 65535
|
134
|
+
chunk = encoded[0, 65535]
|
135
|
+
encoded[0, 65535] = ""
|
136
|
+
strings << Mirah::AST::String.new(strings, node.position, chunk)
|
137
|
+
end
|
138
|
+
strings << Mirah::AST::String.new(strings, node.position, encoded)
|
139
|
+
end
|
140
|
+
values.each do |value|
|
141
|
+
if call
|
142
|
+
scoped_value = Mirah::AST::ScopedBody.new(result, value.position)
|
143
|
+
scoped_value << value
|
144
|
+
scoped_value.static_scope = scope
|
145
|
+
else
|
146
|
+
scoped_value = value
|
147
|
+
end
|
148
|
+
result << scoped_value
|
149
|
+
end
|
150
|
+
return result
|
151
|
+
end
|
152
|
+
|
153
|
+
def load_ast(args)
|
154
|
+
nodes = args.to_a
|
155
|
+
encoded = nodes.shift
|
156
|
+
Mirah::AST::Unquote.inject_values(nodes) do
|
157
|
+
result = Marshal.load(Base64.decode64(encoded))
|
158
|
+
if Mirah::AST::UnquotedValue === result
|
159
|
+
result.node
|
160
|
+
else
|
161
|
+
result
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def __ruby_eval(code, arg)
|
167
|
+
self.instance_eval(code)
|
168
|
+
end
|
169
|
+
|
170
|
+
def fixnum(value)
|
171
|
+
node = eval("1")
|
172
|
+
node.literal = value
|
173
|
+
node
|
174
|
+
end
|
175
|
+
|
176
|
+
def constant(name, array=false)
|
177
|
+
node = eval("Foo")
|
178
|
+
node.name = name
|
179
|
+
node.array = array
|
180
|
+
node
|
181
|
+
end
|
182
|
+
|
183
|
+
def cast(type, value)
|
184
|
+
if value.kind_of?(String)
|
185
|
+
value = Mirah::AST::Local.new(@extra_body, @extra_body.position, value)
|
186
|
+
end
|
187
|
+
fcall = eval("Foo()")
|
188
|
+
fcall.name = type
|
189
|
+
fcall.parameters = [value]
|
190
|
+
fcall
|
191
|
+
end
|
192
|
+
|
193
|
+
def string(value)
|
194
|
+
node = eval('"Foo"')
|
195
|
+
node.literal = value
|
196
|
+
node
|
197
|
+
end
|
198
|
+
|
199
|
+
def empty_array(type_node, size_node)
|
200
|
+
node = eval('int[0]')
|
201
|
+
node.type_node = type_node
|
202
|
+
node.size = size_node
|
203
|
+
node
|
204
|
+
end
|
205
|
+
|
206
|
+
def find_class(name)
|
207
|
+
AST.type(nil, name, false, false)
|
208
|
+
end
|
209
|
+
|
210
|
+
def expand(fvcall, parent)
|
211
|
+
result = yield self, fvcall, parent
|
212
|
+
unless AST::Node === result
|
213
|
+
raise Error.new('Invalid macro result', fvcall.position)
|
214
|
+
end
|
215
|
+
result
|
216
|
+
end
|
217
|
+
|
218
|
+
def append_node(node)
|
219
|
+
@extra_body << node
|
220
|
+
node
|
221
|
+
end
|
222
|
+
|
223
|
+
def define_class(position, name, &block)
|
224
|
+
append_node Mirah::AST::ClassDefinition.new(@extra_body, position, name, &block)
|
225
|
+
end
|
226
|
+
|
227
|
+
def defineClass(name, superclass=nil, interfaces=nil)
|
228
|
+
define_class(@extra_body.position, name) do |class_def|
|
229
|
+
superclass = Mirah::AST::Constant.new(class_def, class_def.position, superclass)
|
230
|
+
superclass.parent = class_def
|
231
|
+
if interfaces
|
232
|
+
class_def.implements(*interfaces.map {|i| Mirah::AST::Constant.new(class_def, class_def.position, i)})
|
233
|
+
end
|
234
|
+
[superclass, body(class_def)]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def body(parent=nil)
|
239
|
+
parent ||= @extra_body
|
240
|
+
Mirah::AST::Body.new(parent, parent.position)
|
241
|
+
end
|
242
|
+
|
243
|
+
def define_closure(position, name, enclosing_type)
|
244
|
+
target = self
|
245
|
+
parent = @extra_body
|
246
|
+
enclosing_type = enclosing_type.unmeta
|
247
|
+
if enclosing_type.respond_to?(:node) && enclosing_type.node
|
248
|
+
parent = target = enclosing_type.node
|
249
|
+
end
|
250
|
+
target.append_node(Mirah::AST::ClosureDefinition.new(
|
251
|
+
parent, position, name, enclosing_type))
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
data/lib/mirah/typer.rb
CHANGED
@@ -13,9 +13,9 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
|
16
|
-
require 'mirah/ast'
|
17
|
-
require 'mirah/transform'
|
18
16
|
require 'mirah/errors'
|
17
|
+
require 'mirah/typer/base'
|
18
|
+
require 'mirah/typer/simple'
|
19
19
|
|
20
20
|
module Mirah
|
21
21
|
module Typer
|
@@ -28,390 +28,9 @@ module Mirah
|
|
28
28
|
end
|
29
29
|
|
30
30
|
InferenceError = Mirah::InferenceError
|
31
|
-
|
32
|
-
class BaseTyper
|
33
|
-
include Mirah
|
34
|
-
|
35
|
-
def log(message); Typer.log(message); end
|
36
|
-
|
37
|
-
def to_s
|
38
|
-
name
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
class Simple < BaseTyper
|
43
|
-
attr_accessor :known_types, :errors, :last_chance
|
44
|
-
|
45
|
-
def initialize(self_type)
|
46
|
-
@known_types = {}
|
47
|
-
|
48
|
-
@known_types["self"] = type_reference(nil, self_type)
|
49
|
-
@known_types["fixnum"] = type_reference(nil, "fixnum")
|
50
|
-
@known_types["float"] = type_reference(nil, "float")
|
51
|
-
@known_types["string"] = type_reference(nil, "string")
|
52
|
-
@known_types["boolean"] = type_reference(nil, "boolean")
|
53
|
-
@errors = []
|
54
|
-
end
|
55
|
-
|
56
|
-
def name
|
57
|
-
"Simple"
|
58
|
-
end
|
59
|
-
|
60
|
-
def set_filename(scope, name); end
|
61
|
-
|
62
|
-
def self_type
|
63
|
-
known_types["self"]
|
64
|
-
end
|
65
|
-
|
66
|
-
def default_type
|
67
|
-
nil
|
68
|
-
end
|
69
|
-
|
70
|
-
def fixnum_type(value=0)
|
71
|
-
known_types["fixnum"]
|
72
|
-
end
|
73
|
-
|
74
|
-
def float_type(value=0)
|
75
|
-
known_types["float"]
|
76
|
-
end
|
77
|
-
|
78
|
-
def string_type
|
79
|
-
known_types["string"]
|
80
|
-
end
|
81
|
-
|
82
|
-
def boolean_type
|
83
|
-
known_types["boolean"]
|
84
|
-
end
|
85
|
-
|
86
|
-
def null_type
|
87
|
-
AST::TypeReference::NullType
|
88
|
-
end
|
89
|
-
|
90
|
-
def no_type
|
91
|
-
AST::TypeReference::NoType
|
92
|
-
end
|
93
|
-
|
94
|
-
# to be overridden
|
95
|
-
def array_type
|
96
|
-
AST::TypeReference::NullType
|
97
|
-
end
|
98
|
-
|
99
|
-
# to be overridden
|
100
|
-
def hash_type
|
101
|
-
AST::TypeReference::NullType
|
102
|
-
end
|
103
|
-
|
104
|
-
def known_type(name)
|
105
|
-
@known_types[name]
|
106
|
-
end
|
107
|
-
|
108
|
-
def define_type(scope, name, superclass, interfaces)
|
109
|
-
log "New type defined: '#{name}' < '#{superclass}'"
|
110
|
-
result = type_definition(scope, name, superclass, interfaces)
|
111
|
-
|
112
|
-
# TODO Get rid of known_types["self"]
|
113
|
-
old_self, known_types["self"] = known_types["self"], result
|
114
|
-
yield
|
115
|
-
known_types["self"] = old_self
|
116
|
-
|
117
|
-
result
|
118
|
-
end
|
119
|
-
|
120
|
-
def learn_local_type(scope, name, type)
|
121
|
-
type = scope.learn_local_type(name, known_types[type] || type)
|
122
|
-
log "Learned local type under #{scope} : #{name} = #{type}"
|
123
|
-
type
|
124
|
-
end
|
125
|
-
|
126
|
-
def local_type(scope, name)
|
127
|
-
type = scope.local_type(name)
|
128
|
-
log "Retrieved local type in #{scope} : #{name} = #{type}" if type
|
129
|
-
type
|
130
|
-
end
|
131
|
-
|
132
|
-
def local_types
|
133
|
-
@local_types ||= {}
|
134
|
-
end
|
135
|
-
|
136
|
-
def local_type_hash(scope)
|
137
|
-
local_types[scope] ||= {}
|
138
|
-
end
|
139
|
-
|
140
|
-
def field_types
|
141
|
-
@field_types ||= {}
|
142
|
-
end
|
143
|
-
|
144
|
-
def field_type_hash(cls)
|
145
|
-
field_types[cls] ||= {}
|
146
|
-
end
|
147
|
-
|
148
|
-
def static_field_types
|
149
|
-
@static_field_types ||= {}
|
150
|
-
end
|
151
|
-
|
152
|
-
def static_field_type_hash(cls)
|
153
|
-
static_field_types[cls] ||= {}
|
154
|
-
end
|
155
|
-
|
156
|
-
def infer_signature(method_def)
|
157
|
-
end
|
158
|
-
|
159
|
-
def learn_field_type(cls, name, type)
|
160
|
-
log "Learned field type under #{cls} : #{name} = #{type}"
|
161
|
-
|
162
|
-
# TODO check for compatibility?
|
163
|
-
field_type_hash(cls)[name] ||= known_types[type] || type
|
164
|
-
|
165
|
-
type
|
166
|
-
end
|
167
|
-
|
168
|
-
def field_type(cls, name)
|
169
|
-
field_type_hash(cls)[name]
|
170
|
-
end
|
171
|
-
|
172
|
-
def learn_static_field_type(cls, name, type)
|
173
|
-
log "Learned field type under #{cls} : #{name} = #{type}"
|
174
|
-
|
175
|
-
# TODO check for compatibility?
|
176
|
-
static_field_type_hash(cls)[name] ||= known_types[type] || type
|
177
|
-
|
178
|
-
type
|
179
|
-
end
|
180
|
-
|
181
|
-
def static_field_type(cls, name)
|
182
|
-
static_field_type_hash(cls)[name]
|
183
|
-
end
|
184
|
-
|
185
|
-
def learn_method_type(target_type, name, parameter_types, type, exceptions)
|
186
|
-
log "Learned method #{name} (#{parameter_types}) on #{target_type} = #{type}"
|
187
|
-
|
188
|
-
get_method_type_hash(target_type, name, parameter_types)[:type] = known_types[type] || type
|
189
|
-
|
190
|
-
# if it's any args are imported types, also add a mapping for the expanded name
|
191
|
-
imported_types = parameter_types.map {|param| known_types[param] || param}
|
192
|
-
get_method_type_hash(target_type, name, imported_types)[:type] = type
|
193
|
-
end
|
194
|
-
|
195
|
-
def method_type(target_type, name, parameter_types)
|
196
|
-
if (target_type && target_type.error?) ||
|
197
|
-
parameter_types.any? {|t| t && t.error?}
|
198
|
-
return AST.error_type
|
199
|
-
end
|
200
|
-
constructor = (name == 'new' && target_type && target_type.meta?)
|
201
|
-
|
202
|
-
if constructor
|
203
|
-
# constructor handled different from other methods
|
204
|
-
simple_type = get_method_type_hash(target_type.unmeta, 'initialize', parameter_types)[:type]
|
205
|
-
else
|
206
|
-
simple_type = get_method_type_hash(target_type, name, parameter_types)[:type]
|
207
|
-
end
|
208
|
-
|
209
|
-
|
210
|
-
if !simple_type
|
211
|
-
log "Method type for \"#{name}\" #{parameter_types} on #{target_type} not found."
|
212
|
-
|
213
|
-
# allow plugins a go if we're in the inference phase
|
214
|
-
simple_type = plugins do |plugin|
|
215
|
-
plugin.method_type(self, target_type, name, parameter_types)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
return nil unless simple_type
|
220
|
-
|
221
|
-
if constructor
|
222
|
-
log "Method type for \"#{name}\" #{parameter_types} on #{target_type} = #{target_type}"
|
223
|
-
target_type.unmeta
|
224
|
-
else
|
225
|
-
log "Method type for \"#{name}\" #{parameter_types} on #{target_type} = #{simple_type}"
|
226
|
-
simple_type
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
def plugins
|
231
|
-
if cycling?
|
232
|
-
Mirah.typer_plugins.each do |plugin|
|
233
|
-
log "Invoking plugin: #{plugin}"
|
234
|
-
|
235
|
-
result = yield plugin
|
236
|
-
return result if result
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
nil
|
241
|
-
end
|
242
|
-
|
243
|
-
def cycling?
|
244
|
-
@cycling
|
245
|
-
end
|
246
|
-
|
247
|
-
def cycling=(c)
|
248
|
-
@cycling = c
|
249
|
-
end
|
250
|
-
|
251
|
-
def cycle(count)
|
252
|
-
@cycling = true
|
253
|
-
count.times do |i|
|
254
|
-
begin
|
255
|
-
log "[Cycle #{i}]: Started..."
|
256
|
-
yield i
|
257
|
-
ensure
|
258
|
-
log "[Cycle #{i}]: Complete!"
|
259
|
-
end
|
260
|
-
end
|
261
|
-
ensure
|
262
|
-
@cycling = false
|
263
|
-
end
|
264
|
-
|
265
|
-
def method_types
|
266
|
-
@method_types ||= {}
|
267
|
-
end
|
268
|
-
|
269
|
-
def get_method_type_hash(target_type, name, parameter_types)
|
270
|
-
method_types[target_type] ||= {}
|
271
|
-
method_types[target_type][name] ||= {}
|
272
|
-
method_types[target_type][name][parameter_types.size] ||= {}
|
273
|
-
|
274
|
-
current = method_types[target_type][name][parameter_types.size]
|
275
|
-
|
276
|
-
parameter_types.each {|type| current[type] ||= {}; current = current[type]}
|
277
|
-
|
278
|
-
current
|
279
|
-
end
|
280
|
-
|
281
|
-
def type_reference(scope, name, array=false, meta=false)
|
282
|
-
AST::TypeReference.new(name, array, meta)
|
283
|
-
end
|
284
|
-
|
285
|
-
def type_definition(scope, name, superclass, interfaces)
|
286
|
-
AST::TypeDefinition.new(name, AST::TypeReference.new(superclass), interfaces)
|
287
|
-
end
|
288
|
-
|
289
|
-
def deferred_nodes
|
290
|
-
@deferred_nodes ||= {}
|
291
|
-
end
|
292
|
-
|
293
|
-
def infer(node, expression=true)
|
294
|
-
begin
|
295
|
-
node.infer(self, expression)
|
296
|
-
rescue InferenceError => ex
|
297
|
-
ex.node ||= node
|
298
|
-
error(node, ex)
|
299
|
-
rescue Exception => ex
|
300
|
-
raise Mirah::InternalCompilerError.wrap(ex, node)
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
def error(node, error_or_msg=nil, backtrace=nil)
|
305
|
-
if error_or_msg.kind_of? InferenceError
|
306
|
-
error = error_or_msg
|
307
|
-
elsif error_or_msg
|
308
|
-
error = InferenceError.new(error_or_msg, node)
|
309
|
-
error.set_backtrace(backtrace) if backtrace
|
310
|
-
else
|
311
|
-
error = InferenceError.new("Unable to infer type.", node)
|
312
|
-
end
|
313
|
-
@errors << error
|
314
|
-
node.resolve_if(self) do
|
315
|
-
AST.error_type
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
def defer(node, error_message=nil)
|
320
|
-
if @error_next
|
321
|
-
log "Marking #{node} as an error"
|
322
|
-
@error_next = false
|
323
|
-
error(node, error_message)
|
324
|
-
else
|
325
|
-
raise "Can't defer nil" if node.nil?
|
326
|
-
return if deferred_nodes.include? node
|
327
|
-
log "Deferring inference for #{node}"
|
328
|
-
|
329
|
-
deferred_nodes[node] = self_type
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
def resolve(raise = false)
|
334
|
-
count = deferred_nodes.size + 1
|
335
|
-
|
336
|
-
log "Entering type inference cycle"
|
337
|
-
|
338
|
-
retried = false
|
339
|
-
cycle(count) do |i|
|
340
|
-
old_deferred = @deferred_nodes
|
341
|
-
@deferred_nodes = {}
|
342
|
-
old_deferred.each do |node, saved_type|
|
343
|
-
known_types["self"] = saved_type
|
344
|
-
type = infer(node)
|
345
|
-
|
346
|
-
log "[Cycle #{i}]: Inferred type for #{node}: #{type || 'FAILED'}"
|
347
|
-
|
348
|
-
if type == default_type
|
349
|
-
@deferred_nodes[node] = saved_type
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
if @deferred_nodes.size == 0
|
354
|
-
log "[Cycle #{i}]: Resolved all types, exiting"
|
355
|
-
break
|
356
|
-
elsif old_deferred == @deferred_nodes
|
357
|
-
if @error_next || retried
|
358
|
-
log "[Cycle #{i}]: Made no progress, bailing out"
|
359
|
-
break
|
360
|
-
elsif @last_chance
|
361
|
-
# Retry this iteration, and mark the first deferred
|
362
|
-
# type as an error.
|
363
|
-
retried = true
|
364
|
-
@error_next = true
|
365
|
-
redo
|
366
|
-
else
|
367
|
-
# This is a hack for default constructor support. The right fix
|
368
|
-
# is probably to check the AST for constructors. Instead we
|
369
|
-
# tell the plugins that we're near the end of inference so they
|
370
|
-
# can assume no new constructors are being added. You could
|
371
|
-
# easily write some circular constructors that would compile
|
372
|
-
# with this technique but fail to run.
|
373
|
-
@last_chance = true
|
374
|
-
redo
|
375
|
-
end
|
376
|
-
end
|
377
|
-
retried = false
|
378
|
-
end
|
379
|
-
|
380
|
-
# done with n sweeps, if any remain mark them as errors
|
381
|
-
error_nodes = @errors.map {|e| e.node}
|
382
|
-
(deferred_nodes.keys - error_nodes).each do |deferred_node|
|
383
|
-
error_nodes << deferred_node
|
384
|
-
error(deferred_node)
|
385
|
-
end
|
386
|
-
if raise && !error_nodes.empty?
|
387
|
-
msg = "Could not infer typing for nodes:"
|
388
|
-
error_nodes.map do |e|
|
389
|
-
msg << "\n "
|
390
|
-
msg << "#{e.inspect} at line #{e.line_number} (child of #{e.parent})"
|
391
|
-
end
|
392
|
-
raise InferenceError.new(msg)
|
393
|
-
end
|
394
|
-
end
|
395
|
-
end
|
396
31
|
end
|
397
32
|
|
398
33
|
def self.typer_plugins
|
399
34
|
@typer_plugins ||= []
|
400
35
|
end
|
401
|
-
end
|
402
|
-
|
403
|
-
if __FILE__ == $0
|
404
|
-
Mirah::AST.verbose = true
|
405
|
-
Mirah::Typer.verbose = true
|
406
|
-
ast = Mirah::AST.parse(File.read(ARGV[0]))
|
407
|
-
typer = Mirah::Typer::Simple.new("script")
|
408
|
-
typer.infer(ast)
|
409
|
-
begin
|
410
|
-
typer.resolve(true)
|
411
|
-
rescue Mirah::Typer::InferenceError => e
|
412
|
-
puts e.message
|
413
|
-
end
|
414
|
-
|
415
|
-
puts "\nAST:"
|
416
|
-
p ast
|
417
36
|
end
|