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,65 @@
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 Body
19
+ def compile(compiler, expression)
20
+ compiler.line(line_number)
21
+ compiler.body(self, expression)
22
+ rescue Exception => ex
23
+ raise Mirah::InternalCompilerError.wrap(ex, self)
24
+ end
25
+ end
26
+
27
+ class ScopedBody
28
+ def compile(compiler, expression)
29
+ compiler.line(line_number)
30
+ compiler.scoped_body(self, expression)
31
+ rescue Exception => ex
32
+ raise Mirah::InternalCompilerError.wrap(ex, self)
33
+ end
34
+ end
35
+
36
+ class BindingReference
37
+ def compile(compiler, expression)
38
+ if expression
39
+ compiler.line(line_number)
40
+ compiler.binding_reference
41
+ end
42
+ rescue Exception => ex
43
+ raise Mirah::InternalCompilerError.wrap(ex, self)
44
+ end
45
+ end
46
+
47
+ class Script
48
+ def compile(compiler, expression)
49
+ # TODO: what does it mean for a script to be an expression? possible?
50
+ compiler.define_main(self)
51
+ rescue Exception => ex
52
+ raise Mirah::InternalCompilerError.wrap(ex, self)
53
+ end
54
+ end
55
+
56
+ class Noop
57
+ def compile(compiler, expression)
58
+ # TODO: what does it mean for a noop to be an expression
59
+ # nothing
60
+ rescue Exception => ex
61
+ raise Mirah::InternalCompilerError.wrap(ex, self)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,27 @@
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 Import
19
+ def compile(compiler, expression)
20
+ # TODO: what does it mean for import to be an expression?
21
+ compiler.import(short, long)
22
+ rescue Exception => ex
23
+ raise Mirah::InternalCompilerError.wrap(ex, self)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -21,16 +21,14 @@ module Mirah
21
21
  # Returns the system PATH_SEPARATOR environment variable value. This is used when
22
22
  # separating multiple paths in one string. If none is defined then a : (colon)
23
23
  # is returned
24
- def self.path_seperator
25
- ps = RbConfig::CONFIG['PATH_SEPARATOR']
26
- ps = ':' if ps.nil? || ps == ''
27
- ps
24
+ def self.path_separator
25
+ File::PATH_SEPARATOR
28
26
  end
29
27
 
30
28
  # Takes an array of strings and joins them using the path_separator returning
31
29
  # a single string value
32
30
  def self.encode_paths(paths)
33
- paths.join(path_seperator)
31
+ paths.join(path_separator)
34
32
  end
35
33
 
36
34
  # Takes a single string value "paths" and returns an array of strings containing the
@@ -39,7 +37,7 @@ module Mirah
39
37
  # is supplied it is returned as the result
40
38
  def self.decode_paths(paths, dest = nil)
41
39
  result = dest ? dest : []
42
- paths.split(path_seperator).each do |path|
40
+ paths.split(path_separator).each do |path|
43
41
  result << path
44
42
  end
45
43
  result
@@ -0,0 +1,61 @@
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
+ require 'mirah/util/process_errors'
16
+
17
+ module Mirah
18
+ class Generator
19
+ include Mirah::Util::ProcessErrors
20
+ def initialize(state, compiler_class, logging, verbose)
21
+ @parser = Mirah::Parser.new(state, logging)
22
+ @compiler = Mirah::Compiler::ASTCompiler.new(compiler_class, logging)
23
+ @logging = logging
24
+ @verbose = verbose
25
+ end
26
+
27
+ attr_accessor :parser, :compiler, :logging, :verbose
28
+
29
+ def generate(arguments)
30
+ # collect all ASTs from all files
31
+ top_nodes = parser.parse_from_args(arguments)
32
+
33
+ # enter all ASTs into inference engine
34
+ puts "Inferring types..." if logging
35
+ infer_asts(top_nodes)
36
+
37
+ # compile each AST in turn
38
+ compiler_results = compiler.compile_asts(top_nodes)
39
+
40
+ puts "Done!" if logging
41
+
42
+ compiler_results
43
+ end
44
+
45
+ def infer_asts(nodes)
46
+ typer = Mirah::JVM::Typer.new(parser.transformer)
47
+ nodes.each {|ast| typer.infer(ast, true) }
48
+ begin
49
+ typer.resolve(false)
50
+ ensure
51
+ puts nodes.inspect if verbose
52
+
53
+ failed = !typer.errors.empty?
54
+ if failed
55
+ puts "Inference Error:"
56
+ process_errors(typer.errors)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -14,897 +14,38 @@
14
14
  # limitations under the License.
