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.
- data/History.txt +181 -0
- data/README.txt +6 -10
- data/Rakefile +86 -9
- data/bin/mirah +2 -0
- data/bin/mirahc +2 -0
- data/bin/mirahp +2 -0
- data/{bin/dubyp → examples/interfaces.mirah} +16 -9
- data/examples/macros/square.mirah +12 -0
- data/examples/macros/square_int.mirah +12 -0
- data/examples/macros/string-each-char.mirah +14 -0
- data/examples/maven/README.txt +2 -0
- data/examples/maven/pom.xml +23 -0
- data/examples/maven/src/main/mirah/hello_mirah.mirah +9 -0
- data/examples/rosettacode/100-doors.mirah +44 -0
- data/examples/rosettacode/99-bottles-of-beer.mirah +13 -0
- data/examples/rosettacode/README.txt +9 -0
- data/examples/rosettacode/boolean-values.mirah +29 -0
- data/examples/rosettacode/comments.mirah +2 -0
- data/examples/rosettacode/copy-a-string.mirah +10 -0
- data/examples/rosettacode/count-occurrences-of-a-substring.mirah +40 -0
- data/examples/rosettacode/create-a-file.mirah +6 -0
- data/examples/rosettacode/empty-string.mirah +9 -0
- data/examples/rosettacode/factorial.mirah +10 -0
- data/examples/rosettacode/fibonacci.mirah +21 -0
- data/examples/rosettacode/file-size.mirah +5 -0
- data/examples/rosettacode/fizz-buzz.mirah +21 -0
- data/examples/rosettacode/flatten-a-list.mirah +24 -0
- data/examples/rosettacode/guess-the-number.mirah +21 -0
- data/examples/rosettacode/is-string-numeric.mirah +127 -0
- data/examples/rosettacode/palindrome.mirah +14 -0
- data/examples/rosettacode/repeat-a-string.mirah +9 -0
- data/examples/rosettacode/reverse-a-string.mirah +6 -0
- data/examples/rosettacode/rot-13.mirah +20 -0
- data/examples/rosettacode/user-input.mirah +4 -0
- data/examples/sort_closure.mirah +1 -1
- data/javalib/dynalink-0.2.jar +0 -0
- data/javalib/mirah-bootstrap.jar +0 -0
- data/lib/mirah.rb +7 -16
- data/lib/mirah/ast.rb +22 -92
- data/lib/mirah/ast/call.rb +41 -9
- data/lib/mirah/ast/class.rb +34 -6
- data/lib/mirah/ast/flow.rb +17 -5
- data/lib/mirah/ast/intrinsics.rb +50 -8
- data/lib/mirah/ast/literal.rb +7 -0
- data/lib/mirah/ast/local.rb +9 -1
- data/lib/mirah/ast/method.rb +21 -8
- data/lib/mirah/ast/scope.rb +1 -1
- data/lib/mirah/ast/structure.rb +81 -15
- data/lib/mirah/ast/type.rb +4 -0
- data/{bin/dubyc → lib/mirah/commands.rb} +4 -11
- data/lib/mirah/commands/base.rb +54 -0
- data/lib/mirah/commands/compile.rb +39 -0
- data/{examples/wiki/Rakefile → lib/mirah/commands/parse.rb} +18 -17
- data/lib/mirah/commands/run.rb +73 -0
- data/lib/mirah/compiler.rb +37 -417
- data/lib/mirah/compiler/call.rb +45 -0
- data/lib/mirah/compiler/class.rb +81 -0
- data/lib/mirah/compiler/flow.rb +109 -0
- data/lib/mirah/compiler/literal.rb +130 -0
- data/lib/mirah/compiler/local.rb +59 -0
- data/lib/mirah/compiler/method.rb +44 -0
- data/lib/mirah/compiler/structure.rb +65 -0
- data/lib/mirah/compiler/type.rb +27 -0
- data/lib/mirah/env.rb +4 -6
- data/lib/mirah/generator.rb +61 -0
- data/lib/mirah/jvm/compiler.rb +8 -867
- data/lib/mirah/jvm/compiler/base.rb +270 -0
- data/lib/mirah/jvm/compiler/java_source.rb +779 -0
- data/lib/mirah/jvm/compiler/jvm_bytecode.rb +851 -0
- data/lib/mirah/jvm/method_lookup.rb +21 -2
- data/lib/mirah/jvm/source_generator/builder.rb +10 -13
- data/lib/mirah/jvm/source_generator/loops.rb +99 -93
- data/lib/mirah/jvm/source_generator/precompile.rb +3 -2
- data/lib/mirah/jvm/typer.rb +3 -3
- data/lib/mirah/jvm/types.rb +10 -426
- data/lib/mirah/jvm/types/array_type.rb +62 -0
- data/lib/mirah/jvm/types/basic_types.rb +1 -0
- data/lib/mirah/jvm/types/dynamic_type.rb +46 -0
- data/lib/mirah/jvm/types/factory.rb +23 -5
- data/lib/mirah/jvm/types/interface_definition.rb +20 -0
- data/lib/mirah/jvm/types/intrinsics.rb +15 -3
- data/lib/mirah/jvm/types/meta_type.rb +45 -0
- data/lib/mirah/jvm/types/methods.rb +12 -5
- data/lib/mirah/jvm/types/null_type.rb +27 -0
- data/lib/mirah/jvm/types/primitive_type.rb +38 -0
- data/lib/mirah/jvm/types/source_mirror.rb +266 -0
- data/lib/mirah/jvm/types/type.rb +173 -0
- data/lib/mirah/jvm/types/type_definition.rb +55 -0
- data/lib/mirah/jvm/types/unreachable_type.rb +27 -0
- data/lib/mirah/jvm/types/void_type.rb +19 -0
- data/lib/mirah/parser.rb +90 -0
- data/lib/mirah/plugin/gwt.rb +5 -5
- data/lib/mirah/plugin/java.rb +1 -1
- data/lib/mirah/transform.rb +4 -321
- data/lib/mirah/transform/ast_ext.rb +63 -0
- data/lib/mirah/transform/error.rb +13 -0
- data/lib/mirah/transform/helper.rb +761 -0
- data/lib/mirah/transform/transformer.rb +255 -0
- data/lib/mirah/typer.rb +2 -383
- data/{bin/duby → lib/mirah/typer/base.rb} +12 -10
- data/lib/mirah/typer/simple.rb +377 -0
- data/lib/mirah/util/argument_processor.rb +114 -0
- data/lib/mirah/util/class_loader.rb +37 -0
- data/lib/mirah/util/compilation_state.rb +51 -0
- data/lib/mirah/util/process_errors.rb +33 -0
- data/lib/mirah/version.rb +1 -1
- data/lib/mirah_task.rb +3 -2
- data/test/{test_ast.rb → core/test_ast.rb} +6 -0
- data/test/{test_compilation.rb → core/test_compilation.rb} +0 -0
- data/test/{test_env.rb → core/test_env.rb} +24 -25
- data/test/{test_macros.rb → core/test_macros.rb} +2 -4
- data/test/{test_typer.rb → core/test_typer.rb} +0 -3
- data/test/jvm/bytecode_test_helper.rb +181 -0
- data/test/{test_javac_compiler.rb → jvm/javac_test_helper.rb} +38 -22
- data/test/jvm/test_enumerable.rb +304 -0
- data/test/{test_java_typer.rb → jvm/test_java_typer.rb} +2 -4
- data/test/{test_jvm_compiler.rb → jvm/test_jvm_compiler.rb} +146 -443
- data/test/jvm/test_macros.rb +147 -0
- data/test/jvm/test_main_method.rb +15 -0
- data/test/{test_gwt.rb → plugins/test_gwt.rb} +0 -2
- metadata +103 -91
- data/bin/jrubyp +0 -52
- data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +0 -339
- data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +0 -42
- data/examples/wiki/src/org/mirah/wiki/error.eduby.html +0 -2
- data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +0 -69
- data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +0 -7
- data/examples/wiki/src/org/mirah/wiki/view.eduby.html +0 -15
- data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
- data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
- data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
- data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
- data/examples/wiki/war/app.yaml +0 -21
- data/examples/wiki/war/public/favicon.ico +0 -0
- data/examples/wiki/war/public/images/appengine_duby.png +0 -0
- data/examples/wiki/war/public/images/back.gif +0 -0
- data/examples/wiki/war/public/images/dir.gif +0 -0
- data/examples/wiki/war/public/images/file.gif +0 -0
- data/examples/wiki/war/public/javascripts/prettify.js +0 -61
- data/examples/wiki/war/public/robots.txt +0 -0
- data/examples/wiki/war/public/stylesheets/main.css +0 -156
- data/examples/wiki/war/public/stylesheets/prettify.css +0 -1
- data/examples/wiki/war/public/stylesheets/sh_style.css +0 -66
- data/examples/wiki/war/public/stylesheets/source.css +0 -21
- data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
- data/examples/wiki/war/public/wmd/images/bg.png +0 -0
- data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
- data/examples/wiki/war/public/wmd/images/bold.png +0 -0
- data/examples/wiki/war/public/wmd/images/code.png +0 -0
- data/examples/wiki/war/public/wmd/images/h1.png +0 -0
- data/examples/wiki/war/public/wmd/images/hr.png +0 -0
- data/examples/wiki/war/public/wmd/images/img.png +0 -0
- data/examples/wiki/war/public/wmd/images/italic.png +0 -0
- data/examples/wiki/war/public/wmd/images/link.png +0 -0
- data/examples/wiki/war/public/wmd/images/ol.png +0 -0
- data/examples/wiki/war/public/wmd/images/redo.png +0 -0
- data/examples/wiki/war/public/wmd/images/separator.png +0 -0
- data/examples/wiki/war/public/wmd/images/ul.png +0 -0
- data/examples/wiki/war/public/wmd/images/undo.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
- data/examples/wiki/war/public/wmd/showdown.js +0 -421
- data/examples/wiki/war/public/wmd/wmd-base.js +0 -1799
- data/examples/wiki/war/public/wmd/wmd-plus.js +0 -311
- data/examples/wiki/war/public/wmd/wmd.js +0 -73
- data/examples/wiki/war/src/org/mirah/wiki/MirahWiki.duby +0 -339
- data/examples/wiki/war/src/org/mirah/wiki/edit.eduby.html +0 -42
- data/examples/wiki/war/src/org/mirah/wiki/error.eduby.html +0 -2
- data/examples/wiki/war/src/org/mirah/wiki/layout.eduby.html +0 -69
- data/examples/wiki/war/src/org/mirah/wiki/parser.eduby.html +0 -7
- data/examples/wiki/war/src/org/mirah/wiki/view.eduby.html +0 -15
- data/javalib/dynalink-0.1.jar +0 -0
- data/javalib/jsr292-mock.jar +0 -0
- data/lib/mirah/class_loader.rb +0 -35
- data/lib/mirah/compilation_state.rb +0 -28
- data/lib/mirah/impl.rb +0 -273
- data/lib/mirah/jvm/base.rb +0 -267
- data/lib/mirah/jvm/source_compiler.rb +0 -760
- 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
|
data/lib/mirah/env.rb
CHANGED
|
@@ -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.
|
|
25
|
-
|
|
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(
|
|
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(
|
|
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
|
data/lib/mirah/jvm/compiler.rb
CHANGED
|
@@ -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::
|
|
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::
|
|
46
|
+
|
|
47
|
+
compiler = Mirah::JVM::Compiler::JVMBytecode.new(ARGV[0])
|
|
907
48
|
compiler.compile(ast)
|
|
908
|
-
|
|
49
|
+
|
|
909
50
|
compiler.generate
|
|
910
51
|
end
|