mirah 0.0.7-java → 0.0.8-java

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