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,62 @@
1
+ module Mirah
2
+ module JVM
3
+ module Types
4
+ class ArrayType < Type
5
+ attr_reader :component_type
6
+
7
+ def initialize(component_type)
8
+ @component_type = component_type
9
+ if @component_type.jvm_type
10
+ #@type = java.lang.reflect.Array.newInstance(@component_type.jvm_type, 0).class
11
+ else
12
+ # FIXME: THIS IS WRONG, but I don't know how to fix it
13
+ #@type = @component_type
14
+ end
15
+ @name = component_type.name
16
+ end
17
+
18
+ def array?
19
+ true
20
+ end
21
+
22
+ def iterable?
23
+ true
24
+ end
25
+
26
+ def inner_class?
27
+ basic_type.inner_class?
28
+ end
29
+
30
+ def basic_type
31
+ component_type.basic_type
32
+ end
33
+
34
+ def superclass
35
+ if component_type.primitive?
36
+ Object
37
+ elsif component_type.array?
38
+ # fix covariance here for arrays of arrays
39
+ # see #55
40
+ Object
41
+ else
42
+ if component_type == Object
43
+ Object
44
+ else
45
+ component_type.superclass.array_type
46
+ end
47
+ end
48
+ end
49
+
50
+ def interfaces
51
+ []
52
+ end
53
+
54
+ def meta
55
+ @meta ||= ArrayMetaType.new(self)
56
+ end
57
+ end
58
+
59
+ class ArrayMetaType < MetaType; end
60
+ end
61
+ end
62
+ end
@@ -33,6 +33,7 @@ module Mirah::JVM::Types
33
33
  BiteScript::ASM::ClassMirror.load('java.lang.Iterable'))
34
34
 
35
35
  Void = VoidType.new
36
+ Unreachable = UnreachableType.new
36
37
  Null = NullType.new
37
38
 
