mirah 0.1.2-java → 0.1.3-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|