mirah 0.1.2-java → 0.1.3-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.
- checksums.yaml +4 -4
- data/History.txt +225 -0
- data/Rakefile +108 -315
- data/TODO.md +100 -0
- data/bin/bundler +16 -0
- data/bin/rake +16 -0
- data/dist/mirahc.jar +0 -0
- data/examples/appengine/Readme +0 -1
- data/examples/literals.mirah +17 -0
- data/examples/macros/string_each_char.mirah +1 -1
- data/lib/mirah.rb +11 -21
- data/lib/mirah/transform/transformer.rb +1 -2
- data/lib/mirah/util/class_loader.rb +1 -1
- data/lib/mirah/util/logging.rb +0 -63
- data/lib/mirah/util/process_errors.rb +1 -0
- data/lib/mirah/version.rb +1 -1
- data/{examples/simple_class.mirah~ → test/artifacts/jar_test.rb} +7 -11
- data/{lib/mirah/commands.rb → test/artifacts/jruby_test.rb} +8 -5
- data/test/core/typer_test.rb +29 -11
- data/test/core/util/argument_processor_test.rb +24 -23
- data/test/core/util/class_loader_test.rb +7 -4
- data/test/core/util/{compilation_state_test.rb → jvm_version_test.rb} +20 -16
- data/test/fixtures/org/foo/ImplicitClassRetAnno.java +4 -0
- data/test/fixtures/org/foo/IntAnno.java +9 -0
- data/test/jvm/annotations_test.rb +11 -11
- data/test/jvm/blocks_test.rb +16 -12
- data/test/jvm/constructors_test.rb +8 -8
- data/test/jvm/enumerable_test.rb +48 -24
- data/test/jvm/generics_test.rb +3 -7
- data/test/jvm/import_test.rb +14 -0
- data/test/jvm/interface_test.rb +9 -24
- data/test/jvm/jvm_commands_test.rb +22 -4
- data/test/jvm/jvm_compiler_test.rb +124 -79
- data/test/jvm/list_extensions_test.rb +1 -1
- data/test/jvm/macros_test.rb +67 -14
- data/test/jvm/main_method_test.rb +1 -1
- data/test/jvm/new_backend_test_helper.rb +100 -3
- data/{lib/mirah/jvm/types/bitescript_ext.rb → test/jvm/static_fields_test.rb} +22 -21
- data/test/mirrors/base_type_test.rb +4 -3
- data/test/mirrors/bytecode_mirror_test.rb +35 -15
- data/test/mirrors/generics_test.rb +14 -5
- data/test/mirrors/member_test.rb +2 -1
- data/test/mirrors/method_lookup_test.rb +18 -6
- data/test/mirrors/mirrors_test.rb +87 -20
- data/test/mirrors/simple_async_mirror_loader_test.rb +7 -3
- data/test/mirrors/simple_mirror_loader_test.rb +5 -5
- data/test/test_helper.rb +25 -1
- metadata +18 -78
- data/bin/mirahp +0 -27
- data/bin/mirahp.cmd +0 -16
- data/examples/Fib.class +0 -0
- data/javalib/mirah-bootstrap.jar +0 -0
- data/javalib/mirah-builtins.jar +0 -0
- data/javalib/mirah-compiler.jar +0 -0
- data/javalib/mirah-mirrors.jar +0 -0
- data/javalib/mirah-newast-transitional.jar +0 -0
- data/javalib/mirah-parser.jar +0 -0
- data/javalib/mirah-util.jar +0 -0
- data/lib/mirah/ast.rb +0 -43
- data/lib/mirah/ast/scope.rb +0 -262
- data/lib/mirah/commands/base.rb +0 -59
- data/lib/mirah/commands/compile.rb +0 -39
- data/lib/mirah/commands/parse.rb +0 -36
- data/lib/mirah/commands/run.rb +0 -78
- data/lib/mirah/generator.rb +0 -150
- data/lib/mirah/jvm/compiler.rb +0 -50
- data/lib/mirah/jvm/compiler/base.rb +0 -421
- data/lib/mirah/jvm/compiler/jvm_bytecode.rb +0 -1194
- data/lib/mirah/jvm/method_lookup.rb +0 -307
- data/lib/mirah/jvm/types.rb +0 -45
- data/lib/mirah/jvm/types/array_type.rb +0 -60
- data/lib/mirah/jvm/types/ast_ext.rb +0 -31
- data/lib/mirah/jvm/types/basic_types.rb +0 -41
- data/lib/mirah/jvm/types/block_type.rb +0 -15
- data/lib/mirah/jvm/types/boolean.rb +0 -70
- data/lib/mirah/jvm/types/enumerable.rb +0 -80
- data/lib/mirah/jvm/types/extensions.rb +0 -110
- data/lib/mirah/jvm/types/factory.rb +0 -830
- data/lib/mirah/jvm/types/floats.rb +0 -99
- data/lib/mirah/jvm/types/generic_type.rb +0 -72
- data/lib/mirah/jvm/types/implicit_nil_type.rb +0 -29
- data/lib/mirah/jvm/types/integers.rb +0 -131
- data/lib/mirah/jvm/types/interface_definition.rb +0 -20
- data/lib/mirah/jvm/types/intrinsics.rb +0 -385
- data/lib/mirah/jvm/types/literals.rb +0 -89
- data/lib/mirah/jvm/types/meta_type.rb +0 -54
- data/lib/mirah/jvm/types/methods.rb +0 -946
- data/lib/mirah/jvm/types/null_type.rb +0 -39
- data/lib/mirah/jvm/types/number.rb +0 -184
- data/lib/mirah/jvm/types/primitive_type.rb +0 -76
- data/lib/mirah/jvm/types/source_mirror.rb +0 -274
- data/lib/mirah/jvm/types/type.rb +0 -311
- data/lib/mirah/jvm/types/type_definition.rb +0 -72
- data/lib/mirah/jvm/types/void_type.rb +0 -19
- data/lib/mirah/util/compilation_state.rb +0 -60
- data/test/core/commands_test.rb +0 -89
- data/test/core/generator_test.rb +0 -26
- data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
- data/test/jvm/bytecode_test_helper.rb +0 -193
- data/test/jvm/factory_test.rb +0 -28
- data/test/jvm/java_typer_test.rb +0 -283
data/lib/mirah/commands/parse.rb
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
|
|
2
|
-
# All contributing project authors may be found in the NOTICE file.
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
|
|
16
|
-
require 'mirah/parser'
|
|
17
|
-
|
|
18
|
-
module Mirah
|
|
19
|
-
module Commands
|
|
20
|
-
class Parse < Base
|
|
21
|
-
def execute
|
|
22
|
-
execute_base do
|
|
23
|
-
parser = Mirah::Parser.new(@state, nil, false)
|
|
24
|
-
|
|
25
|
-
parser.parse_from_args(args).each do |ast|
|
|
26
|
-
puts parser.format_ast(ast)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def command_name
|
|
32
|
-
:parse
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
data/lib/mirah/commands/run.rb
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
|
|
2
|
-
# All contributing project authors may be found in the NOTICE file.
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
|
|
16
|
-
require 'mirah/generator'
|
|
17
|
-
require 'mirah/util/class_loader'
|
|
18
|
-
|
|
19
|
-
module Mirah
|
|
20
|
-
module Commands
|
|
21
|
-
class Run < Base
|
|
22
|
-
def execute
|
|
23
|
-
execute_base do
|
|
24
|
-
class_map = generate_classes
|
|
25
|
-
$CLASSPATH << Mirah::Env.decode_paths(@state.classpath) if @state.classpath
|
|
26
|
-
class_loader = load_classes class_map
|
|
27
|
-
|
|
28
|
-
main = find_main class_map, class_loader
|
|
29
|
-
|
|
30
|
-
run_main(main)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def command_name
|
|
35
|
-
:run
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def load_classes(class_map)
|
|
41
|
-
Mirah::Util::ClassLoader.new(JRuby.runtime.jruby_class_loader, class_map)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def find_main class_map, class_loader
|
|
45
|
-
# TODO: using first main; find correct one?
|
|
46
|
-
class_map.keys.each do |name|
|
|
47
|
-
cls = class_loader.load_class(name)
|
|
48
|
-
main = cls.get_method("main", java::lang::String[].java_class)
|
|
49
|
-
return main if main
|
|
50
|
-
end
|
|
51
|
-
nil
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def run_main(main)
|
|
55
|
-
if main
|
|
56
|
-
begin
|
|
57
|
-
main.invoke(nil, [args.to_java(:string)].to_java)
|
|
58
|
-
rescue java.lang.Exception => e
|
|
59
|
-
e = e.cause if e.cause
|
|
60
|
-
raise e
|
|
61
|
-
end
|
|
62
|
-
else
|
|
63
|
-
puts "No main found" unless @state.version_printed || @state.help_printed
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def generate_classes
|
|
68
|
-
# generate all bytes for all classes
|
|
69
|
-
generator = Mirah::Generator.new(@state, @state.compiler_class, false, @state.verbose)
|
|
70
|
-
class_map = {}
|
|
71
|
-
generator.generate(args).each do |result|
|
|
72
|
-
class_map[result.classname.gsub(/\//, '.')] = Mirah::Util::ClassLoader.binary_string result.bytes
|
|
73
|
-
end
|
|
74
|
-
class_map
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
data/lib/mirah/generator.rb
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
|
|
2
|
-
# All contributing project authors may be found in the NOTICE file.
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
require 'mirah/util/process_errors'
|
|
16
|
-
require 'mirah/util/logging'
|
|
17
|
-
|
|
18
|
-
module Mirah
|
|
19
|
-
class Generator
|
|
20
|
-
include Mirah::Util::ProcessErrors
|
|
21
|
-
include Mirah::Logging::Logged
|
|
22
|
-
java_import 'org.mirah.typer.simple.SimpleScoper'
|
|
23
|
-
java_import 'org.mirah.typer.simple.TypePrinter'
|
|
24
|
-
java_import 'org.mirah.macros.JvmBackend'
|
|
25
|
-
|
|
26
|
-
def initialize(state, compiler_class, logging, verbose)
|
|
27
|
-
@state = state
|
|
28
|
-
|
|
29
|
-
# TODO untie this from the jvm backend (nh)
|
|
30
|
-
if state.type_system
|
|
31
|
-
# Using new type system
|
|
32
|
-
@scoper = SimpleScoper.new do |scoper, node|
|
|
33
|
-
scope = Java::OrgMirahJvmMirrors::JVMScope.new(scoper)
|
|
34
|
-
scope.context_set(node)
|
|
35
|
-
scope
|
|
36
|
-
end
|
|
37
|
-
type_system = state.type_system
|
|
38
|
-
else
|
|
39
|
-
@scoper = SimpleScoper.new {|scoper, node| Mirah::AST::StaticScope.new(node, scoper)}
|
|
40
|
-
type_system = Mirah::JVM::Types::TypeFactory.new
|
|
41
|
-
type_system.classpath = state.classpath if state.classpath
|
|
42
|
-
type_system.bootclasspath = state.bootclasspath
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
@typer = Mirah::Typer::Typer.new(type_system, @scoper, self, nil)
|
|
46
|
-
@parser = Mirah::Parser.new(state, @typer, logging)
|
|
47
|
-
@compiler = Mirah::Compiler::ASTCompiler.new(state, compiler_class, logging)
|
|
48
|
-
@extension_compiler = Mirah::Compiler::ASTCompiler.new(state, compiler_class, logging)
|
|
49
|
-
if type_system.respond_to?(:maybe_initialize_builtins)
|
|
50
|
-
type_system.maybe_initialize_builtins(@typer.macro_compiler)
|
|
51
|
-
end
|
|
52
|
-
@logging = logging
|
|
53
|
-
@verbose = verbose
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
attr_accessor :parser, :compiler, :typer, :logging, :verbose
|
|
57
|
-
|
|
58
|
-
def generate(arguments)
|
|
59
|
-
# collect all ASTs from all files
|
|
60
|
-
top_nodes = parser.parse_from_args(arguments)
|
|
61
|
-
|
|
62
|
-
# enter all ASTs into inference engine
|
|
63
|
-
puts "Inferring types..." if logging
|
|
64
|
-
scoper, typer = infer_asts(top_nodes)
|
|
65
|
-
do_transforms top_nodes
|
|
66
|
-
# compile each AST in turn
|
|
67
|
-
compiler_results = compiler.compile_asts(top_nodes, scoper, typer)
|
|
68
|
-
|
|
69
|
-
puts "Done!" if logging
|
|
70
|
-
|
|
71
|
-
compiler_results
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def do_transforms nodes
|
|
75
|
-
log("Starting Transform")
|
|
76
|
-
|
|
77
|
-
java_import 'org.mirah.jvm.compiler.ClosureTransformer' rescue puts $!
|
|
78
|
-
java_import 'org.mirah.util.Context' rescue puts $!
|
|
79
|
-
#java_import 'org.mirah.typer.Typer'
|
|
80
|
-
#java_import 'org.mirah.macros.Compiler'
|
|
81
|
-
transformer = ClosureTransformer.new(Context.new.tap{|c|c.add(Java::org.mirah.typer::Typer, @typer) }) rescue nil
|
|
82
|
-
if transformer
|
|
83
|
-
nodes.each{|n| n.accept transformer, nil } # rescue log("transformer exception", $!.cause)
|
|
84
|
-
log("POST Transform")
|
|
85
|
-
log_types nodes
|
|
86
|
-
else
|
|
87
|
-
log "No transformer, skipping"
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def infer_asts(nodes, should_raise=false)
|
|
92
|
-
log_and_reraise "Caught exception during type inference" do
|
|
93
|
-
nodes.each {|ast| @typer.infer(ast, false) }
|
|
94
|
-
if should_raise
|
|
95
|
-
error_handler = lambda do |errors|
|
|
96
|
-
message, position = errors[0].message[0].to_a
|
|
97
|
-
raise Mirah::MirahError.new(message, position)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
process_inference_errors(@typer, nodes, &error_handler)
|
|
101
|
-
end
|
|
102
|
-
[@scoper, @typer]
|
|
103
|
-
ensure
|
|
104
|
-
log_types(nodes)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def log_and_reraise message
|
|
108
|
-
yield
|
|
109
|
-
rescue NativeException => ex
|
|
110
|
-
log(message, ex.cause)
|
|
111
|
-
raise ex
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def log_types(nodes)
|
|
115
|
-
if self.logging?
|
|
116
|
-
buf = java.io.ByteArrayOutputStream.new
|
|
117
|
-
ps = java.io.PrintStream.new(buf)
|
|
118
|
-
printer = TypePrinter.new(@typer, ps)
|
|
119
|
-
nodes.each {|ast| printer.scan(ast, nil)}
|
|
120
|
-
ps.close()
|
|
121
|
-
log("Inferred types:\n{0}", java.lang.String.new(buf.toByteArray))
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def compileAndLoadExtension(ast)
|
|
127
|
-
log_types([ast])
|
|
128
|
-
process_inference_errors(@typer, [ast])
|
|
129
|
-
results = @extension_compiler.compile_asts([ast], @scoper, @typer)
|
|
130
|
-
class_map = {}
|
|
131
|
-
first_class_name = nil
|
|
132
|
-
results.each do |result|
|
|
133
|
-
classname = result.classname.gsub(/\//, '.')
|
|
134
|
-
first_class_name ||= classname if classname.include?('$Extension')
|
|
135
|
-
class_map[classname] = Mirah::Util::ClassLoader.binary_string result.bytes
|
|
136
|
-
if @state.save_extensions
|
|
137
|
-
filename = "#{@state.destination}#{result.filename}"
|
|
138
|
-
FileUtils.mkdir_p(File.dirname(filename))
|
|
139
|
-
File.open(filename, 'wb') {|f| f.write(result.bytes)}
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
dcl = Mirah::Util::ClassLoader.new(JRuby.runtime.jruby_class_loader, class_map)
|
|
143
|
-
dcl.load_class(first_class_name)
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def logExtensionAst(ast)
|
|
147
|
-
log("Extension ast:\n#{parser.format_ast(ast)}")
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
data/lib/mirah/jvm/compiler.rb
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
|
|
2
|
-
# All contributing project authors may be found in the NOTICE file.
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
|
|
16
|
-
require 'mirah'
|
|
17
|
-
require 'mirah/jvm/compiler/base'
|
|
18
|
-
require 'mirah/jvm/method_lookup'
|
|
19
|
-
require 'mirah/jvm/types'
|
|
20
|
-
require 'bitescript'
|
|
21
|
-
require 'mirah/jvm/compiler/jvm_bytecode'
|
|
22
|
-
require 'mirah/transform/ast_ext'
|
|
23
|
-
|
|
24
|
-
module Mirah
|
|
25
|
-
module AST
|
|
26
|
-
class FunctionalCall
|
|
27
|
-
attr_accessor :target
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
class Super
|
|
31
|
-
attr_accessor :target
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
module Mirah
|
|
37
|
-
module JVM
|
|
38
|
-
module Compiler
|
|
39
|
-
begin
|
|
40
|
-
class Backend < Java::OrgMirahJvmCompiler::Backend
|
|
41
|
-
def initialize(config, scoper, typer)
|
|
42
|
-
super(typer)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
rescue NameError
|
|
46
|
-
puts "Unable to load new Backend"
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
|
|
2
|
-
# All contributing project authors may be found in the NOTICE file.
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
|
|
16
|
-
module Mirah
|
|
17
|
-
module JVM
|
|
18
|
-
module Compiler
|
|
19
|
-
java_import 'mirah.lang.ast.ClassDefinition'
|
|
20
|
-
java_import 'mirah.lang.ast.StaticMethodDefinition'
|
|
21
|
-
java_import 'mirah.lang.ast.SimpleNodeVisitor'
|
|
22
|
-
java_import 'mirah.lang.ast.NodeScanner'
|
|
23
|
-
|
|
24
|
-
class Base < SimpleNodeVisitor
|
|
25
|
-
attr_accessor :filename, :method, :static, :class
|
|
26
|
-
include Mirah::Logging::Logged
|
|
27
|
-
|
|
28
|
-
class CompilationError < Mirah::NodeError
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def logger_name
|
|
32
|
-
"org.mirah.ruby.JVM.Compiler.Base"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def initialize(config, scoper, typer)
|
|
36
|
-
super()
|
|
37
|
-
@config = config
|
|
38
|
-
@jump_scope = []
|
|
39
|
-
@bindings = Hash.new {|h, type| h[type] = type.define(@file)}
|
|
40
|
-
@captured_locals = Hash.new {|h, binding| h[binding] = {}}
|
|
41
|
-
@self_scope = nil
|
|
42
|
-
@scoper = typer.scoper
|
|
43
|
-
@typer = typer
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def target_jvm_version
|
|
47
|
-
@config.target_jvm_version
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def supports_invokedynamic?
|
|
51
|
-
@config.supports_invokedynamic?
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def defaultNode(node, expression)
|
|
55
|
-
raise ArgumentError, "Can't compile node #{node}"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def visit(node, expression)
|
|
59
|
-
begin
|
|
60
|
-
node.accept(self, expression)
|
|
61
|
-
rescue Exception => ex
|
|
62
|
-
raise Mirah::InternalCompilerError.wrap(ex, node)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def get_scope(node)
|
|
67
|
-
@scoper.get_scope(node)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def introduced_scope(node)
|
|
71
|
-
@scoper.get_introduced_scope(node)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def containing_scope(node)
|
|
75
|
-
scope = get_scope(node)
|
|
76
|
-
name = node.name.identifier
|
|
77
|
-
while (!scope.shadowed?(name) && scope.parent && scope.parent.include?(name))
|
|
78
|
-
scope = scope.parent
|
|
79
|
-
end
|
|
80
|
-
scope
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def inferred_type(node)
|
|
84
|
-
begin
|
|
85
|
-
@typer.get_inferred_type(node).resolve
|
|
86
|
-
rescue Exception => ex
|
|
87
|
-
raise Mirah::InternalCompilerError.wrap(ex, node)
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def error(message, node)
|
|
92
|
-
raise CompilationError.new(message, node)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def toplevel_class
|
|
96
|
-
@class = @type.define(@file)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def generate
|
|
100
|
-
log "Generating #{output_type}..."
|
|
101
|
-
@file.generate do |filename, builder|
|
|
102
|
-
log " #{builder.class_name}"
|
|
103
|
-
if block_given?
|
|
104
|
-
yield filename, builder
|
|
105
|
-
else
|
|
106
|
-
File.open(filename, 'wb') {|f| f.write(builder.generate)}
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
log "...done!"
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Scans the top level of a file to see if it contains anything outside of a ClassDefinition.
|
|
113
|
-
class ScriptScanner < NodeScanner
|
|
114
|
-
attr_reader :found_other, :found_method
|
|
115
|
-
def enterDefault(node, arg)
|
|
116
|
-
@found_other = true
|
|
117
|
-
false
|
|
118
|
-
end
|
|
119
|
-
def enterMethodDefinition(node, arg)
|
|
120
|
-
@found_method = true
|
|
121
|
-
false
|
|
122
|
-
end
|
|
123
|
-
def enterStaticMethodDefinition(node, arg)
|
|
124
|
-
@found_method = true
|
|
125
|
-
false
|
|
126
|
-
end
|
|
127
|
-
def enterConstructorDefinition(node, arg)
|
|
128
|
-
@found_method = true
|
|
129
|
-
false
|
|
130
|
-
end
|
|
131
|
-
def enterPackage(node, arg)
|
|
132
|
-
# ignore
|
|
133
|
-
false
|
|
134
|
-
end
|
|
135
|
-
def enterClassDefinition(node, arg)
|
|
136
|
-
# ignore
|
|
137
|
-
false
|
|
138
|
-
end
|
|
139
|
-
def enterInterfaceDeclaration(node, arg)
|
|
140
|
-
# ignore
|
|
141
|
-
false
|
|
142
|
-
end
|
|
143
|
-
def enterImport(node, arg)
|
|
144
|
-
# ignore
|
|
145
|
-
false
|
|
146
|
-
end
|
|
147
|
-
def enterNodeList(node, arg)
|
|
148
|
-
# Scan the children
|
|
149
|
-
true
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def visitMacroDefinition(node, expression)
|
|
154
|
-
# ignore. It was already compiled
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def visitScript(script, expression)
|
|
158
|
-
@static = true
|
|
159
|
-
@filename = File.basename(script.position.source.name)
|
|
160
|
-
classname = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(@filename)
|
|
161
|
-
@type = @typer.type_system.type(get_scope(script), classname)
|
|
162
|
-
@file = file_builder(@filename)
|
|
163
|
-
body = script.body
|
|
164
|
-
scanner = ScriptScanner.new
|
|
165
|
-
scanner.scan(body, expression)
|
|
166
|
-
need_class = scanner.found_method || scanner.found_other
|
|
167
|
-
if need_class
|
|
168
|
-
@class = @type.define(@file)
|
|
169
|
-
if scanner.found_other
|
|
170
|
-
# Generate the main method
|
|
171
|
-
with :method => @class.main do
|
|
172
|
-
log "Starting main method"
|
|
173
|
-
|
|
174
|
-
@method.start
|
|
175
|
-
@current_scope = get_scope(script)
|
|
176
|
-
declare_locals(@current_scope)
|
|
177
|
-
begin_main
|
|
178
|
-
|
|
179
|
-
prepare_binding(script) do
|
|
180
|
-
visit(body, false)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
finish_main
|
|
184
|
-
@method.stop
|
|
185
|
-
end
|
|
186
|
-
log "Main method complete!"
|
|
187
|
-
else
|
|
188
|
-
visit(body, false)
|
|
189
|
-
end
|
|
190
|
-
@class.stop
|
|
191
|
-
else
|
|
192
|
-
visit(body, false)
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def visitNoop(node, expression)
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def begin_main; end
|
|
200
|
-
def finish_main; end
|
|
201
|
-
|
|
202
|
-
# arg_types must be an Array
|
|
203
|
-
def create_method_builder(name, node, static, exceptions, return_type, arg_types)
|
|
204
|
-
return_type = nil if return_type.name == ':unreachable'
|
|
205
|
-
visibility = :public # TODO
|
|
206
|
-
flags = BiteScript::ASM::Opcodes::ACC_PUBLIC
|
|
207
|
-
flags |= BiteScript::ASM::Opcodes::ACC_STATIC if static
|
|
208
|
-
flags |= BiteScript::ASM::Opcodes::ACC_ABSTRACT if node.annotated_abstract?
|
|
209
|
-
@class.method(flags, name.to_s, [return_type, *arg_types], exceptions)
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
def base_define_method(node)
|
|
213
|
-
name = node.name.identifier.sub(/=$/, '_set')
|
|
214
|
-
args = visit(node.arguments, true)
|
|
215
|
-
is_static = self.static || node.kind_of?(StaticMethodDefinition)
|
|
216
|
-
if name == "initialize" && is_static
|
|
217
|
-
name = "<clinit>"
|
|
218
|
-
end
|
|
219
|
-
arg_types = args.map { |arg| inferred_type(arg) }
|
|
220
|
-
return_type = inferred_type(node).return_type
|
|
221
|
-
exceptions = [] # TODO
|
|
222
|
-
|
|
223
|
-
with :static => is_static, :current_scope => introduced_scope(node) do
|
|
224
|
-
method = create_method_builder(name, node, @static, exceptions,
|
|
225
|
-
return_type, arg_types)
|
|
226
|
-
annotate(method, node.annotations)
|
|
227
|
-
yield method, arg_types
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
arg_types_for_opt = []
|
|
231
|
-
args_for_opt = []
|
|
232
|
-
if args
|
|
233
|
-
args.each do |arg|
|
|
234
|
-
if AST::OptionalArgument === arg
|
|
235
|
-
new_args = arg_types_for_opt
|
|
236
|
-
method = create_method_builder(name, node, @static, exceptions,
|
|
237
|
-
return_type, new_args)
|
|
238
|
-
with :method => method do
|
|
239
|
-
log "Starting new method #{name}(#{arg_types_for_opt})"
|
|
240
|
-
|
|
241
|
-
annotate(method, node.annotations)
|
|
242
|
-
@method.start
|
|
243
|
-
|
|
244
|
-
define_optarg_chain(name, arg,
|
|
245
|
-
return_type,
|
|
246
|
-
args_for_opt,
|
|
247
|
-
arg_types_for_opt)
|
|
248
|
-
|
|
249
|
-
@method.stop
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
arg_types_for_opt << inferred_type(arg)
|
|
253
|
-
args_for_opt << arg
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def visitConstructorDefinition(node, expression)
|
|
259
|
-
args = visit(node.arguments, true)
|
|
260
|
-
arg_types = args.map { |arg| inferred_type(arg) }
|
|
261
|
-
exceptions = [] # node.signature[:throws]
|
|
262
|
-
visibility = :public # node.visibility
|
|
263
|
-
method = @class.build_constructor(visibility, exceptions, *arg_types)
|
|
264
|
-
annotate(method, node.annotations)
|
|
265
|
-
with :current_scope => introduced_scope(node) do
|
|
266
|
-
yield(method, args)
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def visitClassDefinition(class_def, expression)
|
|
271
|
-
log "Compiling class #{class_def.name.identifier}"
|
|
272
|
-
with(:type => inferred_type(class_def),
|
|
273
|
-
:class => inferred_type(class_def).define(@file),
|
|
274
|
-
:static => false) do
|
|
275
|
-
annotate(@class, class_def.annotations)
|
|
276
|
-
visit(class_def.body, false) if class_def.body
|
|
277
|
-
@class.stop
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
def visitArguments(args, expression)
|
|
282
|
-
result = []
|
|
283
|
-
args.required.each {|arg| result << arg}
|
|
284
|
-
args.optional.each {|arg| result << arg}
|
|
285
|
-
result << args.rest if args.rest
|
|
286
|
-
args.required2.each {|arg| result << arg}
|
|
287
|
-
result << args.block if args.block
|
|
288
|
-
result
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
def visitStaticMethodDefinition(mdef, expression)
|
|
292
|
-
visitMethodDefinition(mdef, expression)
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
def visitNodeList(body, expression)
|
|
296
|
-
saved_self = @self_scope
|
|
297
|
-
new_scope = introduced_scope(body)
|
|
298
|
-
if new_scope
|
|
299
|
-
declare_locals(new_scope)
|
|
300
|
-
if new_scope != @self_scope
|
|
301
|
-
if new_scope.self_node && new_scope.self_node != :self
|
|
302
|
-
# FIXME This is a horrible hack!
|
|
303
|
-
# Instead we should eliminate unused self's.
|
|
304
|
-
unless new_scope.self_type.name == 'mirah.impl.Builtin'
|
|
305
|
-
local_assign(
|
|
306
|
-
new_scope, 'self', new_scope.self_type, false, new_scope.self_node)
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
@self_scope = new_scope
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
# all except the last element in a body of code is treated as a statement
|
|
313
|
-
i, last = 0, body.size - 1
|
|
314
|
-
while i < last
|
|
315
|
-
visit(body.get(i), false)
|
|
316
|
-
i += 1
|
|
317
|
-
end
|
|
318
|
-
if last >= 0
|
|
319
|
-
yield body.get(last)
|
|
320
|
-
else
|
|
321
|
-
yield nil
|
|
322
|
-
end
|
|
323
|
-
@self_scope = saved_self
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
def visitClassAppendSelf(node, expression)
|
|
327
|
-
with :static => true, :current_scope => introduced_scope(node) do
|
|
328
|
-
visit(node.body, expression)
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
def visitPackage(node, expression)
|
|
333
|
-
visit(node.body, expression) if node.body
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
def scoped_body(scope, expression)
|
|
337
|
-
body(scope, expression)
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def scoped_local_name(name, scope=nil)
|
|
341
|
-
if scope.nil? || scope == @current_scope
|
|
342
|
-
name
|
|
343
|
-
else
|
|
344
|
-
"#{name}$#{scope.object_id}"
|
|
345
|
-
end
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
def visitImport(node, expression)
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
def visitFixnum(node, expression)
|
|
352
|
-
if expression
|
|
353
|
-
inferred_type(node).literal(method, node.value)
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
def visitCharLiteral(node, expression)
|
|
358
|
-
if expression
|
|
359
|
-
inferred_type(node).literal(method, node.value)
|
|
360
|
-
end
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
alias visitFloat visitFixnum
|
|
364
|
-
|
|
365
|
-
def visitSelf(node, expression)
|
|
366
|
-
if expression
|
|
367
|
-
set_position(node.position)
|
|
368
|
-
scope = get_scope(node)
|
|
369
|
-
if scope.self_node && scope.self_node != :self
|
|
370
|
-
local(scope, 'self', scope.self_type)
|
|
371
|
-
else
|
|
372
|
-
real_self
|
|
373
|
-
end
|
|
374
|
-
end
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
def visitImplicitSelf(node, expression)
|
|
378
|
-
visitSelf(node, expression)
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
def visitUnquote(node, expression)
|
|
382
|
-
body = node.nodes
|
|
383
|
-
i, last = 0, body.size - 1
|
|
384
|
-
while i < last
|
|
385
|
-
visit(body.get(i), false)
|
|
386
|
-
i += 1
|
|
387
|
-
end
|
|
388
|
-
if last >= 0
|
|
389
|
-
visit(body.get(last), expression)
|
|
390
|
-
else
|
|
391
|
-
visitImplicitNil(node, expression)
|
|
392
|
-
end
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
def get_binding(type)
|
|
396
|
-
@bindings[type]
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
def declared_captures(binding=nil)
|
|
400
|
-
@captured_locals[binding || @binding]
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
def with(vars)
|
|
404
|
-
orig_values = {}
|
|
405
|
-
begin
|
|
406
|
-
vars.each do |name, new_value|
|
|
407
|
-
name = "@#{name}"
|
|
408
|
-
orig_values[name] = instance_variable_get name
|
|
409
|
-
instance_variable_set name, new_value
|
|
410
|
-
end
|
|
411
|
-
yield
|
|
412
|
-
ensure
|
|
413
|
-
orig_values.each do |name, value|
|
|
414
|
-
instance_variable_set name, value
|
|
415
|
-
end
|
|
416
|
-
end
|
|
417
|
-
end
|
|
418
|
-
end
|
|
419
|
-
end
|
|
420
|
-
end
|
|
421
|
-
end
|