mirah 0.0.12-java → 0.1.0-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 (171) hide show
  1. data/History.txt +372 -0
  2. data/README.txt +4 -5
  3. data/Rakefile +178 -55
  4. data/examples/appengine/Readme +3 -3
  5. data/examples/appengine/src/org/mirah/MirahApp.mirah +1 -1
  6. data/examples/appengine/src/org/mirah/list.dhtml +1 -1
  7. data/examples/bintrees.mirah +1 -1
  8. data/examples/edb.mirah +1 -1
  9. data/examples/fib.mirah +1 -1
  10. data/examples/interfaces.mirah +1 -1
  11. data/examples/macros/{string-each-char.mirah → string_each_char.mirah} +4 -5
  12. data/examples/maven/README.txt +1 -1
  13. data/examples/maven/src/main/mirah/hello_mirah.mirah +1 -1
  14. data/examples/plugins/appengine/Rakefile +1 -1
  15. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/MetaModel.mirah +1 -1
  16. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +1 -1
  17. data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +1 -1
  18. data/examples/rosettacode/100-doors.mirah +6 -6
  19. data/examples/rosettacode/README.txt +3 -3
  20. data/examples/rosettacode/boolean-values.mirah +1 -1
  21. data/examples/rosettacode/comments.mirah +1 -1
  22. data/examples/rosettacode/count-occurrences-of-a-substring.mirah +1 -1
  23. data/examples/rosettacode/factorial.mirah +1 -1
  24. data/examples/rosettacode/fibonacci.mirah +1 -1
  25. data/examples/rosettacode/fizz-buzz.mirah +2 -2
  26. data/examples/rosettacode/flatten-a-list.mirah +4 -4
  27. data/examples/rosettacode/guess-the-number.mirah +2 -2
  28. data/examples/rosettacode/hamming-numbers.mirah +4 -4
  29. data/examples/rosettacode/is-string-numeric.mirah +22 -22
  30. data/examples/rosettacode/palindrome.mirah +2 -2
  31. data/examples/rosettacode/random-numbers.mirah +1 -1
  32. data/examples/rosettacode/repeat-a-string.mirah +1 -1
  33. data/examples/rosettacode/reverse-a-string.mirah +1 -1
  34. data/examples/rosettacode/rot-13.mirah +5 -5
  35. data/examples/rosettacode/secure-temporary-file.mirah +2 -2
  36. data/examples/rosettacode/sleep.mirah +1 -1
  37. data/examples/rosettacode/string-length.mirah +5 -5
  38. data/examples/swing.mirah +1 -1
  39. data/examples/test.edb +1 -1
  40. data/javalib/mirah-bootstrap.jar +0 -0
  41. data/javalib/mirah-builtins.jar +0 -0
  42. data/javalib/mirah-parser.jar +0 -0
  43. data/javalib/mirah-util.jar +0 -0
  44. data/lib/duby.rb +1 -1
  45. data/lib/mirah.rb +50 -28
  46. data/lib/mirah/ast.rb +15 -605
  47. data/lib/mirah/ast/scope.rb +98 -69
  48. data/lib/mirah/commands.rb +1 -1
  49. data/lib/mirah/commands/base.rb +7 -7
  50. data/lib/mirah/commands/compile.rb +3 -3
  51. data/lib/mirah/commands/parse.rb +7 -5
  52. data/lib/mirah/commands/run.rb +12 -19
  53. data/lib/mirah/compiler.rb +15 -23
  54. data/lib/mirah/errors.rb +16 -1
  55. data/lib/mirah/generator.rb +79 -39
  56. data/lib/mirah/jvm/compiler.rb +1 -19
  57. data/lib/mirah/jvm/compiler/base.rb +233 -90
  58. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +675 -363
  59. data/lib/mirah/jvm/method_lookup.rb +134 -65
  60. data/lib/mirah/jvm/typer.rb +10 -5
  61. data/lib/mirah/jvm/types.rb +10 -2
  62. data/lib/mirah/jvm/types/array_type.rb +10 -12
  63. data/lib/mirah/{compiler/type.rb → jvm/types/ast_ext.rb} +12 -8
  64. data/lib/mirah/jvm/types/basic_types.rb +26 -33
  65. data/lib/mirah/jvm/types/bitescript_ext.rb +1 -1
  66. data/lib/mirah/jvm/types/block_type.rb +15 -0
  67. data/lib/mirah/jvm/types/boolean.rb +8 -4
  68. data/lib/mirah/jvm/types/dynamic_type.rb +12 -13
  69. data/lib/mirah/jvm/types/enumerable.rb +7 -7
  70. data/lib/mirah/jvm/types/extensions.rb +11 -6
  71. data/lib/mirah/jvm/types/factory.rb +624 -94
  72. data/lib/mirah/jvm/types/floats.rb +21 -15
  73. data/lib/mirah/jvm/types/generic_type.rb +72 -0
  74. data/lib/mirah/jvm/types/implicit_nil_type.rb +29 -0
  75. data/lib/mirah/jvm/types/integers.rb +26 -71
  76. data/lib/mirah/jvm/types/interface_definition.rb +3 -3
  77. data/lib/mirah/jvm/types/intrinsics.rb +203 -168
  78. data/lib/mirah/jvm/types/literals.rb +6 -6
  79. data/lib/mirah/jvm/types/meta_type.rb +13 -4
  80. data/lib/mirah/jvm/types/methods.rb +281 -93
  81. data/lib/mirah/jvm/types/null_type.rb +17 -5
  82. data/lib/mirah/jvm/types/number.rb +10 -7
  83. data/lib/mirah/jvm/types/primitive_type.rb +17 -6
  84. data/lib/mirah/jvm/types/source_mirror.rb +12 -7
  85. data/lib/mirah/jvm/types/type.rb +107 -23
  86. data/lib/mirah/jvm/types/type_definition.rb +25 -10
  87. data/lib/mirah/jvm/types/unreachable_type.rb +1 -1
  88. data/lib/mirah/jvm/types/void_type.rb +3 -3
  89. data/lib/mirah/parser.rb +154 -16
  90. data/lib/mirah/plugin/edb.rb +1 -1
  91. data/lib/mirah/transform.rb +1 -2
  92. data/lib/mirah/transform/ast_ext.rb +24 -43
  93. data/lib/mirah/transform/transformer.rb +29 -224
  94. data/lib/mirah/typer.rb +2 -16
  95. data/lib/mirah/util/argument_processor.rb +25 -10
  96. data/lib/mirah/util/class_loader.rb +1 -1
  97. data/lib/mirah/util/compilation_state.rb +16 -17
  98. data/lib/mirah/util/delegate.rb +2 -2
  99. data/lib/mirah/util/logging.rb +110 -0
  100. data/lib/mirah/util/process_errors.rb +69 -11
  101. data/lib/mirah/version.rb +1 -1
  102. data/test/core/commands_test.rb +6 -24
  103. data/test/core/env_test.rb +5 -5
  104. data/{lib/mirah/jvm/source_generator/typer.rb → test/core/generator_test.rb} +9 -9
  105. data/test/core/typer_test.rb +196 -158
  106. data/test/core/util/argument_processor_test.rb +10 -10
  107. data/test/core/util/class_loader_test.rb +6 -5
  108. data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
  109. data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
  110. data/test/fixtures/org/foo/LowerCaseInnerClass.java +7 -0
  111. data/test/jvm/annotations_test.rb +5 -5
  112. data/test/jvm/blocks_test.rb +140 -88
  113. data/test/jvm/bytecode_test_helper.rb +112 -94
  114. data/test/jvm/cast_test.rb +162 -0
  115. data/test/jvm/constructors_test.rb +18 -8
  116. data/test/jvm/enumerable_test.rb +77 -44
  117. data/test/jvm/example_test.rb +53 -0
  118. data/test/jvm/factory_test.rb +7 -1
  119. data/test/jvm/generics_test.rb +57 -0
  120. data/test/jvm/hash_test.rb +106 -0
  121. data/test/jvm/import_test.rb +81 -0
  122. data/test/jvm/interface_test.rb +73 -0
  123. data/test/jvm/java_typer_test.rb +92 -66
  124. data/{lib/mirah/typer/base.rb → test/jvm/jvm_commands_test.rb} +6 -10
  125. data/test/jvm/jvm_compiler_test.rb +170 -604
  126. data/test/jvm/list_extensions_test.rb +23 -0
  127. data/test/jvm/macros_test.rb +197 -32
  128. data/test/jvm/main_method_test.rb +4 -4
  129. data/test/jvm/numeric_extensions_test.rb +13 -0
  130. data/test/jvm/rescue_test.rb +73 -16
  131. data/test/jvm/varargs_test.rb +65 -0
  132. data/test/test_helper.rb +1 -2
  133. metadata +234 -251
  134. data/examples/SortClosure$__xform_tmp_1.class +0 -0
  135. data/examples/SortClosure$__xform_tmp_2.class +0 -0
  136. data/examples/SortClosure.class +0 -0
  137. data/examples/macros/StringEachChar$Extension1.class +0 -0
  138. data/lib/mirah/ast/call.rb +0 -345
  139. data/lib/mirah/ast/class.rb +0 -359
  140. data/lib/mirah/ast/flow.rb +0 -381
  141. data/lib/mirah/ast/intrinsics.rb +0 -563
  142. data/lib/mirah/ast/literal.rb +0 -178
  143. data/lib/mirah/ast/local.rb +0 -112
  144. data/lib/mirah/ast/method.rb +0 -408
  145. data/lib/mirah/ast/structure.rb +0 -387
  146. data/lib/mirah/ast/type.rb +0 -146
  147. data/lib/mirah/commands/base.rb~ +0 -57
  148. data/lib/mirah/compiler/call.rb +0 -45
  149. data/lib/mirah/compiler/class.rb +0 -81
  150. data/lib/mirah/compiler/flow.rb +0 -109
  151. data/lib/mirah/compiler/literal.rb +0 -130
  152. data/lib/mirah/compiler/local.rb +0 -59
  153. data/lib/mirah/compiler/method.rb +0 -44
  154. data/lib/mirah/compiler/structure.rb +0 -65
  155. data/lib/mirah/jvm/compiler/java_source.rb +0 -787
  156. data/lib/mirah/jvm/method_lookup.rb~ +0 -247
  157. data/lib/mirah/jvm/source_generator/builder.rb +0 -468
  158. data/lib/mirah/jvm/source_generator/loops.rb +0 -131
  159. data/lib/mirah/jvm/source_generator/precompile.rb +0 -210
  160. data/lib/mirah/plugin/gwt.rb +0 -189
  161. data/lib/mirah/plugin/java.rb +0 -70
  162. data/lib/mirah/transform/error.rb +0 -13
  163. data/lib/mirah/transform/helper.rb +0 -765
  164. data/lib/mirah/typer/simple.rb +0 -384
  165. data/lib/mirah/version.rb~ +0 -18
  166. data/test/core/ast_test.rb +0 -382
  167. data/test/core/compilation_test.rb +0 -130
  168. data/test/core/macros_test.rb +0 -61
  169. data/test/jvm/javac_test_helper.rb +0 -89
  170. data/test/jvm/jvm_compiler_test.rb~ +0 -2181
  171. data/test/plugins/gwt_test.rb +0 -69
