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