mirah 0.0.7-java → 0.0.8-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. data/History.txt +181 -0
  2. data/README.txt +6 -10
  3. data/Rakefile +86 -9
  4. data/bin/mirah +2 -0
  5. data/bin/mirahc +2 -0
  6. data/bin/mirahp +2 -0
  7. data/{bin/dubyp → examples/interfaces.mirah} +16 -9
  8. data/examples/macros/square.mirah +12 -0
  9. data/examples/macros/square_int.mirah +12 -0
  10. data/examples/macros/string-each-char.mirah +14 -0
  11. data/examples/maven/README.txt +2 -0
  12. data/examples/maven/pom.xml +23 -0
  13. data/examples/maven/src/main/mirah/hello_mirah.mirah +9 -0
  14. data/examples/rosettacode/100-doors.mirah +44 -0
  15. data/examples/rosettacode/99-bottles-of-beer.mirah +13 -0
  16. data/examples/rosettacode/README.txt +9 -0
  17. data/examples/rosettacode/boolean-values.mirah +29 -0
  18. data/examples/rosettacode/comments.mirah +2 -0
  19. data/examples/rosettacode/copy-a-string.mirah +10 -0
  20. data/examples/rosettacode/count-occurrences-of-a-substring.mirah +40 -0
  21. data/examples/rosettacode/create-a-file.mirah +6 -0
  22. data/examples/rosettacode/empty-string.mirah +9 -0
  23. data/examples/rosettacode/factorial.mirah +10 -0
  24. data/examples/rosettacode/fibonacci.mirah +21 -0
  25. data/examples/rosettacode/file-size.mirah +5 -0
  26. data/examples/rosettacode/fizz-buzz.mirah +21 -0
  27. data/examples/rosettacode/flatten-a-list.mirah +24 -0
  28. data/examples/rosettacode/guess-the-number.mirah +21 -0
  29. data/examples/rosettacode/is-string-numeric.mirah +127 -0
  30. data/examples/rosettacode/palindrome.mirah +14 -0
  31. data/examples/rosettacode/repeat-a-string.mirah +9 -0
  32. data/examples/rosettacode/reverse-a-string.mirah +6 -0
  33. data/examples/rosettacode/rot-13.mirah +20 -0
  34. data/examples/rosettacode/user-input.mirah +4 -0
  35. data/examples/sort_closure.mirah +1 -1
  36. data/javalib/dynalink-0.2.jar +0 -0
  37. data/javalib/mirah-bootstrap.jar +0 -0
  38. data/lib/mirah.rb +7 -16
  39. data/lib/mirah/ast.rb +22 -92
  40. data/lib/mirah/ast/call.rb +41 -9
  41. data/lib/mirah/ast/class.rb +34 -6
  42. data/lib/mirah/ast/flow.rb +17 -5
  43. data/lib/mirah/ast/intrinsics.rb +50 -8
  44. data/lib/mirah/ast/literal.rb +7 -0
  45. data/lib/mirah/ast/local.rb +9 -1
  46. data/lib/mirah/ast/method.rb +21 -8
  47. data/lib/mirah/ast/scope.rb +1 -1
  48. data/lib/mirah/ast/structure.rb +81 -15
  49. data/lib/mirah/ast/type.rb +4 -0
  50. data/{bin/dubyc → lib/mirah/commands.rb} +4 -11
  51. data/lib/mirah/commands/base.rb +54 -0
  52. data/lib/mirah/commands/compile.rb +39 -0
  53. data/{examples/wiki/Rakefile → lib/mirah/commands/parse.rb} +18 -17
  54. data/lib/mirah/commands/run.rb +73 -0
  55. data/lib/mirah/compiler.rb +37 -417
  56. data/lib/mirah/compiler/call.rb +45 -0
  57. data/lib/mirah/compiler/class.rb +81 -0
  58. data/lib/mirah/compiler/flow.rb +109 -0
  59. data/lib/mirah/compiler/literal.rb +130 -0
  60. data/lib/mirah/compiler/local.rb +59 -0
  61. data/lib/mirah/compiler/method.rb +44 -0
  62. data/lib/mirah/compiler/structure.rb +65 -0
  63. data/lib/mirah/compiler/type.rb +27 -0
  64. data/lib/mirah/env.rb +4 -6
  65. data/lib/mirah/generator.rb +61 -0
  66. data/lib/mirah/jvm/compiler.rb +8 -867
  67. data/lib/mirah/jvm/compiler/base.rb +270 -0
  68. data/lib/mirah/jvm/compiler/java_source.rb +779 -0
  69. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +851 -0
  70. data/lib/mirah/jvm/method_lookup.rb +21 -2
  71. data/lib/mirah/jvm/source_generator/builder.rb +10 -13
  72. data/lib/mirah/jvm/source_generator/loops.rb +99 -93
  73. data/lib/mirah/jvm/source_generator/precompile.rb +3 -2
  74. data/lib/mirah/jvm/typer.rb +3 -3
  75. data/lib/mirah/jvm/types.rb +10 -426
  76. data/lib/mirah/jvm/types/array_type.rb +62 -0
  77. data/lib/mirah/jvm/types/basic_types.rb +1 -0
  78. data/lib/mirah/jvm/types/dynamic_type.rb +46 -0
  79. data/lib/mirah/jvm/types/factory.rb +23 -5
  80. data/lib/mirah/jvm/types/interface_definition.rb +20 -0
  81. data/lib/mirah/jvm/types/intrinsics.rb +15 -3
  82. data/lib/mirah/jvm/types/meta_type.rb +45 -0
  83. data/lib/mirah/jvm/types/methods.rb +12 -5
  84. data/lib/mirah/jvm/types/null_type.rb +27 -0
  85. data/lib/mirah/jvm/types/primitive_type.rb +38 -0
  86. data/lib/mirah/jvm/types/source_mirror.rb +266 -0
  87. data/lib/mirah/jvm/types/type.rb +173 -0
  88. data/lib/mirah/jvm/types/type_definition.rb +55 -0
  89. data/lib/mirah/jvm/types/unreachable_type.rb +27 -0
  90. data/lib/mirah/jvm/types/void_type.rb +19 -0
  91. data/lib/mirah/parser.rb +90 -0
  92. data/lib/mirah/plugin/gwt.rb +5 -5
  93. data/lib/mirah/plugin/java.rb +1 -1
  94. data/lib/mirah/transform.rb +4 -321
  95. data/lib/mirah/transform/ast_ext.rb +63 -0
  96. data/lib/mirah/transform/error.rb +13 -0
  97. data/lib/mirah/transform/helper.rb +761 -0
  98. data/lib/mirah/transform/transformer.rb +255 -0
  99. data/lib/mirah/typer.rb +2 -383
  100. data/{bin/duby → lib/mirah/typer/base.rb} +12 -10
  101. data/lib/mirah/typer/simple.rb +377 -0
  102. data/lib/mirah/util/argument_processor.rb +114 -0
  103. data/lib/mirah/util/class_loader.rb +37 -0
  104. data/lib/mirah/util/compilation_state.rb +51 -0
  105. data/lib/mirah/util/process_errors.rb +33 -0
  106. data/lib/mirah/version.rb +1 -1
  107. data/lib/mirah_task.rb +3 -2
  108. data/test/{test_ast.rb → core/test_ast.rb} +6 -0
  109. data/test/{test_compilation.rb → core/test_compilation.rb} +0 -0
  110. data/test/{test_env.rb → core/test_env.rb} +24 -25
  111. data/test/{test_macros.rb → core/test_macros.rb} +2 -4
  112. data/test/{test_typer.rb → core/test_typer.rb} +0 -3
  113. data/test/jvm/bytecode_test_helper.rb +181 -0
  114. data/test/{test_javac_compiler.rb → jvm/javac_test_helper.rb} +38 -22
  115. data/test/jvm/test_enumerable.rb +304 -0
  116. data/test/{test_java_typer.rb → jvm/test_java_typer.rb} +2 -4
  117. data/test/{test_jvm_compiler.rb → jvm/test_jvm_compiler.rb} +146 -443
  118. data/test/jvm/test_macros.rb +147 -0
  119. data/test/jvm/test_main_method.rb +15 -0
  120. data/test/{test_gwt.rb → plugins/test_gwt.rb} +0 -2
  121. metadata +103 -91
  122. data/bin/jrubyp +0 -52
  123. data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +0 -339
  124. data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +0 -42
  125. data/examples/wiki/src/org/mirah/wiki/error.eduby.html +0 -2
  126. data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +0 -69
  127. data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +0 -7
  128. data/examples/wiki/src/org/mirah/wiki/view.eduby.html +0 -15
  129. data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
  130. data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
  131. data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
  132. data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
  133. data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
  134. data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
  135. data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
  136. data/examples/wiki/war/app.yaml +0 -21
  137. data/examples/wiki/war/public/favicon.ico +0 -0
  138. data/examples/wiki/war/public/images/appengine_duby.png +0 -0
  139. data/examples/wiki/war/public/images/back.gif +0 -0
  140. data/examples/wiki/war/public/images/dir.gif +0 -0
  141. data/examples/wiki/war/public/images/file.gif +0 -0
  142. data/examples/wiki/war/public/javascripts/prettify.js +0 -61
  143. data/examples/wiki/war/public/robots.txt +0 -0
  144. data/examples/wiki/war/public/stylesheets/main.css +0 -156
  145. data/examples/wiki/war/public/stylesheets/prettify.css +0 -1
  146. data/examples/wiki/war/public/stylesheets/sh_style.css +0 -66
  147. data/examples/wiki/war/public/stylesheets/source.css +0 -21
  148. data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
  149. data/examples/wiki/war/public/wmd/images/bg.png +0 -0
  150. data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
  151. data/examples/wiki/war/public/wmd/images/bold.png +0 -0
  152. data/examples/wiki/war/public/wmd/images/code.png +0 -0
  153. data/examples/wiki/war/public/wmd/images/h1.png +0 -0
  154. data/examples/wiki/war/public/wmd/images/hr.png +0 -0
  155. data/examples/wiki/war/public/wmd/images/img.png +0 -0
  156. data/examples/wiki/war/public/wmd/images/italic.png +0 -0
  157. data/examples/wiki/war/public/wmd/images/link.png +0 -0
  158. data/examples/wiki/war/public/wmd/images/ol.png +0 -0
  159. data/examples/wiki/war/public/wmd/images/redo.png +0 -0
  160. data/examples/wiki/war/public/wmd/images/separator.png +0 -0
  161. data/examples/wiki/war/public/wmd/images/ul.png +0 -0
  162. data/examples/wiki/war/public/wmd/images/undo.png +0 -0
  163. data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
  164. data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
  165. data/examples/wiki/war/public/wmd/showdown.js +0 -421
  166. data/examples/wiki/war/public/wmd/wmd-base.js +0 -1799
  167. data/examples/wiki/war/public/wmd/wmd-plus.js +0 -311
  168. data/examples/wiki/war/public/wmd/wmd.js +0 -73
  169. data/examples/wiki/war/src/org/mirah/wiki/MirahWiki.duby +0 -339
  170. data/examples/wiki/war/src/org/mirah/wiki/edit.eduby.html +0 -42
  171. data/examples/wiki/war/src/org/mirah/wiki/error.eduby.html +0 -2
  172. data/examples/wiki/war/src/org/mirah/wiki/layout.eduby.html +0 -69
  173. data/examples/wiki/war/src/org/mirah/wiki/parser.eduby.html +0 -7
  174. data/examples/wiki/war/src/org/mirah/wiki/view.eduby.html +0 -15
  175. data/javalib/dynalink-0.1.jar +0 -0
  176. data/javalib/jsr292-mock.jar +0 -0
  177. data/lib/mirah/class_loader.rb +0 -35
  178. data/lib/mirah/compilation_state.rb +0 -28
  179. data/lib/mirah/impl.rb +0 -273
  180. data/lib/mirah/jvm/base.rb +0 -267
  181. data/lib/mirah/jvm/source_compiler.rb +0 -760
  182. 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
@@ -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