@@ -1,381 +0,0 @@
1
- # Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
2
- # All contributing project authors may be found in the NOTICE file.
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- module Mirah
17
- module AST
18
- class Condition < Node
19
- child :predicate
20
-
21
- def initialize(parent, line_number, &block)
22
- super(parent, line_number, &block)
23
- end
24
-
25
- def infer(typer, expression)
26
- unless resolved?
27
- @inferred_type = typer.infer(predicate, true)
28
- if @inferred_type && !@inferred_type.primitive?
29
- call = Call.new(parent, position, '!=') do |call|
30
- predicate.parent = call
31
- [predicate, [Null.new(call, position)]]
32
- end
33
- self.predicate = call
34
- @inferred_type = typer.infer(predicate, true)
35
- end
36
-
37
- @inferred_type ? resolved! : typer.defer(self)
38
- end
39
-
40
- @inferred_type
41
- end
42
- end
43
-
44
- class If < Node
45
- child :condition
46
- child :body
47
- child :else
48
-
49
- def initialize(parent, line_number, &block)
50
- super(parent, line_number, &block)
51
- end
52
-
53
- def infer(typer, expression)
54
- unless resolved?
55
- condition_type = typer.infer(condition, true)
56
- unless condition_type
57
- typer.defer(condition)
58
- end
59
-
60
- # condition type is unrelated to body types, so we proceed with bodies
61
- then_type = typer.infer(body, expression) if body
62
- else_type = typer.infer(self.else, expression) if self.else
63
-
64
- if expression
65
- have_body_type = body.nil? || then_type
66
- have_else_type = self.else.nil? || else_type
67
-
68
- if have_body_type && have_else_type
69
- if then_type && else_type
70
- # both then and else inferred, ensure they're compatible
71
- if then_type.compatible?(else_type)
72
- # types are compatible...if condition is resolved, we're done
73
- @inferred_type = then_type.narrow(else_type)
74
- resolved! if condition_type
75
- else
76
- raise Mirah::Typer::InferenceError.new("if statement with incompatible result types #{then_type} and #{else_type}")
77
- end
78
- else
79
- @inferred_type = then_type || else_type
80
- resolved!
81
- end
82
- else
83
- typer.defer(self)
84
- end
85
- else
86
- @inferred_type = typer.no_type
87
- resolved!
88
- end
89
- end
90
-
91
- @inferred_type
92
- end
93
- end
94
-
95
- class Loop < Node
96
- child :init
97
- child :condition
98
- child :pre
99
- child :body
100
- child :post
101
- attr_accessor :check_first, :negative, :redo
102
-
103
- def initialize(parent, position, check_first, negative, &block)
104
- @check_first = check_first
105
- @negative = negative
106
-
107
- @children = [
108
- Body.new(self, position),
109
- nil,
110
- Body.new(self, position),
111
- nil,
112
- Body.new(self, position),
113
- ]
114
- super(parent, position) do |l|
115
- condition, body = yield(l)
116
- [self.init, condition, self.pre, body, self.post]
117
- end
118
- end
119
-
120
- def infer(typer, expression)
121
- unless resolved?
122
- child_types = children.map do |c|
123
- if c.nil? || (Body === c && c.empty?)
124
- typer.no_type
125
- else
126
- typer.infer(c, true)
127
- end
128
- end
129
- if child_types.any? {|t| t.nil?}
130
- typer.defer(self)
131
- else
132
- resolved!
133
- @inferred_type = typer.null_type
134
- end
135
- end
136
-
137
- @inferred_type
138
- end
139
-
140
- def check_first?; @check_first; end
141
- def negative?; @negative; end
142
-
143
- def redo?
144
- if @redo.nil?
145
- nodes = @children.dup
146
- until nodes.empty?
147
- node = nodes.shift
148
- while node.respond_to?(:inlined) && node.inlined
149
- node = node.inlined
150
- end
151
- next if node.nil? || Loop === node
152
- if Redo === node
153
- return @redo = true
154
- end
155
- nodes.insert(-1, *node.children.flatten)
156
- end
157
- return @redo = false
158
- else
159
- @redo
160
- end
161
- end
162
-
163
- def init?
164
- init && !(init.kind_of?(Body) && init.empty?)
165
- end
166
-
167
- def pre?
168
- pre && !(pre.kind_of?(Body) && pre.empty?)
169
- end
170
-
171
- def post?
172
- post && !(post.kind_of?(Body) && post.empty?)
173
- end
174
-
175
- def to_s
176
- "Loop(check_first = #{check_first?}, negative = #{negative?})"
177
- end
178
- end
179
-
180
- class Not < Node
181
- def initialize(parent, line_number, &block)
182
- super(parent, line_number, &block)
183
- end
184
- end
185
-
186
- class Return < Node
187
- include Valued
188
-
189
- child :value
190
-
191
- def initialize(parent, line_number, &block)
192
- super(parent, line_number, &block)
193
- end
194
-
195
- def infer(typer, expression)
196
- resolve_if(typer) do
197
- if value
198
- typer.infer(value, true)
199
- else
200
- typer.no_type
201
- end
202
- end
203
- end
204
- end
205
-
206
- class Break < Node;
207
- def infer(typer, expression)
208
- unless resolved?
209
- resolved!
210
- @inferred_type = typer.null_type
211
- end
212
- @inferred_type
213
- end
214
- end
215
-
216
- class Next < Break; end
217
-
218
- class Redo < Break; end
219
-
220
- class Raise < Node
221
- include Valued
222
-
223
- child :exception
224
-
225
- def initialize(parent, line_number, &block)
226
- super(parent, line_number, &block)
227
- end
228
-
229
- def infer(typer, expression)
230
- unless resolved?
231
- @inferred_type = AST.unreachable_type
232
- throwable = AST.type(nil, 'java.lang.Throwable')
233
- if children.size == 1
234
- arg_type = typer.infer(self.exception, true)
235
- unless arg_type
236
- typer.defer(self)
237
- return
238
- end
239
- if throwable.compatible?(arg_type) && !arg_type.meta?
240
- resolved!
241
- return @inferred_type
242
- end
243
- end
244
-
245
- arg_types = children.map {|c| typer.infer(c, true)}
246
- if arg_types.any? {|c| c.nil?}
247
- typer.defer(self)
248
- else
249
- if arg_types[0] && throwable.compatible?(arg_types[0])
250
- klass = children.shift
251
- else
252
- klass = Constant.new(self, position, 'RuntimeException')
253
- end
254
- exception = Call.new(self, position, 'new') do
255
- [klass, children, nil]
256
- end
257
- resolved!
258
- @children = [exception]
259
- typer.infer(exception, true)
260
- end
261
- end
262
- @inferred_type
263
- end
264
- end
265
-
266
- defmacro('raise') do |transformer, fcall, parent|
267
- Raise.new(parent, fcall.position) do |raise_node|
268
- fcall.parameters
269
- end
270
- end
271
-
272
- class RescueClause < Node
273
- include Scope
274
- include Scoped
275
- attr_accessor :name, :type, :types
276
- child :type_nodes
277
- child :body
278
-
279
- def initialize(parent, position)
280
- super(parent, position) do
281
- static_scope.parent = scope.static_scope
282
- yield(self) if block_given?
283
- end
284
- end
285
-
286
- def infer(typer, expression)
287
- unless resolved?
288
- @types ||= type_nodes.map {|n| n.type_reference(typer)}
289
- if name
290
- static_scope.shadow(name)
291
- # TODO find the common parent Throwable
292
- @type = types.size == 1 ? types[0] : AST.type(nil, 'java.lang.Throwable')
293
- typer.learn_local_type(static_scope, name, @type)
294
- end
295
- @inferred_type = typer.infer(body, true)
296
-
297
- (@inferred_type && body.resolved?) ? resolved! : typer.defer(self)
298
- end
299
-
300
- @inferred_type
301
- end
302
-
303
- def binding_type(mirah=nil)
304
- static_scope.parent.binding_type(defining_class, mirah)
305
- end
306
-
307
- def binding_type=(type)
308
- static_scope.parent.binding_type = type
309
- end
310
-
311
- def has_binding?
312
- static_scope.parent.has_binding?
313
- end
314
- end
315
-
316
- class Rescue < Node
317
- child :body
318
- child :clauses
319
- child :else_node
320
-
321
- def initialize(parent, position, &block)
322
- super(parent, position, &block)
323
- end
324
-
325
- def infer(typer, expression)
326
- unless resolved?
327
- # TODO: generalize this s.t.
328
- # the problem with deferred inference
329
- # assuming expression == true is dealt with
330
- @expression = expression if @expression == nil
331
- expression = @expression
332
-
333
- primary_type = if else_node
334
- typer.infer(body, false) if body
335
- typer.infer(else_node, expression)
336
- elsif body
337
- typer.infer(body, expression)
338
- end
339
-
340
- clause_types = clauses.map {|c| typer.infer(c, expression)}
341
- types = []
342
- types << primary_type if primary_type
343
- types += clause_types
344
- if types.any? {|t| t.nil?}
345
- typer.defer(self)
346
- else
347
- if !expression || primary_type.nil? || clause_types.all?{ |t| primary_type.compatible? t}
348
- resolved!
349
- types.each do |type|
350
- @inferred_type ||= type unless type.unreachable?
351
- end
352
- @inferred_type ||= primary_type
353
- else
354
- clause, clause_type = clauses.zip(clause_types).find{ |clause, t| !primary_type.compatible? t }
355
-
356
- raise Mirah::Typer::InferenceError.new("rescue statement with incompatible result types #{primary_type} and #{clause_type}", clause)
357
- end
358
- end
359
- end
360
- @inferred_type
361
- end
362
- end
363
-
364
- class Ensure < Node
365
- child :body
366
- child :clause
367
- attr_accessor :state # Used by some compilers.
368
-
369
- def initialize(parent, position, &block)
370
- super(parent, position, &block)
371
- end
372
-
373
- def infer(typer, expression)
374
- resolve_if(typer) do
375
- typer.infer(clause, false)
376
- typer.infer(body, false)
377
- end
378
- end
379
- end
380
- end
381
- end
@@ -1,563 +0,0 @@
1
- # Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
2
- # All contributing project authors may be found in the NOTICE file.
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- require 'fileutils'
17
-
18
- module Mirah::AST
19
-
20
- class Unquote < Node
21
- child :value
22
-
23
- def infer(typer, expression)
24
- raise Mirah::SyntaxError.new("Unquote used outside of macro", self)
25
- end
26
-
27
- def _dump(depth)
28
- vals = Unquote.__extracted
29
- index = vals.size
30
- vals << value
31
- Marshal.dump([position, index])
32
- end
33
-
34
-
35
- def self._load(str)
36
- if str =~ /^\d+$/
37
- # This just returns the exact node passed in.
38
- index = str.to_i
39
- Unquote.__injected[index].dup
40
- else
41
- position, index = Marshal.load(str)
42
- holder = UnquotedValue.new(nil, position)
43
- value = Unquote.__injected[index]
44
- begin
45
- holder << value.dup
46
- rescue TypeError
47
- holder << value
48
- end
49
- holder
50
- end
51
- end
52
-
53
- def self.__extracted
54
- Thread.current[:'Mirah::AST::Unquote.extracted']
55
- end
56
-
57
- def self.__extracted=(value)
58
- Thread.current[:'Mirah::AST::Unquote.extracted'] = value
59
- end
60
-
61
- def self.__injected
62
- Thread.current[:'Mirah::AST::Unquote.injected']
63
- end
64
-
65
- def self.__injected=(value)
66
- Thread.current[:'Mirah::AST::Unquote.injected'] = value
67
- end
68
-
69
- def self.extract_values
70
- values = []
71
- saved, self.__extracted = self.__extracted, values
72
- begin
73
- yield
74
- return values
75
- ensure
76
- self.__extracted = saved
77
- end
78
- end
79
-
80
- def self.inject_values(values)
81
- saved, self.__injected = self.__injected, values
82
- begin
83
- yield
84
- ensure
85
- self.__injected = saved
86
- end
87
- end
88
- end
89
-
90
- class UnquotedValue < Node
91
- java_import 'java.lang.Character'
92
- child :value
93
-
94
- def name
95
- case value
96
- when Mirah::AST::String
97
- value.literal
98
- when ::String
99
- value
100
- when Named
101
- value.name
102
- when Node
103
- value.string_value
104
- else
105
- raise "Bad unquote value for name #{value} (#{value.class})"
106
- end
107
- end
108
-
109
- def type
110
- Constant.new(nil, position, name)
111
- end
112
-
113
- def node
114
- case value
115
- when Node
116
- value
117
- when ::String
118
- c = value[0]
119
- if c == ?@
120
- return Field.new(nil, position, value[1, value.length])
121
- elsif Character.isUpperCase(c)
122
- return Constant.new(nil, position, value)
123
- else
124
- return Local.new(nil, position, value)
125
- end
126
- when ::Fixnum
127
- return Fixnum.new(nil, position, value)
128
- else
129
- raise "Bad unquote value for node #{value} (#{value.class})"
130
- end
131
- end
132
-
133
- def nodes
134
- case value
135
- when ::Array, Java::JavaUtil::List
136
- # TODO convert items to nodes.
137
- value.to_a
138
- else
139
- [node]
140
- end
141
- end
142
-
143
- def f_arg_item(value)
144
- case value
145
- when Arguments, Argument
146
- value
147
- when Node
148
- RequiredArgument.new(nil, position, value.string_value)
149
- when ::String
150
- RequiredArgument.new(nil, position, value)
151
- when ::Array, java.util.List
152
- name, type = value.map do |item|
153
- if item.kind_of?(Node)
154
- item.string_value
155
- else
156
- item.to_s
157
- end
158
- end
159
- RequiredArgument.new(nil, position, name, type)
160
- else
161
- raise "Bad unquote value for arg #{value} (#{value.class})"
162
- end
163
- end
164
-
165
- def f_arg
166
- case value
167
- when ::Array, java.util.List
168
- value.map {|item| f_arg_item(item)}
169
- else
170
- f_arg_item(value)
171
- end
172
- end
173
- end
174
-
175
- class UnquoteAssign < Node
176
- child :name
177
- child :value
178
-
179
- def infer(typer, expression)
180
- raise Mirah::SyntaxError.new("UnquoteAssign used outside of macro")
181
- end
182
-
183
- def _dump(depth)
184
- vals = Unquote.__extracted
185
- index = vals.size
186
- vals << self.name
187
- Marshal.dump([position, index, self.value])
188
- end
189
-
190
-
191
- def self._load(str)
192
- position, index, value = Marshal.load(str)
193
- holder = UnquotedValueAssign.new(nil, position)
194
- holder << Unquote.__injected[index].dup
195
- holder << value
196
- holder
197
- end
198
- end
199
-
200
- class UnquotedValueAssign < UnquotedValue
201
- child :name_node
202
- child :value
203
-
204
- def name
205
- raise "Bad unquote value #{value}"
206
- end
207
-
208
- def node
209
- if ScopedBody === self.name_node
210
- scope = name_node
211
- name_node = scope.children[0]
212
- else
213
- name_node = self.name_node
214
- end
215
-
216
- klass = LocalAssignment
217
- name = case name_node
218
- when Field
219
- # TODO support AttrAssign
220
- klass = FieldAssignment
221
- name_node.name
222
- when Named
223
- name_node.name
224
- when String
225
- name_node.literal
226
- else
227
- raise "Bad unquote value"
228
- end
229
-
230
- if name[0] == ?@
231
- name = name[1, name.length]
232
- klass = FieldAssignment
233
- end
234
-
235
- n = klass.new(nil, position, name)
236
- n << value
237
- n.validate_children
238
-
239
- if scope
240
- scope.children.clear
241
- scope << n
242
- else
243
- return n
244
- end
245
- end
246
-
247
- def f_arg
248
- raise "Bad unquote value"
249
- end
250
- end
251
-
252
- class MacroDefinition < Node
253
- include Named
254
- include Scoped
255
-
256
- child :arguments
257
- child :body
258
-
259
- attr_accessor :proxy
260
-
261
- def self.new(*args, &block)
262
- real_node = super
263
- real_node.proxy = NodeProxy.new(real_node)
264
- end
265
-
266
- def initialize(parent, line_number, name, &block)
267
- super(parent, line_number, &block)
268
- self.name = name
269
- end
270
-
271
- def infer(typer, expression)
272
- resolve_if(typer) do
273
- self_type = scope.static_scope.self_type
274
- extension_name = "%s$%s" % [self_type.name,
275
- typer.transformer.tmp("Extension%s")]
276
- klass = build_and_load_extension(self_type,
277
- extension_name,
278
- typer.transformer.state)
279
-
280
- # restore the self type since we're sharing a type factory
281
- typer.known_types['self'] = self_type
282
-
283
- arg_types = argument_types
284
- macro = self_type.add_compiled_macro(klass, name, arg_types)
285
- if arguments[-1].kind_of?(BlockArgument) && arguments[-1].optional?
286
- arg_types.pop
287
- self_type.add_method(name, arg_types, macro)
288
- end
289
- proxy.__inline__(Noop.new(parent, position))
290
- proxy.infer(typer, expression)
291
- end
292
- end
293
-
294
- def argument_types
295
- arguments.map do |arg|
296
- if arg.kind_of?(BlockArgument)
297
- TypeReference::BlockType
298
- else
299
- # TODO support typed args. Also there should be a way
300
- # to accept any AST node.
301
- Mirah::JVM::Types::Object
302
- end
303
- end
304
- end
305
-
306
- def signature
307
- args = argument_types
308
- if args.size > 0 && args[-1].block?
309
- args[-1] = BiteScript::ASM::Type.getObjectType('duby.lang.compiler.Block')
310
- end
311
- [nil] + args
312
- end
313
-
314
- def build_and_load_extension(parent, name, state)
315
- transformer = Mirah::Transform::Transformer.new(state)
316
- transformer.filename = name.gsub(".", "/")
317
- orig_factory = Mirah::AST.type_factory
318
- new_factory = orig_factory.dup
319
- Mirah::AST.type_factory = new_factory
320
- ast = build_ast(name, parent, transformer)
321
- classes = compile_ast(name, ast, transformer)
322
- loader = Mirah::Util::ClassLoader.new(
323
- JRuby.runtime.jruby_class_loader, classes)
324
- klass = loader.loadClass(name, true)
325
- if state.save_extensions
326
- annotate(parent, name)
327
- end
328
- Mirah::AST.type_factory = orig_factory
329
- klass
330
- end
331
-
332
- def annotate(type, class_name)
333
- node = type.unmeta.node
334
- if node
335
- extension = node.annotation('duby.anno.Extensions')
336
- extension ||= begin
337
- node.annotations << Annotation.new(
338
- nil, nil, BiteScript::ASM::Type.getObjectType('duby/anno/Extensions'))
339
- node.annotations[-1].runtime = false
340
- node.annotations[-1]
341
- end
342
- extension['macros'] ||= []
343
- macro = Annotation.new(nil, nil,
344
- BiteScript::ASM::Type.getObjectType('duby/anno/Macro'))
345
- macro['name'] = name
346
- macro['signature'] = BiteScript::Signature.signature(*signature)
347
- macro['class'] = class_name
348
- extension['macros'] << macro
349
- # TODO deal with optional blocks.
350
- else
351
- puts "Warning: No ClassDefinition for #{type.name}. Macros can't be loaded from disk."
352
- end
353
- end
354
-
355
- def compile_ast(name, ast, transformer)
356
- begin
357
- # FIXME: This is JVM specific, and should move out of platform-independent code
358
- typer = Mirah::JVM::Typer.new(transformer)
359
- typer.infer(ast, false)
360
- typer.resolve(true)
361
- typer.errors.each do |e|
362
- raise e
363
- end
364
- ensure
365
- puts ast.inspect if transformer.state.verbose
366
- end
367
- # FIXME: This is JVM specific, and should move out of platform-independent code
368
- compiler = Mirah::JVM::Compiler::JVMBytecode.new
369
- ast.compile(compiler, false)
370
- class_map = {}
371
- compiler.generate do |outfile, builder|
372
- bytes = builder.generate
373
- name = builder.class_name.gsub(/\//, '.')
374
- class_map[name] = Mirah::Util::ClassLoader.binary_string bytes
375
- if transformer.state.save_extensions
376
- outfile = "#{transformer.destination}#{outfile}"
377
- FileUtils.mkdir_p(File.dirname(outfile))
378
- File.open(outfile, 'wb') do |f|
379
- f.write(bytes)
380
- end
381
- end
382
- end
383
- class_map
384
- end
385
-
386
- def build_ast(name, parent, transformer)
387
- # TODO should use a new type factory too.
388
-
389
- ast = Mirah::AST.parse_ruby("begin;end")
390
- ast = transformer.transform(ast, nil)
391
-
392
- # Start building the extension class
393
- extension = transformer.define_class(position, name)
394
- #extension.superclass = Mirah::AST.type(nil, 'duby.lang.compiler.Macro')
395
- extension.implements(Mirah::AST.type(nil, 'duby.lang.compiler.Macro'))
396
-
397
- extension.static_scope.import('duby.lang.compiler.Node', 'Node')
398
- extension.static_scope.package = scope.static_scope.package
399
-
400
- # The constructor just saves the state
401
- extension.define_constructor(
402
- position,
403
- ['mirah', Mirah::AST.type(nil, 'duby.lang.compiler.Compiler')],
404
- ['call', Mirah::AST.type(nil, 'duby.lang.compiler.Call')]) do |c|
405
- transformer.eval("@mirah = mirah;@call = call", '-', c, 'mirah', 'call')
406
- end
407
-
408
- node_type = Mirah::AST.type(nil, 'duby.lang.compiler.Node')
409
-
410
- # expand() parses the arguments out of call and then passes them off to
411
- # _expand
412
- expand = extension.define_method(
413
- position, 'expand', node_type)
414
- pos = parent.position
415
- args = []
416
- expand_call = FunctionalCall.new(nil, pos, '_expand')
417
- self.arguments.each_with_index do |arg, i|
418
- # TODO optional args
419
- args << if arg.kind_of?(BlockArgument)
420
- Call.new(expand_call, pos, 'block') do |block_call|
421
- [Field.new(block_call, pos, 'call'), [], nil]
422
- end
423
- else
424
- cast = FunctionalCall.new(expand_call, pos, 'duby.lang.compiler.Node')
425
- cast.cast = true
426
- cast.parameters = [] << Call.new(cast, pos, 'get') do |getcall|
427
- [Local.new(getcall, pos, 'args'), [Fixnum.new(getcall, pos, i)], nil]
428
- end
429
- cast
430
- end
431
- end
432
- expand_call.parameters = args
433
- expand.body = transformer.eval(<<-end)
434
- args = @call.arguments
435
- nil
436
- end
437
- expand.body << expand_call
438
- actual_args = arguments.map do |arg|
439
- type = if arg.kind_of?(BlockArgument)
440
- Mirah::AST.type(nil, 'duby.lang.compiler.Block')
441
- else
442
- node_type
443
- end
444
- [arg.name, type, arg.position]
445
- end
446
- m = extension.define_method(position, '_expand', node_type, *actual_args)
447
- scope.static_scope.imports.each do |short, long|
448
- m.static_scope.import(long, short)
449
- end
450
- scope.static_scope.search_packages.each do |package|
451
- m.static_scope.import(package, '*')
452
- end
453
- m.body = self.body
454
- ast.body = extension
455
- ast
456
- end
457
- end
458
-
459
- defmacro('defmacro') do |duby, fcall, parent|
460
- macro = fcall.parameters[0]
461
- block_arg = nil
462
- args = macro.parameters if macro.respond_to?(:parameters)
463
- body = if macro.respond_to?(:block) && macro.block
464
- macro.block
465
- else
466
- fcall.block
467
- end
468
- body = body.body if body
469
-
470
- MacroDefinition.new(parent, fcall.position, macro.name) do |mdef|
471
- # TODO optional args?
472
- args = if args
473
- args.map do |arg|
474
- case arg
475
- when LocalAssignment
476
- OptionalArgument.new(mdef, arg.position, arg.name) do |optarg|
477
- # TODO check that they actually passed nil as the value
478
- Null.new(parent, arg.value_node.position)
479
- end
480
- when FunctionalCall
481
- RequiredArgument.new(mdef, arg.position, arg.name)
482
- when BlockPass
483
- farg = BlockArgument.new(mdef, arg.position, arg.value.name)
484
- farg.optional = true if LocalAssignment === arg.value
485
- farg
486
- else
487
- raise "Unsupported argument #{arg}"
488
- end
489
- end
490
- else
491
- []
492
- end
493
- body.parent = mdef if body
494
- [args, body]
495
- end
496
- end
497
-
498
- defmacro('macro') do |transformer, fcall, parent|
499
- # Alternate macro syntax.
500
- # macro def foo(...);...;end
501
- # This one supports special names like []=,
502
- # but you can't use optional blocks.
503
- method = fcall.parameters[0]
504
- macro = MacroDefinition.new(parent, fcall.position, method.name)
505
- macro.arguments = method.arguments.args || []
506
- macro.body = method.body
507
- macro
508
- end
509
-
510
- defmacro('abstract') do |transformer, fcall, parent|
511
- class_or_method = fcall.parameters[0]
512
- class_or_method.abstract = true
513
- class_or_method
514
- end
515
-
516
- defmacro('puts') do |transformer, fcall, parent|
517
- Call.new(parent, fcall.position, "println") do |x|
518
- args = fcall.parameters
519
- args.each do |arg|
520
- arg.parent = x
521
- end
522
- [
523
- Call.new(x, fcall.position, "out") do |y|
524
- [
525
- Constant.new(y, fcall.position, "System"),
526
- []
527
- ]
528
- end,
529
- args,
530
- nil
531
- ]
532
- end
533
- end
534
-
535
- defmacro('print') do |transformer, fcall, parent|
536
- Call.new(parent, fcall.position, "print") do |x|
537
- args = fcall.parameters
538
- args.each do |arg|
539
- arg.parent = x
540
- end
541
- [
542
- Call.new(x, fcall.position, "out") do |y|
543
- [
544
- Constant.new(y, fcall.position, "System"),
545
- []
546
- ]
547
- end,
548
- args,
549
- nil
550
- ]
551
- end
552
- end
553
-
554
- class InlineCode
555
- def initialize(&block)
556
- @block = block
557
- end
558
-
559
- def inline(transformer, call)
560
- @block.call(transformer, call)
561
- end
562
- end
563
- end