38
39
  WIDENING_CONVERSIONS = {
@@ -0,0 +1,46 @@
1
+ module Mirah
2
+ module JVM
3
+ module Types
4
+ class DynamicType < Type
5
+ ObjectType = Type.new(BiteScript::ASM::ClassMirror.for_name('java.lang.Object'))
6
+
7
+ def initialize
8
+ # For naming, bytecode purposes, we are an Object
9
+ @name = "java.lang.Object"
10
+ end
11
+
12
+ def basic_type
13
+ self
14
+ end
15
+
16
+ def is_parent(other)
17
+ ObjectType.assignable_from?(other)
18
+ end
19
+
20
+ def assignable_from?(other)
21
+ ObjectType.assignable_from?(other)
22
+ end
23
+
24
+ def jvm_type
25
+ java.lang.Object
26
+ end
27
+
28
+ def full_name
29
+ "dynamic"
30
+ end
31
+
32
+ def dynamic?
33
+ true
34
+ end
35
+
36
+ def superclass
37
+ ObjectType.superclass
38
+ end
39
+
40
+ def interfaces
41
+ ObjectType.interfaces
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
 
16
16
  require 'jruby'
17
+ require 'mirah/jvm/types/source_mirror'
17
18
  module Mirah::JVM::Types
18
19
  class TypeFactory
19
20
  BASIC_TYPES = {
@@ -136,7 +137,7 @@ module Mirah::JVM::Types
136
137
  packages.each do |package|
137
138
  begin
138
139
  return get_type("#{package}.#{name}")
139
- rescue
140
+ rescue NameError
140
141
  end
141
142
  end
142
143
  raise NameError, "Cannot find class #{name}"
@@ -213,12 +214,29 @@ module Mirah::JVM::Types
213
214
  Void
214
215
  end
215
216
 
217
+ def unreachable_type
218
+ Unreachable
219
+ end
220
+
216
221
  def get_mirror(name)
217
222
  @mirrors[name] ||= begin
218
- classname = name.tr('.', '/') + ".class"
219
- stream = JRuby.runtime.jruby_class_loader.getResourceAsStream(classname)
220
- raise NameError, "Class '#{name}' not found." unless stream
221
- BiteScript::ASM::ClassMirror.load(stream)
223
+ classname = name.tr('.', '/')
224
+ stream = JRuby.runtime.jruby_class_loader.getResourceAsStream(classname + ".class")
225
+ if stream
226
+ BiteScript::ASM::ClassMirror.load(stream) if stream
227
+ else
228
+ url = JRuby.runtime.jruby_class_loader.getResource(classname + ".java")
229
+ if url
230
+ file = java.io.File.new(url.toURI)
231
+ mirrors = JavaSourceMirror.load(file, self)
232
+ mirrors.each do |mirror|
233
+ @mirrors[mirror.type.class_name] = mirror
234
+ end if mirrors
235
+ @mirrors[name]
236
+ else
237
+ raise NameError, "Class '#{name}' not found."
238
+ end
239
+ end
222
240
  end
223
241
  end
224
242
  end
@@ -0,0 +1,20 @@
1
+ module Mirah
2
+ module JVM
3
+ module Types
4
+ class InterfaceDefinition < TypeDefinition
5
+ def initialize(name, node)
6
+ super(name, node)
7
+ end
8
+
9
+ def define(builder)
10
+ class_name = @name.tr('.', '/')
11
+ @type ||= builder.public_interface(class_name, *interfaces)
12
+ end
13
+
14
+ def interface?
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -78,11 +78,15 @@ module Mirah::JVM::Types
78
78
  # However the only way to do that is to wrap them in a ScopedBody.
79
79
  # It'd be better if we didn't have to expose this wrapper node to
80
80
  # the user code.
81
+ #
82
+ if call.block && call.name != 'quote'
83
+ call.block.body = wrap_with_scoped_body call, call.block.body
84
+ end
85
+
81
86
  call.parameters = call.parameters.map do |arg|
82
- wrapper = Mirah::AST::ScopedBody.new(call.parent, call.position)
83
- wrapper.static_scope = call.scope.static_scope
84
- wrapper << arg
87
+ wrap_with_scoped_body call, arg
85
88
  end
89
+
86
90
  expander = klass.constructors[0].newInstance(duby, call)
87
91
  ast = expander.expand
88
92
  if ast
@@ -98,6 +102,12 @@ module Mirah::JVM::Types
98
102
  end
99
103
  end
100
104
  end
105
+
106
+ def wrap_with_scoped_body call, node
107
+ wrapper = Mirah::AST::ScopedBody.new(call.parent, call.position)
108
+ wrapper.static_scope = call.scope.static_scope
109
+ wrapper << node
110
+ end
101
111
 
102
112
  def declared_intrinsics(name=nil)
103
113
  methods = []
@@ -377,6 +387,8 @@ module Mirah::JVM::Types
377
387
  if var
378
388
  forloop.pre << transformer.eval(
379
389
  "#{var.name} = #{it}.next", '', forloop, it)
390
+ else
391
+ forloop.pre << transformer.eval("#{it}.next", '', forloop, it)
380
392
  end
381
393
  call.block.body.parent = forloop if call.block.body
382
394
  [
@@ -0,0 +1,45 @@
1
+ module Mirah
2
+ module JVM
3
+ module Types
4
+ class MetaType < Type
5
+ attr_reader :unmeta
6
+
7
+ def initialize(unmeta)
8
+ @name = unmeta.name
9
+ @unmeta = unmeta
10
+ end
11
+
12
+ def basic_type
13
+ @unmeta.basic_type
14
+ end
15
+
16
+ def meta?
17
+ true
18
+ end
19
+
20
+ def meta
21
+ self
22
+ end
23
+
24
+ def superclass
25
+ @unmeta.superclass.meta if @unmeta.superclass
26
+ end
27
+
28
+ def interfaces
29
+ []
30
+ end
31
+
32
+ def jvm_type
33
+ unmeta.jvm_type
34
+ end
35
+
36
+ def inner_class?
37
+ basic_type.inner_class?
38
+ end
39
+ end
40
+
41
+ class TypeDefMeta < MetaType
42
+ end
43
+ end
44
+ end
45
+ end
@@ -280,16 +280,21 @@ module Mirah::JVM::Types
280
280
  ast.parameters.each do |param|
281
281
  param.compile(compiler, true)
282
282
  end
283
+ handle = compiler.method.mh_invokestatic(
284
+ org.dynalang.dynalink.DefaultBootstrapper,
285
+ "bootstrap",
286
+ java.lang.invoke.CallSite,
287
+ java.lang.invoke.MethodHandles::Lookup,
288
+ java.lang.String,
289
+ java.lang.invoke.MethodType)
283
290
  compiler.method.invokedynamic(
284
- target,
285
291
  "dyn:callPropWithThis:#{name}",
286
- [return_type, target, *@types])
292
+ [return_type, target, *@types],
293
+ handle)
287
294
 
288
295
  unless expression
289
296
  return_type.pop(compiler.method)
290
297
  end
291
-
292
- compiler.bootstrap_dynamic
293
298
  end
294
299
  end
295
300
 
@@ -568,7 +573,9 @@ module Mirah::JVM::Types
568
573
  member = MirahMember.new(self, name, arguments, type, false, exceptions)
569
574
  if name == 'initialize'
570
575
  if @default_constructor_added
571
- unless arguments.empty?
576
+ if arguments.empty?
577
+ @default_constructor_added = false
578
+ else
572
579
  raise "Can't add constructor #{member} after using the default."
573
580
  end
574
581
  else
@@ -0,0 +1,27 @@
1
+ module Mirah
2
+ module JVM
3
+ module Types
4
+ class NullType < Type
5
+ def initialize
6
+ super(BiteScript::ASM::ClassMirror.load('java.lang.Object'))
7
+ end
8
+
9
+ def to_s
10
+ "Type(null)"
11
+ end
12
+
13
+ def null?
14
+ true
15
+ end
16
+
17
+ def compatible?(other)
18
+ !other.primitive?
19
+ end
20
+
21
+ def assignable_from?(other)
22
+ !other.primitive?
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ module Mirah
2
+ module JVM
3
+ module Types
4
+ class PrimitiveType < Type
5
+ def initialize(type, wrapper)
6
+ @wrapper = wrapper
7
+ super(type)
8
+ end
9
+
10
+ def primitive?
11
+ true
12
+ end
13
+
14
+ def primitive_type
15
+ @wrapper::TYPE
16
+ end
17
+
18
+ def newarray(method)
19
+ method.send "new#{name}array"
20
+ end
21
+
22
+ def interfaces
23
+ []
24
+ end
25
+
26
+ def convertible_to?(type)
27
+ return true if type == self
28
+ widening_conversions = WIDENING_CONVERSIONS[self]
29
+ widening_conversions && widening_conversions.include?(type)
30
+ end
31
+
32
+ def superclass
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,266 @@
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 'jruby'
17
+ require 'set'
18
+ require 'bitescript'
19
+ module Mirah::JVM::Types
20
+ class JavaSourceMirror
21
+ begin
22
+ java_import 'javax.tools.ToolProvider'
23
+ java_import 'java.util.Arrays'
24
+ java_import 'javax.tools.SimpleJavaFileObject'
25
+ java_import 'javax.tools.JavaFileObject'
26
+ java_import 'java.net.URI'
27
+ java_import 'javax.lang.model.element.Element'
28
+ java_import 'javax.lang.model.type.TypeKind'
29
+ java_import 'javax.lang.model.type.TypeMirror'
30
+ java_import 'com.sun.tools.javac.model.JavacElements'
31
+ java_import 'javax.lang.model.util.ElementScanner6'
32
+ java_import 'javax.lang.model.element.AnnotationValueVisitor'
33
+ rescue
34
+ end
35
+
36
+ if defined?(JavacElements)
37
+ class FakeJavaFile < SimpleJavaFileObject
38
+ def initialize(package, name, kind='class')
39
+ package ||= ''
40
+ super(URI.create(FakeJavaFile.build_uri(package, name)), JavaFileObject::Kind::SOURCE)
41
+ @code = ''
42
+ if package != ""
43
+ @code << "package #{package};\n"
44
+ end
45
+ @code << "@org.mirah.infer.FakeClass\n"
46
+ @code << "public #{kind} #{name} { }"
47
+ end
48
+
49
+ def self.build_uri(package, name)
50
+ name = name.tr('.', '$')
51
+ package = package.tr('.', '/')
52
+ package << '/' unless "" == package
53
+ "string:///#{package}#{name}#{JavaFileObject::Kind::SOURCE.extension}"
54
+ end
55
+
56
+ def getCharContent(ignoreEncodingErrors)
57
+ java.lang.String.new(@code)
58
+ end
59
+ end
60
+
61
+ class JavaSourceParser < ElementScanner6
62
+ include AnnotationValueVisitor
63
+
64
+ # TODO support generics
65
+ def initialize(file, type_factory)
66
+ super()
67
+ @file = file
68
+ @type_factory = type_factory
69
+ @mirrors = []
70
+ end
71
+
72
+ def parse
73
+ tools = ToolProvider.system_java_compiler
74
+ units = [get_java_file(tools)] + get_fake_files
75
+ @javac = tools.get_task(nil, nil, nil, classpath, nil, units)
76
+ @element_utils = JavacElements.instance(@javac.context)
77
+ elements = @javac.enter
78
+ elements.each {|elem| scan(elem)}
79
+ @mirrors
80
+ end
81
+
82
+ def classpath
83
+ [
84
+ '-classpath',
85
+ $CLASSPATH.to_a.join(java.io.File.pathSeparator)
86
+ ]
87
+ end
88
+
89
+ def get_java_file(tools)
90
+ fm = tools.get_standard_file_manager(nil, nil, nil)
91
+ fm.get_java_file_objects(@file).to_a[0]
92
+ end
93
+
94
+ def get_fake_files
95
+ mirah_typedefs = Set.new(@type_factory.known_types.values.reject {|t| !t.kind_of?(TypeDefinition)})
96
+ files = [FakeJavaFile.new('org.mirah.infer', 'FakeClass', '@interface')]
97
+ mirah_typedefs.each do |typedef|
98
+ typedef.name =~ /^(?:(.+)\.)?([^.]+)$/
99
+ package, name = $1, $2
100
+ kind = if typedef.interface?
101
+ 'interface'
102
+ else
103
+ 'class'
104
+ end
105
+ files << FakeJavaFile.new(package, name, kind)
106
+ end
107
+ files
108
+ end
109
+
110
+ def visitType(elem, arg)
111
+ return anno_visitType(elem, arg) if elem.kind_of?(TypeMirror)
112
+ if elem.annotation_mirrors.any? {|a| a.toString == '@org.mirah.infer.FakeClass'}
113
+ return
114
+ end
115
+ superclass = internal_type_name(elem.superclass) || 'java/lang/Object'
116
+ interfaces = elem.interfaces.map {|i| internal_type_name(i)}
117
+ flags = flags_from_modifiers(elem)
118
+ builder = BiteScript::ASM::ClassMirror::Builder.new
119
+ builder.visit(0, flags, internal_name(elem), nil, superclass, interfaces)
120
+ with(builder) do
121
+ elem.annotation_mirrors.each {|anno| visitAnnotation(anno)}
122
+ super(elem, arg)
123
+ end
124
+ @mirrors << builder.mirror
125
+ builder.mirror
126
+ end
127
+
128
+ def visitVariable(field, arg)
129
+ flags = flags_from_modifiers(field)
130
+ type = type_desc(field.as_type)
131
+ fbuilder = @current.visitField(
132
+ flags, field.simple_name, type, nil, field.constant_value)
133
+ with fbuilder do
134
+ field.annotation_mirrors.each {|anno| visitAnnotation(anno)}
135
+ end
136
+ end
137
+
138
+ def visitExecutable(method, arg)
139
+ # TODO varags
140
+ flags = flags_from_modifiers(method)
141
+ exceptions = method.thrown_types.map {|t| internal_type_name(t)}
142
+ desc = type_desc(method.as_type)
143
+ mbuilder = @current.visitMethod(flags, method.simple_name, desc, nil, exceptions)
144
+ with mbuilder do
145
+ method.annotation_mirrors.each {|anno| visitAnnotation(anno)}
146
+ end
147
+ end
148
+
149
+ def visitAnnotation(elem, arg=nil)
150
+ desc = type_desc(elem.annotation_type)
151
+ if arg.nil?
152
+ anno = @current.visitAnnotation(desc, 0)
153
+ else
154
+ builder, name = arg
155
+ anno = builder.visitAnnotation(name, desc)
156
+ end
157
+ elem.element_values.each do |method, value|
158
+ name = method.simple_name
159
+ visit(value, [anno, name])
160
+ end
161
+ end
162
+
163
+ # AnnotationValueVisitor
164
+ def visitArray(values, arg)
165
+ anno, name = arg
166
+ array = anno.visitArray(name)
167
+ values.each do |value|
168
+ visit(value, [array, name])
169
+ end
170
+ end
171
+
172
+ def visitBoolean(val, arg)
173
+ anno, name = arg
174
+ anno.visit(name, val)
175
+ end
176
+ alias visitByte visitBoolean
177
+ alias visitChar visitBoolean
178
+ alias visitDouble visitBoolean
179
+ alias visitFloat visitBoolean
180
+ alias visitInt visitBoolean
181
+ alias visitLong visitBoolean
182
+ alias visitShort visitBoolean
183
+ alias visitString visitBoolean
184
+ alias visitUnknown visitBoolean
185
+
186
+ def visitEnumConstant(c, arg)
187
+ anno, name = arg
188
+ anno.visitEnum(name, type_desc(c.as_type), c.simple_name)
189
+ end
190
+
191
+ def anno_visitType(t, arg)
192
+ anno, name = arg
193
+ anno.visit(name, BiteScript::ASM::Type.getType(type_desc(t)))
194
+ end
195
+
196
+ def with(elem)
197
+ saved, @current = @current, elem
198
+ begin
199
+ yield
200
+ ensure
201
+ @current = saved
202
+ end
203
+ end
204
+
205
+ def flags_from_modifiers(elem)
206
+ flags = 0
207
+ elem.modifiers.each do |modifier|
208
+ flags |= BiteScript::ASM::Opcodes.const_get("ACC_#{modifier.name}")
209
+ end
210
+ flags
211
+ end
212
+
213
+ def internal_name(element)
214
+ @element_utils.get_binary_name(element).to_s.tr('.', '/')
215
+ end
216
+
217
+ def internal_type_name(type)
218
+ return nil if type.kind == TypeKind::NONE
219
+ return @element_utils.get_binary_name(type.as_element).to_s.tr('.', '/')
220
+ end
221
+
222
+ def type_desc(type)
223
+ case type.kind.name
224
+ when 'ARRAY'
225
+ "[#{type_desc(type.component_type)}"
226
+ when 'BOOLEAN'
227
+ 'Z'
228
+ when 'BYTE'
229
+ 'B'
230
+ when 'CHAR'
231
+ 'C'
232
+ when 'DECLARED'
233
+ name = internal_type_name(type)
234
+ "L#{name};"
235
+ when 'DOUBLE'
236
+ 'D'
237
+ when 'FLOAT'
238
+ 'F'
239
+ when 'INT'
240
+ 'I'
241
+ when 'LONG'
242
+ 'J'
243
+ when 'SHORT'
244
+ 'S'
245
+ when 'VOID'
246
+ 'V'
247
+ when 'EXECUTABLE'
248
+ desc = '('
249
+ type.parameter_types.each do |param|
250
+ desc << type_desc(param)
251
+ end
252
+ desc << ')'
253
+ desc << type_desc(type.return_type)
254
+ else
255
+ raise ArgumentError, "Unsupported type #{type.kind.name}"
256
+ end
257
+ end
258
+ end
259
+ end
260
+
261
+ def self.load(file, factory)
262
+ parser = JavaSourceParser.new(file, factory)
263
+ parser.parse
264
+ end
265
+ end
266
+ end