15
15
 
16
16
  require 'mirah'
17
- require 'mirah/jvm/base'
17
+ require 'mirah/jvm/compiler/base'
18
18
  require 'mirah/jvm/method_lookup'
19
19
  require 'mirah/jvm/types'
20
20
  require 'mirah/typer'
21
21
  require 'mirah/plugin/java'
22
22
  require 'bitescript'
23
+ require 'mirah/jvm/compiler/jvm_bytecode'
23
24
 
24
25
  module Mirah
25
26
  module AST
26
27
  class FunctionalCall
27
28
  attr_accessor :target
28
29
  end
29
-
30
+
30
31
  class Super
31
32
  attr_accessor :target
32
33
  end
33
34
  end
34
-
35
- module Compiler
36
- class JVM < JVMCompilerBase
37
- java_import java.lang.System
38
- java_import java.io.PrintStream
39
- include Mirah::JVM::MethodLookup
40
- Types = Mirah::JVM::Types
41
-
42
- class << self
43
- attr_accessor :verbose
44
-
45
- def log(message)
46
- puts "* [#{name}] #{message}" if JVM.verbose
47
- end
48
-
49
- def classname_from_filename(filename)
50
- basename = File.basename(filename).sub(/\.(duby|mirah)$/, '')
51
- basename.split(/_/).map{|x| x[0...1].upcase + x[1..-1]}.join
52
- end
53
- end
54
-
55
- module JVMLogger
56
- def log(message); JVM.log(message); end
57
- end
58
-
59
- class ImplicitSelf
60
- attr_reader :inferred_type
61
-
62
- def initialize(type)
63
- @inferred_type = type
64
- end
65
-
66
- def compile(compiler, expression)
67
- compiler.compile_self if expression
68
- end
69
- end
70
-
71
- def initialize
72
- super
73
- @jump_scope = []
74
- end
75
-
76
- def file_builder(filename)
77
- builder = BiteScript::FileBuilder.new(filename)
78
- AST.type_factory.define_types(builder)
79
- builder
80
- end
81
-
82
- def output_type
83
- "classes"
84
- end
85
-
86
- def push_jump_scope(node)
87
- raise "Not a node" unless Mirah::AST::Node === node
88
- begin
89
- @jump_scope << node
90
- yield
91
- ensure
92
- @jump_scope.pop
93
- end
94
- end
95
-
96
- def find_ensures(before)
97
- found = []
98
- @jump_scope.reverse_each do |scope|
99
- if Mirah::AST::Ensure === scope
100
- found << scope
101
- end
102
- break if before === scope
103
- end
104
- found
105
- end
106
-
107
- def begin_main
108
- # declare argv variable
109
- @method.local('argv', AST.type(nil, 'string', true))
110
- end
111
-
112
- def finish_main
113
- @method.returnvoid
114
- end
115
-
116
- def prepare_binding(scope)
117
- if scope.has_binding?
118
- type = scope.binding_type
119
- @binding = @bindings[type]
120
- @method.new type
121
- @method.dup
122
- @method.invokespecial type, "<init>", [@method.void]
123
- if scope.respond_to? :arguments
124
- scope.arguments.args.each do |param|
125
- name = param.name
126
- param_type = param.inferred_type
127
- if scope.static_scope.captured?(param.name)
128
- @method.dup
129
- type.load(@method, @method.local(name, param_type))
130
- @method.putfield(type, name, param_type)
131
- end
132
- end
133
- end
134
- type.store(@method, @method.local('$binding', type))
135
- end
136
- begin
137
- yield
138
- ensure
139
- if scope.has_binding?
140
- @binding.stop
141
- @binding = nil
142
- end
143
- end
144
- end
145
-
146
- def define_method(node)
147
- push_jump_scope(node) do
148
- base_define_method(node, true) do |method, arg_types|
149
- return if @class.interface?
150
-
151
- log "Starting new #{node.static? ? 'static ' : ''}method #{node.name}(#{arg_types})"
152
- args = node.arguments.args
153
- method_body(method, args, node, node.signature[:return])
154
- log "Method #{node.name}(#{arg_types}) complete!"
155
- end
156
- end
157
- end
158
-
159
- def define_optarg_chain(name, arg, return_type,
160
- args_for_opt, arg_types_for_opt)
161
- # declare all args so they get their values
162
- @method.aload(0) unless @static
163
- args_for_opt.each do |req_arg|
164
- req_arg.inferred_type.load(@method, @method.local(req_arg.name, req_arg.inferred_type))
165
- end
166
- arg.value.compile(self, true)
167
-
168
- # invoke the next one in the chain
169
- if @static
170
- @method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
171
- else
172
- @method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
173
- end
174
-
175
- return_type.return(@method)
176
- end
177
-
178
- def constructor(node)
179
- push_jump_scope(node) do
180
- super(node, true) do |method, args|
181
- method_body(method, args, node, Types::Void) do
182
- method.aload 0
183
- if node.delegate_args
184
- if node.calls_super
185
- delegate_class = @type.superclass
186
- else
187
- delegate_class = @type
188
- end
189
- delegate_types = node.delegate_args.map do |arg|
190
- arg.inferred_type
191
- end
192
- constructor = delegate_class.constructor(*delegate_types)
193
- node.delegate_args.each do |arg|
194
- arg.compile(self, true)
195
- end
196
- method.invokespecial(
197
- delegate_class, "<init>",
198
- [@method.void, *constructor.argument_types])
199
- else
200
- method.invokespecial @class.superclass, "<init>", [@method.void]
201
- end
202
- end
203
- end
204
- end
205
- end
206
-
207
- def method_body(method, args, node, return_type)
208
- body = node.body
209
- with(:method => method,
210
- :declared_locals => {}) do
211
-
212
- method.start
213
-
214
- scope = node.static_scope
215
-
216
- # declare all args so they get their values
217
- if args
218
- args.each {|arg| declare_local(scope, arg.name, arg.inferred_type)}
219
- end
220
- declare_locals(scope)
221
-
222
- yield if block_given?
223
-
224
- prepare_binding(node) do
225
- expression = return_type != Types::Void
226
- body.compile(self, expression) if body
227
- end
228
-
229
- return_type.return(@method)
230
-
231
- @method.stop
232
- end
233
- end
234
-
235
- def define_closure(class_def, expression)
236
- compiler = ClosureCompiler.new(@file, @type, self)
237
- compiler.define_class(class_def, expression)
238
- end
239
-
240
- def branch(iff, expression)
241
- elselabel = @method.label
242
- donelabel = @method.label
243
-
244
- # this is ugly...need a better way to abstract the idea of compiling a
245
- # conditional branch while still fitting into JVM opcodes
246
- predicate = iff.condition.predicate
247
- if iff.body || expression
248
- jump_if_not(predicate, elselabel)
249
-
250
- if iff.body
251
- iff.body.compile(self, expression)
252
- elsif expression
253
- iff.inferred_type.init_value(@method)
254
- end
255
-
256
- @method.goto(donelabel)
257
- else
258
- jump_if(predicate, donelabel)
259
- end
260
-
261
- elselabel.set!
262
-
263
- if iff.else
264
- iff.else.compile(self, expression)
265
- elsif expression
266
- iff.inferred_type.init_value(@method)
267
- end
268
-
269
- donelabel.set!
270
- end
271
-
272
- def loop(loop, expression)
273
- push_jump_scope(loop) do
274
- with(:break_label => @method.label,
275
- :redo_label => @method.label,
276
- :next_label => @method.label) do
277
- predicate = loop.condition.predicate
278
-
279
- loop.init.compile(self, false) if loop.init?
280
-
281
- pre_label = @redo_label
282
-
283
- if loop.check_first
284
- @next_label.set! unless loop.post?
285
- if loop.negative
286
- # if condition, exit
287
- jump_if(predicate, @break_label)
288
- else
289
- # if not condition, exit
290
- jump_if_not(predicate, @break_label)
291
- end
292
- end
293
-
294
- if loop.pre?
295
- pre_label = method.label
296
- pre_label.set!
297
- loop.pre.compile(self, false)
298
- end
299
-
300
-
301
- @redo_label.set!
302
- loop.body.compile(self, false) if loop.body
303
-
304
- if loop.check_first && !loop.post?
305
- @method.goto(@next_label)
306
- else
307
- @next_label.set!
308
- loop.post.compile(self, false) if loop.post?
309
- if loop.negative
310
- # if not condition, continue
311
- jump_if_not(predicate, pre_label)
312
- else
313
- # if condition, continue
314
- jump_if(predicate, pre_label)
315
- end
316
- end
317
-
318
- @break_label.set!
319
-
320
- # loops always evaluate to null
321
- @method.aconst_null if expression
322
- end
323
- end
324
- end
325
-
326
- def break(node)
327
- error("break outside of loop", node) unless @break_label
328
- handle_ensures(find_ensures(Mirah::AST::Loop))
329
- @method.goto(@break_label)
330
- end
331
-
332
- def next(node)
333
- error("next outside of loop", node) unless @next_label
334
- handle_ensures(find_ensures(Mirah::AST::Loop))
335
- @method.goto(@next_label)
336
- end
337
-
338
- def redo(node)
339
- error("redo outside of loop", node) unless @redo_label
340
- handle_ensures(find_ensures(Mirah::AST::Loop))
341
- @method.goto(@redo_label)
342
- end
343
-
344
- def jump_if(predicate, target)
345
- unless predicate.inferred_type == Types::Boolean
346
- raise "Expected boolean, found #{predicate.inferred_type}"
347
- end
348
- if Mirah::AST::Call === predicate
349
- method = extract_method(predicate)
350
- if method.respond_to? :jump_if
351
- method.jump_if(self, predicate, target)
352
- return
353
- end
354
- end
355
- predicate.compile(self, true)
356
- @method.ifne(target)
357
- end
358
-
359
- def jump_if_not(predicate, target)
360
- unless predicate.inferred_type == Types::Boolean
361
- raise "Expected boolean, found #{predicate.inferred_type}"
362
- end
363
- if Mirah::AST::Call === predicate
364
- method = extract_method(predicate)
365
- if method.respond_to? :jump_if_not
366
- method.jump_if_not(self, predicate, target)
367
- return
368
- end
369
- end
370
- predicate.compile(self, true)
371
- @method.ifeq(target)
372
- end
373
-
374
- def extract_method(call)
375
- target = call.target.inferred_type!
376
- params = call.parameters.map do |param|
377
- param.inferred_type!
378
- end
379
- target.get_method(call.name, params)
380
- end
381
-
382
- def call(call, expression)
383
- return cast(call, expression) if call.cast?
384
- method = extract_method(call)
385
- if method
386
- method.call(self, call, expression)
387
- else
388
- raise "Missing method #{target}.#{call.name}(#{params.join ', '})"
389
- end
390
- end
391
-
392
- def self_call(fcall, expression)
393
- return cast(fcall, expression) if fcall.cast?
394
- type = fcall.scope.static_scope.self_type
395
- type = type.meta if (@static && type == @type)
396
- fcall.target = ImplicitSelf.new(type)
397
-
398
- params = fcall.parameters.map do |param|
399
- param.inferred_type
400
- end
401
- method = type.get_method(fcall.name, params)
402
- unless method
403
- target = static ? @class.name : 'self'
404
-
405
- raise NameError, "No method %s.%s(%s)" %
406
- [target, fcall.name, params.join(', ')]
407
- end
408
- method.call(self, fcall, expression)
409
- end
410
-
411
- def super_call(sup, expression)
412
- type = @type.superclass
413
- sup.target = ImplicitSelf.new(type)
414
-
415
- params = sup.parameters.map do |param|
416
- param.inferred_type
417
- end
418
- method = type.get_method(sup.name, params)
419
- unless method
420
-
421
- raise NameError, "No method %s.%s(%s)" %
422
- [type, sup.name, params.join(', ')]
423
- end
424
- method.call_special(self, sup, expression)
425
- end
426
-
427
- def cast(fcall, expression)
428
- # casting operation, not a call
429
- castee = fcall.parameters[0]
430
-
431
- # TODO move errors to inference phase
432
- source_type_name = castee.inferred_type.name
433
- target_type_name = fcall.inferred_type.name
434
- if castee.inferred_type.primitive?
435
- if fcall.inferred_type.primitive?
436
- if source_type_name == 'boolean' && target_type_name != "boolean"
437
- raise TypeError.new "not a boolean type: #{castee.inferred_type}"
438
- end
439
- # ok
440
- primitive = true
441
- else
442
- raise TypeError.new "Cannot cast #{castee.inferred_type} to #{fcall.inferred_type}: not a reference type."
443
- end
444
- elsif fcall.inferred_type.primitive?
445
- raise TypeError.new "not a primitive type: #{castee.inferred_type}"
446
- else
447
- # ok
448
- primitive = false
449
- end
450
-
451
- castee.compile(self, expression)
452
- if expression
453
- if primitive
454
- source_type_name = 'int' if %w[byte short char].include? source_type_name
455
- if (source_type_name != 'int') && (%w[byte short char].include? target_type_name)
456
- target_type_name = 'int'
457
- end
458
-
459
- if source_type_name != target_type_name
460
- if RUBY_VERSION == "1.9"
461
- @method.send "#{source_type_name[0]}2#{target_type_name[0]}"
462
- else
463
- @method.send "#{source_type_name[0].chr}2#{target_type_name[0].chr}"
464
- end
465
- end
466
- else
467
- if (source_type_name != target_type_name ||
468
- castee.inferred_type.array? != fcall.inferred_type.array?)
469
- @method.checkcast fcall.inferred_type
470
- end
471
- end
472
- end
473
- end
474
-
475
- def body(body, expression)
476
- # last element is an expression only if the body is an expression
477
- super(body, expression) do |last|
478
- compile(last, expression)
479
- end
480
- end
481
-
482
- def local(scope, name, type)
483
- type.load(@method, @method.local(scoped_local_name(name, scope), type))
484
- end
485
-
486
- def local_assign(scope, name, type, expression, value)
487
- declare_local(scope, name, type)
488
-
489
- value.compile(self, true)
490
-
491
- # if expression, dup the value we're assigning
492
- @method.dup if expression
493
-
494
- type.store(@method, @method.local(scoped_local_name(name, scope), type))
495
- end
496
-
497
- def declared_locals
498
- @declared_locals ||= {}
499
- end
500
-
501
- def annotate(builder, annotations)
502
- annotations.each do |annotation|
503
- type = annotation.type
504
- type = type.jvm_type if type.respond_to?(:jvm_type)
505
- builder.annotate(type, annotation.runtime?) do |visitor|
506
- annotation.values.each do |name, value|
507
- annotation_value(visitor, name, value)
508
- end
509
- end
510
- end
511
- end
512
-
513
- def annotation_value(builder, name, value)
514
- case value
515
- when Mirah::AST::Annotation
516
- type = value.type
517
- type = type.jvm_type if type.respond_to?(:jvm_type)
518
- builder.annotation(name, type) do |child|
519
- value.values.each do |name, value|
520
- annotation_value(child, name, value)
521
- end
522
- end
523
- when ::Array
524
- builder.array(name) do |array|
525
- value.each do |item|
526
- annotation_value(array, nil, item)
527
- end
528
- end
529
- else
530
- builder.value(name, value)
531
- end
532
- end
533
-
534
- def declared?(scope, name)
535
- declared_locals.include?(scoped_local_name(name, scope))
536
- end
537
-
538
- def declare_local(scope, name, type)
539
- # TODO confirm types are compatible
540
- name = scoped_local_name(name, scope)
541
- unless declared_locals[name]
542
- declared_locals[name] = type
543
- index = @method.local(name, type)
544
- end
545
- end
546
-
547
- def local_declare(scope, name, type)
548
- end
549
-
550
- def declare_locals(scope)
551
- scope.locals.each do |name|
552
- unless scope.captured?(name) || declared?(scope, name)
553
- type = scope.local_type(name)
554
- declare_local(scope, name, type)
555
- type.init_value(@method)
556
- type.store(@method, @method.local(scoped_local_name(name, scope), type))
557
- end
558
- end
559
- end
560
-
561
- def get_binding(type)
562
- @bindings[type]
563
- end
564
-
565
- def declared_captures(binding=nil)
566
- @captured_locals[binding || @binding]
567
- end
568
-
569
- def captured_local_declare(scope, name, type)
570
- unless declared_captures[name]
571
- declared_captures[name] = type
572
- # default should be fine, but I don't think bitescript supports it.
573
- @binding.protected_field(name, type)
574
- end
575
- end
576
-
577
- def captured_local(scope, name, type)
578
- captured_local_declare(scope, name, type)
579
- binding_reference
580
- @method.getfield(scope.binding_type, name, type)
581
- end
582
-
583
- def captured_local_assign(node, expression)
584
- scope, name, type = node.containing_scope, node.name, node.inferred_type
585
- captured_local_declare(scope, name, type)
586
- binding_reference
587
- node.value.compile(self, true)
588
- @method.dup_x2 if expression
589
- @method.putfield(scope.binding_type, name, type)
590
- end
591
-
592
- def field(name, type, annotations, static_field)
593
- name = name[1..-1] if name =~ /^@/
594
-
595
- real_type = declared_fields[name] || type
596
-
597
- declare_field(name, real_type, annotations, static_field)
598
-
599
- # load self object unless static
600
- method.aload 0 unless static || static_field
601
-
602
- if static || static_field
603
- @method.getstatic(@class, name, type)
604
- else
605
- @method.getfield(@class, name, type)
606
- end
607
- end
608
-
609
- def declared_fields
610
- @declared_fields ||= {}
611
- @declared_fields[@class] ||= {}
612
- end
613
-
614
- def declare_field(name, type, annotations, static_field)
615
- # TODO confirm types are compatible
616
- unless declared_fields[name]
617
- declared_fields[name] = type
618
- field = if static || static_field
619
- @class.private_static_field name, type
620
- else
621
- @class.private_field name, type
622
- end
623
- annotate(field, annotations)
624
- end
625
- end
626
-
627
- def field_declare(name, type, annotations, static_field)
628
- name = name[1..-1] if name =~ /^@/
629
- declare_field(name, type, annotations, static_field)
630
- end
631
-
632
- def field_assign(name, type, expression, value, annotations, static_field)
633
- name = name[1..-1] if name =~ /^@/
634
-
635
- real_type = declared_fields[name] || type
636
-
637
- declare_field(name, real_type, annotations, static_field)
638
-
639
- method.aload 0 unless static || static_field
640
- value.compile(self, true)
641
- if expression
642
- instruction = 'dup'
643
- instruction << '2' if type.wide?
644
- instruction << '_x1' unless static || static_field
645
- method.send instruction
646
- end
647
-
648
- if static || static_field
649
- @method.putstatic(@class, name, real_type)
650
- else
651
- @method.putfield(@class, name, real_type)
652
- end
653
- end
654
-
655
- def string(value)
656
- @method.ldc(value)
657
- end
658
-
659
- def build_string(nodes, expression)
660
- if expression
661
- # could probably be more efficient with non-default constructor
662
- builder_class = Mirah::AST.type(nil, 'java.lang.StringBuilder')
663
- @method.new builder_class
664
- @method.dup
665
- @method.invokespecial builder_class, "<init>", [@method.void]
666
-
667
- nodes.each do |node|
668
- node.compile(self, true)
669
- method = find_method(builder_class, "append", [node.inferred_type], false)
670
- if method
671
- @method.invokevirtual builder_class, "append", [method.return_type, *method.argument_types]
672
- else
673
- log "Could not find a match for #{java::lang::StringBuilder}.append(#{node.inferred_type})"
674
- fail "Could not compile"
675
- end
676
- end
677
-
678
- # convert to string
679
- @method.invokevirtual java::lang::StringBuilder.java_class, "toString", [@method.string]
680
- else
681
- nodes.each do |node|
682
- node.compile(self, false)
683
- end
684
- end
685
- end
686
-
687
- def to_string(body, expression)
688
- if expression
689
- body.compile(self, true)
690
- body.inferred_type.box(@method) if body.inferred_type.primitive?
691
- null = method.label
692
- done = method.label
693
- method.dup
694
- method.ifnull(null)
695
- @method.invokevirtual @method.object, "toString", [@method.string]
696
- @method.goto(done)
697
- null.set!
698
- method.pop
699
- method.ldc("null")
700
- done.set!
701
- else
702
- body.compile(self, false)
703
- end
704
- end
705
-
706
- def boolean(value)
707
- value ? @method.iconst_1 : @method.iconst_0
708
- end
709
-
710
- def regexp(value, flags = 0)
711
- # TODO: translate flags to Java-appropriate values
712
- @method.ldc(value)
713
- @method.invokestatic java::util::regex::Pattern, "compile", [java::util::regex::Pattern, @method.string]
714
- end
715
-
716
- def array(node, expression)
717
- if expression
718
- # create basic arraylist
719
- @method.new java::util::ArrayList
720
- @method.dup
721
- @method.ldc_int node.children ? node.children.size : 0
722
- @method.invokespecial java::util::ArrayList, "<init>", [@method.void, @method.int]
723
-
724
- # elements, as expressions
725
- # TODO: ensure they're all reference types!
726
- node.children.each do |n|
727
- @method.dup
728
- n.compile(self, true)
729
- # TODO this feels like it should be in the node.compile itself
730
- if n.inferred_type!.primitive?
731
- n.inferred_type.box(@method)
732
- end
733
- @method.invokeinterface java::util::List, "add", [@method.boolean, @method.object]
734
- @method.pop
735
- end
736
-
737
- # make it unmodifiable
738
- @method.invokestatic java::util::Collections, "unmodifiableList", [java::util::List, java::util::List]
739
- else
740
- # elements, as non-expressions
741
- # TODO: ensure they're all reference types!
742
- node.children.each do |n|
743
- n.compile(self, true)
744
- # TODO this feels like it should be in the node.compile itself
745
- if n.inferred_type.primitive?
746
- n.inferred_type.box(@method)
747
- end
748
- end
749
- end
750
- end
751
-
752
- def null
753
- @method.aconst_null
754
- end
755
-
756
- def binding_reference
757
- @method.aload(@method.local('$binding'))
758
- end
759
-
760
- def real_self
761
- method.aload(0)
762
- end
763
-
764
- def line(num)
765
- @method.line(num) if @method
766
- end
767
-
768
- def print(print_node)
769
- @method.getstatic System, "out", PrintStream
770
- print_node.parameters.each {|param| param.compile(self, true)}
771
- params = print_node.parameters.map {|param| param.inferred_type.jvm_type}
772
- method_name = print_node.println ? "println" : "print"
773
- method = find_method(PrintStream.java_class, method_name, params, false)
774
- if (method)
775
- @method.invokevirtual(
776
- PrintStream,
777
- method_name,
778
- [method.return_type, *method.parameter_types])
779
- else
780
- log "Could not find a match for #{PrintStream}.#{method_name}(#{params})"
781
- fail "Could not compile"
782
- end
783
- end
784
-
785
- def return(return_node)
786
- return_node.value.compile(self, true) if return_node.value
787
- handle_ensures(find_ensures(Mirah::AST::MethodDefinition))
788
- return_node.inferred_type.return(@method)
789
- end
790
-
791
- def _raise(exception)
792
- exception.compile(self, true)
793
- @method.athrow
794
- end
795
-
796
- def rescue(rescue_node, expression)
797
- start = @method.label.set!
798
- body_end = @method.label
799
- done = @method.label
800
- rescue_node.body.compile(self, expression)
801
- body_end.set!
802
- @method.goto(done)
803
- rescue_node.clauses.each do |clause|
804
- target = @method.label.set!
805
- if clause.name
806
- @method.astore(declare_local(clause.static_scope, clause.name, clause.type))
807
- else
808
- @method.pop
809
- end
810
- declare_locals(clause.static_scope)
811
- clause.body.compile(self, expression)
812
- @method.goto(done)
813
- clause.types.each do |type|
814
- @method.trycatch(start, body_end, target, type)
815
- end
816
- end
817
- done.set!
818
- end
819
-
820
- def handle_ensures(nodes)
821
- nodes.each do |ensure_node|
822
- ensure_node.clause.compile(self, false)
823
- end
824
- end
825
-
826
- def ensure(node, expression)
827
- node.state = @method.label # Save the ensure target for JumpNodes
828
- start = @method.label.set!
829
- body_end = @method.label
830
- done = @method.label
831
- push_jump_scope(node) do
832
- node.body.compile(self, expression) # First compile the body
833
- end
834
- body_end.set!
835
- handle_ensures([node]) # run the ensure clause
836
- @method.goto(done) # and continue on after the exception handler
837
- target = @method.label.set! # Finally, create the exception handler
838
- @method.trycatch(start, body_end, target, nil)
839
- handle_ensures([node])
840
- @method.athrow
841
- done.set!
842
- end
843
-
844
- def empty_array(type, size)
845
- size.compile(self, true)
846
- type.newarray(@method)
847
- end
848
-
849
- def bootstrap_dynamic
850
- # hacky, I know
851
- unless defined? @class.bootstrapped
852
- def @class.bootstrapped; true; end
853
- method = @class.build_method("<clinit>", :public, :static, [], Java::void)
854
- method.start
855
- method.ldc org.mirah.DynalangBootstrap
856
- method.ldc "bootstrap"
857
- method.invokestatic java.dyn.Linkage, "registerBootstrapMethod", [method.void, java.lang.Class, method.string]
858
- method.returnvoid
859
- method.stop
860
- end
861
- end
862
-
863
- class ClosureCompiler < Mirah::Compiler::JVM
864
- def initialize(file, type, parent)
865
- @file = file
866
- @type = type
867
- @jump_scope = []
868
- @parent = parent
869
- end
870
-
871
- def prepare_binding(scope)
872
- if scope.has_binding?
873
- type = scope.binding_type
874
- @binding = @parent.get_binding(type)
875
- @method.aload 0
876
- @method.getfield(@class, 'binding', @binding)
877
- type.store(@method, @method.local('$binding', type))
878
- end
879
- begin
880
- yield
881
- ensure
882
- if scope.has_binding?
883
- @binding = nil
884
- end
885
- end
886
- end
887
-
888
- def declared_captures
889
- @parent.declared_captures(@binding)
890
- end
891
- end
892
- end
893
- end
894
35
  end
895
36
 
896
37
  if __FILE__ == $0
897
38
  Mirah::Typer.verbose = true
898
39
  Mirah::AST.verbose = true
899
- Mirah::Compiler::JVM.verbose = true
40
+ Mirah::JVM::Compiler::JVMBytecode.verbose = true
900
41
  ast = Mirah::AST.parse(File.read(ARGV[0]))
901
-
42
+
902
43
  typer = Mirah::Typer::Simple.new(:script)
903
44
  ast.infer(typer)
904
45
  typer.resolve(true)
905
-
906
- compiler = Mirah::Compiler::JVM.new(ARGV[0])
46
+
47
+ compiler = Mirah::JVM::Compiler::JVMBytecode.new(ARGV[0])
907
48
  compiler.compile(ast)
908
-
49
+
909
50
  compiler.generate
910
51
  end