mirah 0.0.12-java → 0.1.0-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 +372 -0
- data/README.txt +4 -5
- data/Rakefile +178 -55
- data/examples/appengine/Readme +3 -3
- data/examples/appengine/src/org/mirah/MirahApp.mirah +1 -1
- data/examples/appengine/src/org/mirah/list.dhtml +1 -1
- data/examples/bintrees.mirah +1 -1
- data/examples/edb.mirah +1 -1
- data/examples/fib.mirah +1 -1
- data/examples/interfaces.mirah +1 -1
- data/examples/macros/{string-each-char.mirah → string_each_char.mirah} +4 -5
- data/examples/maven/README.txt +1 -1
- data/examples/maven/src/main/mirah/hello_mirah.mirah +1 -1
- data/examples/plugins/appengine/Rakefile +1 -1
- data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/MetaModel.mirah +1 -1
- data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +1 -1
- data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +1 -1
- data/examples/rosettacode/100-doors.mirah +6 -6
- data/examples/rosettacode/README.txt +3 -3
- data/examples/rosettacode/boolean-values.mirah +1 -1
- data/examples/rosettacode/comments.mirah +1 -1
- data/examples/rosettacode/count-occurrences-of-a-substring.mirah +1 -1
- data/examples/rosettacode/factorial.mirah +1 -1
- data/examples/rosettacode/fibonacci.mirah +1 -1
- data/examples/rosettacode/fizz-buzz.mirah +2 -2
- data/examples/rosettacode/flatten-a-list.mirah +4 -4
- data/examples/rosettacode/guess-the-number.mirah +2 -2
- data/examples/rosettacode/hamming-numbers.mirah +4 -4
- data/examples/rosettacode/is-string-numeric.mirah +22 -22
- data/examples/rosettacode/palindrome.mirah +2 -2
- data/examples/rosettacode/random-numbers.mirah +1 -1
- data/examples/rosettacode/repeat-a-string.mirah +1 -1
- data/examples/rosettacode/reverse-a-string.mirah +1 -1
- data/examples/rosettacode/rot-13.mirah +5 -5
- data/examples/rosettacode/secure-temporary-file.mirah +2 -2
- data/examples/rosettacode/sleep.mirah +1 -1
- data/examples/rosettacode/string-length.mirah +5 -5
- data/examples/swing.mirah +1 -1
- data/examples/test.edb +1 -1
- data/javalib/mirah-bootstrap.jar +0 -0
- data/javalib/mirah-builtins.jar +0 -0
- data/javalib/mirah-parser.jar +0 -0
- data/javalib/mirah-util.jar +0 -0
- data/lib/duby.rb +1 -1
- data/lib/mirah.rb +50 -28
- data/lib/mirah/ast.rb +15 -605
- data/lib/mirah/ast/scope.rb +98 -69
- data/lib/mirah/commands.rb +1 -1
- data/lib/mirah/commands/base.rb +7 -7
- data/lib/mirah/commands/compile.rb +3 -3
- data/lib/mirah/commands/parse.rb +7 -5
- data/lib/mirah/commands/run.rb +12 -19
- data/lib/mirah/compiler.rb +15 -23
- data/lib/mirah/errors.rb +16 -1
- data/lib/mirah/generator.rb +79 -39
- data/lib/mirah/jvm/compiler.rb +1 -19
- data/lib/mirah/jvm/compiler/base.rb +233 -90
- data/lib/mirah/jvm/compiler/jvm_bytecode.rb +675 -363
- data/lib/mirah/jvm/method_lookup.rb +134 -65
- data/lib/mirah/jvm/typer.rb +10 -5
- data/lib/mirah/jvm/types.rb +10 -2
- data/lib/mirah/jvm/types/array_type.rb +10 -12
- data/lib/mirah/{compiler/type.rb → jvm/types/ast_ext.rb} +12 -8
- data/lib/mirah/jvm/types/basic_types.rb +26 -33
- data/lib/mirah/jvm/types/bitescript_ext.rb +1 -1
- data/lib/mirah/jvm/types/block_type.rb +15 -0
- data/lib/mirah/jvm/types/boolean.rb +8 -4
- data/lib/mirah/jvm/types/dynamic_type.rb +12 -13
- data/lib/mirah/jvm/types/enumerable.rb +7 -7
- data/lib/mirah/jvm/types/extensions.rb +11 -6
- data/lib/mirah/jvm/types/factory.rb +624 -94
- data/lib/mirah/jvm/types/floats.rb +21 -15
- data/lib/mirah/jvm/types/generic_type.rb +72 -0
- data/lib/mirah/jvm/types/implicit_nil_type.rb +29 -0
- data/lib/mirah/jvm/types/integers.rb +26 -71
- data/lib/mirah/jvm/types/interface_definition.rb +3 -3
- data/lib/mirah/jvm/types/intrinsics.rb +203 -168
- data/lib/mirah/jvm/types/literals.rb +6 -6
- data/lib/mirah/jvm/types/meta_type.rb +13 -4
- data/lib/mirah/jvm/types/methods.rb +281 -93
- data/lib/mirah/jvm/types/null_type.rb +17 -5
- data/lib/mirah/jvm/types/number.rb +10 -7
- data/lib/mirah/jvm/types/primitive_type.rb +17 -6
- data/lib/mirah/jvm/types/source_mirror.rb +12 -7
- data/lib/mirah/jvm/types/type.rb +107 -23
- data/lib/mirah/jvm/types/type_definition.rb +25 -10
- data/lib/mirah/jvm/types/unreachable_type.rb +1 -1
- data/lib/mirah/jvm/types/void_type.rb +3 -3
- data/lib/mirah/parser.rb +154 -16
- data/lib/mirah/plugin/edb.rb +1 -1
- data/lib/mirah/transform.rb +1 -2
- data/lib/mirah/transform/ast_ext.rb +24 -43
- data/lib/mirah/transform/transformer.rb +29 -224
- data/lib/mirah/typer.rb +2 -16
- data/lib/mirah/util/argument_processor.rb +25 -10
- data/lib/mirah/util/class_loader.rb +1 -1
- data/lib/mirah/util/compilation_state.rb +16 -17
- data/lib/mirah/util/delegate.rb +2 -2
- data/lib/mirah/util/logging.rb +110 -0
- data/lib/mirah/util/process_errors.rb +69 -11
- data/lib/mirah/version.rb +1 -1
- data/test/core/commands_test.rb +6 -24
- data/test/core/env_test.rb +5 -5
- data/{lib/mirah/jvm/source_generator/typer.rb → test/core/generator_test.rb} +9 -9
- data/test/core/typer_test.rb +196 -158
- data/test/core/util/argument_processor_test.rb +10 -10
- data/test/core/util/class_loader_test.rb +6 -5
- data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass.java +7 -0
- data/test/jvm/annotations_test.rb +5 -5
- data/test/jvm/blocks_test.rb +140 -88
- data/test/jvm/bytecode_test_helper.rb +112 -94
- data/test/jvm/cast_test.rb +162 -0
- data/test/jvm/constructors_test.rb +18 -8
- data/test/jvm/enumerable_test.rb +77 -44
- data/test/jvm/example_test.rb +53 -0
- data/test/jvm/factory_test.rb +7 -1
- data/test/jvm/generics_test.rb +57 -0
- data/test/jvm/hash_test.rb +106 -0
- data/test/jvm/import_test.rb +81 -0
- data/test/jvm/interface_test.rb +73 -0
- data/test/jvm/java_typer_test.rb +92 -66
- data/{lib/mirah/typer/base.rb → test/jvm/jvm_commands_test.rb} +6 -10
- data/test/jvm/jvm_compiler_test.rb +170 -604
- data/test/jvm/list_extensions_test.rb +23 -0
- data/test/jvm/macros_test.rb +197 -32
- data/test/jvm/main_method_test.rb +4 -4
- data/test/jvm/numeric_extensions_test.rb +13 -0
- data/test/jvm/rescue_test.rb +73 -16
- data/test/jvm/varargs_test.rb +65 -0
- data/test/test_helper.rb +1 -2
- metadata +234 -251
- data/examples/SortClosure$__xform_tmp_1.class +0 -0
- data/examples/SortClosure$__xform_tmp_2.class +0 -0
- data/examples/SortClosure.class +0 -0
- data/examples/macros/StringEachChar$Extension1.class +0 -0
- data/lib/mirah/ast/call.rb +0 -345
- data/lib/mirah/ast/class.rb +0 -359
- data/lib/mirah/ast/flow.rb +0 -381
- data/lib/mirah/ast/intrinsics.rb +0 -563
- data/lib/mirah/ast/literal.rb +0 -178
- data/lib/mirah/ast/local.rb +0 -112
- data/lib/mirah/ast/method.rb +0 -408
- data/lib/mirah/ast/structure.rb +0 -387
- data/lib/mirah/ast/type.rb +0 -146
- data/lib/mirah/commands/base.rb~ +0 -57
- data/lib/mirah/compiler/call.rb +0 -45
- data/lib/mirah/compiler/class.rb +0 -81
- data/lib/mirah/compiler/flow.rb +0 -109
- data/lib/mirah/compiler/literal.rb +0 -130
- data/lib/mirah/compiler/local.rb +0 -59
- data/lib/mirah/compiler/method.rb +0 -44
- data/lib/mirah/compiler/structure.rb +0 -65
- data/lib/mirah/jvm/compiler/java_source.rb +0 -787
- data/lib/mirah/jvm/method_lookup.rb~ +0 -247
- data/lib/mirah/jvm/source_generator/builder.rb +0 -468
- data/lib/mirah/jvm/source_generator/loops.rb +0 -131
- data/lib/mirah/jvm/source_generator/precompile.rb +0 -210
- data/lib/mirah/plugin/gwt.rb +0 -189
- data/lib/mirah/plugin/java.rb +0 -70
- data/lib/mirah/transform/error.rb +0 -13
- data/lib/mirah/transform/helper.rb +0 -765
- data/lib/mirah/typer/simple.rb +0 -384
- data/lib/mirah/version.rb~ +0 -18
- data/test/core/ast_test.rb +0 -382
- data/test/core/compilation_test.rb +0 -130
- data/test/core/macros_test.rb +0 -61
- data/test/jvm/javac_test_helper.rb +0 -89
- data/test/jvm/jvm_compiler_test.rb~ +0 -2181
- data/test/plugins/gwt_test.rb +0 -69
|
@@ -14,36 +14,29 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
module Mirah::JVM::Types
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Int => [Int, Long, Float, Double],
|
|
44
|
-
Long => [Long, Float, Double],
|
|
45
|
-
Float => [Float, Double],
|
|
46
|
-
Double => [Double]
|
|
47
|
-
}
|
|
48
|
-
TYPE_ORDERING = [Byte, Short, Int, Long, Float, Double]
|
|
49
|
-
end
|
|
17
|
+
class TypeFactory
|
|
18
|
+
def create_basic_types
|
|
19
|
+
@known_types.update(
|
|
20
|
+
'boolean' => BooleanType.new(self, 'boolean', java.lang.Boolean),
|
|
21
|
+
'byte' => IntegerType.new(self, 'byte', java.lang.Byte),
|
|
22
|
+
'char' => IntegerType.new(self, 'char', java.lang.Character),
|
|
23
|
+
'short' => IntegerType.new(self, 'short', java.lang.Short),
|
|
24
|
+
'int' => IntegerType.new(self, 'int', java.lang.Integer),
|
|
25
|
+
'long' => LongType.new(self, 'long', java.lang.Long),
|
|
26
|
+
'float' => FloatType.new(self, 'float', java.lang.Float),
|
|
27
|
+
'double' => DoubleType.new(self, 'double', java.lang.Double)
|
|
28
|
+
)
|
|
29
|
+
@known_types['fixnum'] = @known_types['int']
|
|
30
|
+
@known_types['Object'] = type(nil, 'java.lang.Object')
|
|
31
|
+
@known_types['string'] = @known_types['String'] = @known_types['java.lang.String'] =
|
|
32
|
+
StringType.new(self, get_mirror('java.lang.String'))
|
|
33
|
+
type(nil, 'java.lang.Class')
|
|
34
|
+
@known_types['Iterable'] = @known_types['java.lang.Iterable'] =
|
|
35
|
+
IterableType.new(self, get_mirror('java.lang.Iterable'))
|
|
36
|
+
@known_types['void'] = VoidType.new(self)
|
|
37
|
+
@known_types['null'] = NullType.new(self)
|
|
38
|
+
@known_types['implicit_nil'] = ImplicitNilType.new(self)
|
|
39
|
+
@known_types['dynamic'] = DynamicType.new(self)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -28,16 +28,20 @@ module Mirah::JVM::Types
|
|
|
28
28
|
builder.invokestatic box_type, "valueOf", [box_type, self]
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
def box_type
|
|
32
|
+
@type_system.type(nil, 'java.lang.Boolean')
|
|
33
|
+
end
|
|
34
|
+
|
|
31
35
|
def add_intrinsics
|
|
32
36
|
args = [math_type]
|
|
33
37
|
add_method('==', args, ComparisonIntrinsic.new(self, '==', :eq, args))
|
|
34
38
|
add_method('!=', args, ComparisonIntrinsic.new(self, '!=', :ne, args))
|
|
35
39
|
end
|
|
36
|
-
|
|
40
|
+
|
|
37
41
|
def math_type
|
|
38
|
-
|
|
42
|
+
@type_system.type(nil, 'boolean')
|
|
39
43
|
end
|
|
40
|
-
|
|
44
|
+
|
|
41
45
|
# same as NumberType's
|
|
42
46
|
def compile_boolean_operator(compiler, op, negated, call, label)
|
|
43
47
|
# Promote the target or the argument if necessary
|
|
@@ -62,4 +66,4 @@ module Mirah::JVM::Types
|
|
|
62
66
|
builder.send "if_icmp#{op}", label
|
|
63
67
|
end
|
|
64
68
|
end
|
|
65
|
-
end
|
|
69
|
+
end
|
|
@@ -2,11 +2,10 @@ module Mirah
|
|
|
2
2
|
module JVM
|
|
3
3
|
module Types
|
|
4
4
|
class DynamicType < Type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def initialize
|
|
5
|
+
def initialize(types)
|
|
8
6
|
# For naming, bytecode purposes, we are an Object
|
|
9
|
-
|
|
7
|
+
super(types, "java.lang.Object")
|
|
8
|
+
@object_type ||= types.type(nil, 'java.lang.Object')
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
def basic_type
|
|
@@ -14,17 +13,17 @@ module Mirah
|
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def is_parent(other)
|
|
17
|
-
|
|
16
|
+
@object_type.assignable_from?(other)
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
def assignable_from?(other)
|
|
21
|
-
|
|
20
|
+
@object_type.assignable_from?(other)
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
def jvm_type
|
|
25
24
|
java.lang.Object
|
|
26
25
|
end
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
def full_name
|
|
29
28
|
"dynamic"
|
|
30
29
|
end
|
|
@@ -32,15 +31,15 @@ module Mirah
|
|
|
32
31
|
def dynamic?
|
|
33
32
|
true
|
|
34
33
|
end
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
def superclass
|
|
37
|
-
|
|
36
|
+
@object_type
|
|
38
37
|
end
|
|
39
|
-
|
|
40
|
-
def interfaces
|
|
41
|
-
|
|
38
|
+
|
|
39
|
+
def interfaces(include_parent=true)
|
|
40
|
+
@object_type.interfaces
|
|
42
41
|
end
|
|
43
42
|
end
|
|
44
43
|
end
|
|
45
44
|
end
|
|
46
|
-
end
|
|
45
|
+
end
|
|
@@ -20,7 +20,7 @@ module Mirah::JVM::Types
|
|
|
20
20
|
code = intrinsics['each'][arg_types].return_type
|
|
21
21
|
code.inline(transformer, call)
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
def add_enumerable_macros
|
|
25
25
|
all_proc = proc do |transformer, call|
|
|
26
26
|
if !call.block
|
|
@@ -31,15 +31,15 @@ module Mirah::JVM::Types
|
|
|
31
31
|
# block and attach it to the real call.
|
|
32
32
|
call.block = transformer.eval("foo {|#{var}| #{var}}").block
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
# Now that we've got a block we can transform it into a Loop.
|
|
36
36
|
forloop = expand_each(transformer, call)
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
# Start adding stuff to the loop.
|
|
39
39
|
# At the beginning of the loop we create a temp initialized to true
|
|
40
40
|
all = transformer.tmp
|
|
41
41
|
forloop.init << transformer.eval("#{all} = true")
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
# Now we want to wrap the body of the loop. Start off by using
|
|
44
44
|
# foo as a placeholder.
|
|
45
45
|
body = transformer.eval(
|
|
@@ -48,7 +48,7 @@ module Mirah::JVM::Types
|
|
|
48
48
|
body.condition.predicate = call.block.body
|
|
49
49
|
# And finally patch the new body back into the forloop.
|
|
50
50
|
forloop.body = call.block.body.parent = body
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# Loops don't have a return value, so we need somewhere to
|
|
53
53
|
# put the result.
|
|
54
54
|
result = Mirah::AST::Body.new(call.parent, call.position)
|
|
@@ -69,7 +69,7 @@ module Mirah::JVM::Types
|
|
|
69
69
|
"if foo;#{any} = true;break;end", '', forloop)
|
|
70
70
|
body.condition.predicate = call.block.body
|
|
71
71
|
forloop.body = call.block.body.parent = body
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
result = Mirah::AST::Body.new(call.parent, call.position)
|
|
74
74
|
result << forloop << transformer.eval("#{any}", '', nil, any)
|
|
75
75
|
end
|
|
@@ -77,4 +77,4 @@ module Mirah::JVM::Types
|
|
|
77
77
|
add_macro('any?', Mirah::AST.block_type, &any_proc)
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
|
-
end
|
|
80
|
+
end
|
|
@@ -62,22 +62,27 @@ module Mirah::JVM::Types
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def declared_instance_methods(name=nil)
|
|
65
|
-
__combine_methods(__getobj__.declared_instance_methods)
|
|
65
|
+
__combine_methods(__getobj__.declared_instance_methods, name)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def declared_class_methods(name=nil)
|
|
69
|
-
__combine_methods(__getobj__.declared_class_methods)
|
|
69
|
+
__combine_methods(__getobj__.declared_class_methods, name)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
def
|
|
72
|
+
def find_callable_methods(name, include_interfaces=false)
|
|
73
|
+
__combine_methods(__getobj__.find_callable_methods(name, include_interfaces), name)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def __combine_methods(basic_methods, name)
|
|
73
77
|
methods = {}
|
|
74
78
|
basic_methods.each do |method|
|
|
75
|
-
key = [method.name, method.
|
|
79
|
+
key = [method.name, method.argument_types, method.return_type]
|
|
76
80
|
methods[key] = method
|
|
77
81
|
end
|
|
78
82
|
@static_includes.each do |type|
|
|
79
83
|
type.declared_class_methods.each do |method|
|
|
80
|
-
|
|
84
|
+
next if name && method.name != name
|
|
85
|
+
key = [method.name, method.argument_types, method.return_type]
|
|
81
86
|
methods[key] ||= method
|
|
82
87
|
end
|
|
83
88
|
end
|
|
@@ -98,4 +103,4 @@ module Mirah::JVM::Types
|
|
|
98
103
|
ExtendedType.new(self).include(type)
|
|
99
104
|
end
|
|
100
105
|
end
|
|
101
|
-
end
|
|
106
|
+
end
|
|
@@ -16,32 +16,35 @@
|
|
|
16
16
|
require 'jruby'
|
|
17
17
|
require 'mirah/jvm/types/source_mirror'
|
|
18
18
|
module Mirah::JVM::Types
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
19
|
+
java_import 'org.mirah.typer.simple.SimpleTypes'
|
|
20
|
+
class TypeFactory < SimpleTypes
|
|
21
|
+
java_import 'org.mirah.typer.AssignableTypeFuture'
|
|
22
|
+
java_import 'org.mirah.typer.PickFirst'
|
|
23
|
+
java_import 'org.mirah.typer.BaseTypeFuture'
|
|
24
|
+
#java_import 'org.mirah.typer.BlockType'
|
|
25
|
+
java_import 'org.mirah.typer.ErrorType'
|
|
26
|
+
java_import 'org.mirah.typer.GenericTypeFuture'
|
|
27
|
+
java_import 'org.mirah.typer.MethodFuture'
|
|
28
|
+
java_import 'org.mirah.typer.MethodType'
|
|
29
|
+
java_import 'org.mirah.typer.SimpleFuture'
|
|
30
|
+
java_import 'org.mirah.typer.TypeFuture'
|
|
31
|
+
java_import 'org.mirah.typer.TypeSystem'
|
|
32
|
+
java_import 'org.mirah.typer.NarrowingTypeFuture'
|
|
33
|
+
java_import 'mirah.lang.ast.ClassDefinition'
|
|
34
|
+
java_import 'mirah.lang.ast.InterfaceDeclaration'
|
|
35
|
+
java_import 'mirah.lang.ast.Script'
|
|
36
|
+
java_import 'mirah.lang.ast.SimpleString'
|
|
37
|
+
include TypeSystem
|
|
38
|
+
include Mirah::Logging::Logged
|
|
39
|
+
|
|
40
|
+
begin
|
|
41
|
+
java_import 'org.mirah.builtins.Builtins'
|
|
42
|
+
rescue NameError
|
|
43
|
+
# We might be trying to compile mirah-builtins.jar, so just continue.
|
|
44
|
+
Builtins = nil
|
|
45
|
+
end
|
|
44
46
|
|
|
47
|
+
java_import 'java.net.URLClassLoader'
|
|
45
48
|
attr_accessor :package
|
|
46
49
|
attr_reader :known_types
|
|
47
50
|
|
|
@@ -53,10 +56,13 @@ module Mirah::JVM::Types
|
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
def initialize
|
|
59
|
+
super(":unused")
|
|
56
60
|
@known_types = ParanoidHash.new
|
|
57
|
-
@
|
|
61
|
+
@anonymous_classes = Hash.new {|h, k| h[k] = 0}
|
|
58
62
|
@declarations = []
|
|
59
63
|
@mirrors = {}
|
|
64
|
+
@futures = {}
|
|
65
|
+
create_basic_types
|
|
60
66
|
end
|
|
61
67
|
|
|
62
68
|
def initialize_copy(other)
|
|
@@ -65,6 +71,465 @@ module Mirah::JVM::Types
|
|
|
65
71
|
value.basic_type.kind_of?(Mirah::JVM::Types::TypeDefinition)
|
|
66
72
|
end
|
|
67
73
|
@declarations = []
|
|
74
|
+
@futures = {}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def maybe_initialize_builtins(compiler)
|
|
78
|
+
if Builtins
|
|
79
|
+
begin
|
|
80
|
+
Builtins.initialize_builtins(compiler)
|
|
81
|
+
rescue NativeException => ex
|
|
82
|
+
error("Error initializing builtins", ex.cause)
|
|
83
|
+
rescue => ex
|
|
84
|
+
error("Error initializing builtins: #{ex.message}\n\t#{ex.backtrace.join("\n\t")}")
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
warning "Unable to initialize builtins"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def wrap(resolved_type)
|
|
92
|
+
future = BaseTypeFuture.new(nil)
|
|
93
|
+
future.resolved(resolved_type) if resolved_type
|
|
94
|
+
future
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def cache_and_wrap(resolved_type)
|
|
98
|
+
@futures[resolved_type.name] ||= wrap(resolved_type)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def cache_and_wrap_type(name)
|
|
102
|
+
@futures[name] ||= begin
|
|
103
|
+
type = type(nil, name)
|
|
104
|
+
wrapper = wrap(type)
|
|
105
|
+
wrapper.resolved(ErrorType.new([["Cannot find class #{name}"]])) if type.nil?
|
|
106
|
+
wrapper
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# TypeSystem methods
|
|
111
|
+
def addDefaultImports(scope)
|
|
112
|
+
scope.import('java.lang.*', '*')
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def getNullType; cache_and_wrap_type('null') end
|
|
116
|
+
def getImplicitNilType; cache_and_wrap_type('implicit_nil') end
|
|
117
|
+
def getVoidType; cache_and_wrap_type('void') end
|
|
118
|
+
def getBaseExceptionType; cache_and_wrap_type('java.lang.Throwable') end
|
|
119
|
+
def getDefaultExceptionType; cache_and_wrap_type('java.lang.Exception') end
|
|
120
|
+
def getHashType; cache_and_wrap_type('java.util.HashMap') end
|
|
121
|
+
def getRegexType; cache_and_wrap_type('java.util.regex.Pattern') end
|
|
122
|
+
def getStringType; cache_and_wrap_type('java.lang.String') end
|
|
123
|
+
def getBooleanType; cache_and_wrap_type('boolean') end
|
|
124
|
+
|
|
125
|
+
def getFixnumType(value)
|
|
126
|
+
long = java.lang.Long.new(value)
|
|
127
|
+
if long.int_value != value
|
|
128
|
+
cache_and_wrap_type('long')
|
|
129
|
+
elsif long.short_value != value
|
|
130
|
+
cache_and_wrap_type('int')
|
|
131
|
+
elsif long.byte_value != value
|
|
132
|
+
wide = type(nil, 'int')
|
|
133
|
+
narrow = type(nil, 'short')
|
|
134
|
+
NarrowingTypeFuture.new(nil, wide, narrow)
|
|
135
|
+
else
|
|
136
|
+
wide = type(nil, 'int')
|
|
137
|
+
narrow = type(nil, 'byte')
|
|
138
|
+
NarrowingTypeFuture.new(nil, wide, narrow)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def getCharType(value) cache_and_wrap_type('char') end
|
|
143
|
+
|
|
144
|
+
def getFloatType(value)
|
|
145
|
+
d = java.lang.Double.new(value)
|
|
146
|
+
if d.float_value != value
|
|
147
|
+
cache_and_wrap_type('double')
|
|
148
|
+
else
|
|
149
|
+
wide = type(nil, 'double')
|
|
150
|
+
narrow = type(nil, 'float')
|
|
151
|
+
NarrowingTypeFuture.new(nil, wide, narrow)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def getMetaType(type)
|
|
156
|
+
if type.kind_of?(Type)
|
|
157
|
+
type.meta
|
|
158
|
+
else
|
|
159
|
+
future = BaseTypeFuture.new(nil)
|
|
160
|
+
type.on_update {|_, resolved| future.resolved(resolved.meta)}
|
|
161
|
+
future.position_set(type.position)
|
|
162
|
+
future.error_message_set(type.error_message)
|
|
163
|
+
future
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def getSuperClass(future)
|
|
168
|
+
superclass = BaseTypeFuture.new(nil)
|
|
169
|
+
future.on_update do |_, type|
|
|
170
|
+
superclass.resolved(type.superclass)
|
|
171
|
+
end
|
|
172
|
+
superclass
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def getArrayType(type)
|
|
176
|
+
if type.kind_of?(Type)
|
|
177
|
+
type.array_type
|
|
178
|
+
else
|
|
179
|
+
future = BaseTypeFuture.new(nil)
|
|
180
|
+
type.on_update {|_, resolved| future.resolved(resolved.array_type)}
|
|
181
|
+
future
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def box(type)
|
|
186
|
+
boxed = BaseTypeFuture.new(nil)
|
|
187
|
+
type.on_update do |_, resolved|
|
|
188
|
+
if resolved.isError || !resolved.primitive?
|
|
189
|
+
boxed.resolved(resolved)
|
|
190
|
+
else
|
|
191
|
+
boxed.resolved(resolved.box_type)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
boxed
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def getArrayLiteralType(type, position)
|
|
198
|
+
result = Mirah::JVM::Types::GenericType.new(type(nil, 'java.util.List')) # Upgrade to a generic type.
|
|
199
|
+
variable = result.type_parameters[0]
|
|
200
|
+
result.type_parameter_map[variable.name] = _build_generic_type_future(variable.bounds, position)
|
|
201
|
+
result.type_parameter_map[variable.name].assign(box(type), position)
|
|
202
|
+
wrap(result)
|
|
203
|
+
rescue => ex
|
|
204
|
+
Mirah.print_error("Error inferring generics: #{ex.message}", position)
|
|
205
|
+
log("Error inferring generics: #{ex.message}\n#{ex.backtrace.join("\n")}")
|
|
206
|
+
cache_and_wrap_type('java.util.List')
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def getHashLiteralType(key_type, value_type, position)
|
|
210
|
+
result = Mirah::JVM::Types::GenericType.new(type(nil, 'java.util.HashMap')) # Upgrade to a generic type.
|
|
211
|
+
generic_key, generic_value = result.type_parameters
|
|
212
|
+
for variable, type in [[generic_key, key_type], [generic_value, value_type]]
|
|
213
|
+
result.type_parameter_map[variable.name] = _build_generic_type_future(variable.bounds, position)
|
|
214
|
+
result.type_parameter_map[variable.name].assign(box(type), position)
|
|
215
|
+
end
|
|
216
|
+
wrap(result)
|
|
217
|
+
rescue => ex
|
|
218
|
+
Mirah.print_error("Error inferring generics: #{ex.message}", position)
|
|
219
|
+
log("Error inferring generics: #{ex.message}\n#{ex.backtrace.join("\n")}")
|
|
220
|
+
cache_and_wrap_type('java.util.HashMap')
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def get(scope, typeref)
|
|
224
|
+
basic_type = if scope.nil?
|
|
225
|
+
cache_and_wrap_type(typeref.name)
|
|
226
|
+
else
|
|
227
|
+
imports = scope.imports
|
|
228
|
+
name = typeref.name
|
|
229
|
+
name = imports[name] while imports.include?(name)
|
|
230
|
+
types = [ cache_and_wrap_type(name), nil ]
|
|
231
|
+
packages = []
|
|
232
|
+
packages << scope.package if scope.package && scope.package != ''
|
|
233
|
+
(packages + scope.search_packages).each do |package|
|
|
234
|
+
types << cache_and_wrap_type("#{package}.#{name}")
|
|
235
|
+
types << nil
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
future = PickFirst.new(types, nil)
|
|
239
|
+
future.position_set(typeref.position)
|
|
240
|
+
future.error_message_set("Cannot find class #{typeref.name}")
|
|
241
|
+
future
|
|
242
|
+
end
|
|
243
|
+
if typeref.isArray
|
|
244
|
+
getArrayType(basic_type)
|
|
245
|
+
elsif typeref.isStatic
|
|
246
|
+
getMetaType(basic_type)
|
|
247
|
+
else
|
|
248
|
+
basic_type
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def getLocalType(scope, name, position)
|
|
253
|
+
scope.local_type(name, position)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def getMethodType(call)
|
|
257
|
+
target = call.resolved_target
|
|
258
|
+
argTypes = call.resolved_parameters
|
|
259
|
+
macro_types = call.parameter_nodes.map do |node|
|
|
260
|
+
get_type(node.java_class.name)
|
|
261
|
+
end if call.parameter_nodes
|
|
262
|
+
_find_method_type(call.scope, target, call.name, argTypes, macro_types, call.position)
|
|
263
|
+
rescue => ex
|
|
264
|
+
Mirah.print_error("Error getting method type #{target.name}.#{call.name}: #{ex.message}", call.position)
|
|
265
|
+
puts ex.backtrace.join("\n\t")
|
|
266
|
+
ErrorType.new([["Internal error: #{ex}", call.position]])
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def _find_method_type(scope, target, name, argTypes, macroTypes, position)
|
|
270
|
+
if target.respond_to?(:isError) && target.isError
|
|
271
|
+
return target
|
|
272
|
+
end
|
|
273
|
+
type = BaseTypeFuture.new(nil)
|
|
274
|
+
target.find_method2(target, name, argTypes, macroTypes, target.meta?, scope) do |method|
|
|
275
|
+
if method.nil?
|
|
276
|
+
unless argTypes.any?{|t| t && t.isError && (type.resolved(t); true)}
|
|
277
|
+
type.resolved(ErrorType.new([
|
|
278
|
+
["Cannot find %s method %s(%s) on %s" %
|
|
279
|
+
[ target.meta? ? "static" : "instance",
|
|
280
|
+
name,
|
|
281
|
+
argTypes.map{|t| t ? t.full_name : "?"}.join(', '),
|
|
282
|
+
target.full_name], position]]))
|
|
283
|
+
end
|
|
284
|
+
elsif method.kind_of?(Exception)
|
|
285
|
+
type.resolved(ErrorType.new([[method.message, position]]))
|
|
286
|
+
else
|
|
287
|
+
result = method.return_type
|
|
288
|
+
|
|
289
|
+
# Handle generics.
|
|
290
|
+
begin
|
|
291
|
+
if name == 'new' and target.type_parameters
|
|
292
|
+
result = Mirah::JVM::Types::GenericType.new(result) # Upgrade to a generic type.
|
|
293
|
+
target.type_parameters.each do |var|
|
|
294
|
+
result.type_parameter_map.put(var.name, _build_generic_type_future(var.bounds, position))
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
genericParameterTypes = method.member.generic_parameter_types
|
|
298
|
+
if genericParameterTypes
|
|
299
|
+
genericParameterTypes.each_index do |i|
|
|
300
|
+
_handle_nested_generic_parameter(genericParameterTypes[i], argTypes[i], result.type_parameter_map, position)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
elsif target.generic? && method.respond_to?(:member)
|
|
304
|
+
genericParameterTypes = method.member.generic_parameter_types
|
|
305
|
+
if genericParameterTypes
|
|
306
|
+
genericParameterTypes.each_index do |i|
|
|
307
|
+
_handle_nested_generic_parameter(genericParameterTypes[i], argTypes[i], target.type_parameter_map, position)
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
result = _handle_nested_generic_return(result, method.member.generic_return_type, target.type_parameter_map, position)
|
|
312
|
+
result.resolve if result.respond_to?(:resolve)
|
|
313
|
+
end
|
|
314
|
+
rescue => ex
|
|
315
|
+
Mirah.print_error("Error inferring generics: #{ex.message}", position)
|
|
316
|
+
log("Error inferring generics: #{ex.message}\n#{ex.backtrace.join("\n")}")
|
|
317
|
+
result = method.return_type
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
if result.kind_of?(TypeFuture)
|
|
321
|
+
if result.isResolved
|
|
322
|
+
type.resolved(result.resolve)
|
|
323
|
+
else
|
|
324
|
+
result.onUpdate {|x, resolved| type.resolved(resolved) }
|
|
325
|
+
end
|
|
326
|
+
else
|
|
327
|
+
type.resolved(result)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# TODO(shepheb): This is modifying the argTypes of _find_method_type, and it shouldn't be.
|
|
331
|
+
# Moved to the bottom so the generics code above can access the original argTypes that were passed to _find_method_type.
|
|
332
|
+
argTypes = method.argument_types
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
argTypes = argTypes.map do |t|
|
|
336
|
+
if t.nil?
|
|
337
|
+
t
|
|
338
|
+
elsif t.isBlock
|
|
339
|
+
type.position_set(position) if (position && type.position.nil?)
|
|
340
|
+
# This should only happen if type is an error.
|
|
341
|
+
type.resolve
|
|
342
|
+
else
|
|
343
|
+
t
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
return_type = AssignableTypeFuture.new(nil)
|
|
347
|
+
return_type.assign(type, position)
|
|
348
|
+
MethodFuture.new(name, argTypes, return_type, false, position)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def _build_generic_type_future(bounds, position)
|
|
352
|
+
typeName = "java.lang.Object"
|
|
353
|
+
if bounds.size > 1
|
|
354
|
+
raise ArgumentError, "Multiple bounds on type variables are not supported."
|
|
355
|
+
elsif bounds.size == 1
|
|
356
|
+
typeName = bounds[0].raw_type.getClassName
|
|
357
|
+
end
|
|
358
|
+
GenericTypeFuture.new(position, type(nil, typeName))
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def _handle_nested_generic_parameter(expectedType, providedType, type_parameter_map, position)
|
|
362
|
+
if expectedType.kind_of?(BiteScript::ASM::TypeVariable)
|
|
363
|
+
gtf = type_parameter_map.get(expectedType.name)
|
|
364
|
+
gtf.assign(SimpleFuture.new(providedType), position)
|
|
365
|
+
elsif expectedType.kind_of?(BiteScript::ASM::Wildcard) && providedType.kind_of?(TypeFuture)
|
|
366
|
+
# TODO(shepheb): Handle bounds here.
|
|
367
|
+
gtf = type_parameter_map.get(expectedType.upper_bound.name)
|
|
368
|
+
gtf.assign(providedType, position)
|
|
369
|
+
elsif expectedType.kind_of?(BiteScript::ASM::ParameterizedType)
|
|
370
|
+
# We can assume assignable_from? here, or this method would not have been called.
|
|
371
|
+
expectedParameters = expectedType.type_arguments
|
|
372
|
+
# Look up the values of the provided type's parameters.
|
|
373
|
+
providedParameters = providedType.type_parameters.map do |var|
|
|
374
|
+
if providedType.generic?
|
|
375
|
+
providedType.type_parameter_map.get(var.name)
|
|
376
|
+
else
|
|
377
|
+
type_parameter_map.get(var.name)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
if expectedParameters && providedParameters && expectedParameters.size == providedParameters.size
|
|
382
|
+
expectedParameters.each_index do |i|
|
|
383
|
+
_handle_nested_generic_parameter(expectedParameters[i], providedParameters[i], type_parameter_map, position)
|
|
384
|
+
end
|
|
385
|
+
else
|
|
386
|
+
raise ArgumentError, "Type parameter mismatch: Expected #{expectedParameters}, found #{providedParameters}."
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# TODO(shepheb): Handles only one level of nesting, it should handle arbitrary depth by recursion.
|
|
392
|
+
def _handle_nested_generic_return(returnType, genericReturnType, type_parameter_map, position)
|
|
393
|
+
if genericReturnType.kind_of?(BiteScript::ASM::TypeVariable)
|
|
394
|
+
type_parameter_map.get(genericReturnType.name)
|
|
395
|
+
elsif genericReturnType.kind_of?(BiteScript::ASM::ParameterizedType)
|
|
396
|
+
returnType = GenericType.new(returnType)
|
|
397
|
+
expectedTypeParameters = returnType.jvm_type.type_parameters
|
|
398
|
+
providedTypeParameters = genericReturnType.type_arguments
|
|
399
|
+
if expectedTypeParameters && providedTypeParameters && expectedTypeParameters.size == providedTypeParameters.size
|
|
400
|
+
expectedTypeParameters.each_index do |i|
|
|
401
|
+
returnType.type_parameter_map.put(expectedTypeParameters[i].name, type_parameter_map.get(providedTypeParameters[i].name))
|
|
402
|
+
end
|
|
403
|
+
else
|
|
404
|
+
raise ArgumentError, "Type parameter mismatch: Expected #{expectedTypeParameters}, found #{providedTypeParameters}"
|
|
405
|
+
end
|
|
406
|
+
returnType
|
|
407
|
+
else
|
|
408
|
+
returnType
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def getMethodDefType(target, name, argTypes, returnType, position)
|
|
413
|
+
if target.nil?
|
|
414
|
+
return ErrorType.new([["No target", position]])
|
|
415
|
+
end
|
|
416
|
+
unless argTypes.all? {|a| a.hasDeclaration}
|
|
417
|
+
infer_override_args(target, name, argTypes)
|
|
418
|
+
end
|
|
419
|
+
if returnType.nil?
|
|
420
|
+
returnType = infer_override_return_type(target, name, argTypes)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
args = argTypes.map {|a| a.resolve}
|
|
424
|
+
target = target.resolve
|
|
425
|
+
type = _find_method_type(nil, target, name, args, nil, position)
|
|
426
|
+
type.onUpdate do |m, resolved|
|
|
427
|
+
_declare_method(target, name, args, type)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
args.each_with_index do |arg, i|
|
|
431
|
+
if arg.isError
|
|
432
|
+
argTypes[i].onUpdate do |x, resolved|
|
|
433
|
+
args[i] = resolved
|
|
434
|
+
_declare_method(target, name, args, type)
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
if type.kind_of?(ErrorType)
|
|
440
|
+
puts "Got error type for method #{name} on #{target.resolve} (#{target.resolve.class})"
|
|
441
|
+
position = type.position rescue nil
|
|
442
|
+
return_type = AssignableTypeFuture.new(position)
|
|
443
|
+
return_type.declare(type, position)
|
|
444
|
+
type = MethodFuture.new(name, args, return_type, false, position)
|
|
445
|
+
elsif returnType
|
|
446
|
+
type.returnType.declare(returnType, position)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
type.to_java(MethodFuture)
|
|
450
|
+
rescue => ex
|
|
451
|
+
target_name = target.respond_to?(:name) ? target.name : target.resolve.name
|
|
452
|
+
error("Error getting method def type #{target_name}.#{name}: #{ex.message}\n#{ex.backtrace.join("\n\t")}")
|
|
453
|
+
return_type = AssignableTypeFuture.new(nil)
|
|
454
|
+
return_type.declare(ErrorType.new([["Internal error: #{ex}"]]), nil)
|
|
455
|
+
MethodFuture.new(name, [], return_type, false, nil)
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
def _declare_method(target, name, args, type)
|
|
459
|
+
return if args.any? {|a| a.isError }
|
|
460
|
+
return unless type.kind_of?(MethodFuture) && type.returnType.isResolved
|
|
461
|
+
resolved = type.returnType.resolve
|
|
462
|
+
resolved = resolved.returnType if resolved.respond_to?(:returnType)
|
|
463
|
+
log "Learned {0} method {1}.{2}({3}) = {4}", [
|
|
464
|
+
target.meta? ? "static" : "instance",
|
|
465
|
+
target.full_name,
|
|
466
|
+
name,
|
|
467
|
+
args.map{|a| a.full_name}.join(', '),
|
|
468
|
+
resolved.full_name].to_java
|
|
469
|
+
rewritten_name = name.sub(/=$/, '_set')
|
|
470
|
+
if target.meta?
|
|
471
|
+
target.unmeta.declare_static_method(rewritten_name, args, resolved, [])
|
|
472
|
+
else
|
|
473
|
+
target.declare_method(rewritten_name, args, resolved, [])
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def getMainType(scope, script)
|
|
478
|
+
filename = File.basename(script.position.source.name || 'DashE')
|
|
479
|
+
classname = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(filename)
|
|
480
|
+
getMetaType(cache_and_wrap(declare_type(scope, classname)))
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
def defineType(scope, node, name, superclass, interfaces)
|
|
484
|
+
# TODO what if superclass or interfaces change later?
|
|
485
|
+
log("Defining type #{name} < #{superclass.resolve.name if superclass} #{interfaces.map{|i|i.resolve.name}.inspect}")
|
|
486
|
+
type = define_type(scope, node)
|
|
487
|
+
future = @futures[type.name]
|
|
488
|
+
if future
|
|
489
|
+
future.resolved(type)
|
|
490
|
+
future
|
|
491
|
+
else
|
|
492
|
+
cache_and_wrap(type)
|
|
493
|
+
end
|
|
494
|
+
rescue => ex
|
|
495
|
+
Mirah.print_error("Error defining type #{name}: #{ex.message}", node.position)
|
|
496
|
+
puts ex.backtrace.join("\n\t")
|
|
497
|
+
ErrorType.new([["Internal error: #{ex}", node.position]])
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def addMacro(klass, macro)
|
|
501
|
+
klass.unmeta.add_compiled_macro(macro)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def extendClass(classname, extensions)
|
|
505
|
+
get_type(classname).load_extensions(extensions)
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def infer_override_args(target, name, arg_types)
|
|
509
|
+
# TODO What if the method we're overriding hasn't been inferred yet?
|
|
510
|
+
log("Infering argument types for #{name}")
|
|
511
|
+
by_name = target.resolve.find_callable_methods(name, true)
|
|
512
|
+
by_name_and_arity = by_name.select {|m| m.argument_types.size == arg_types.size}
|
|
513
|
+
filtered_args = Set.new(by_name_and_arity.map {|m| m.argument_types})
|
|
514
|
+
if filtered_args.size == 1
|
|
515
|
+
arg_types.zip(filtered_args.first).each do |arg, super_arg|
|
|
516
|
+
arg.declare(cache_and_wrap(super_arg), arg.position)
|
|
517
|
+
end
|
|
518
|
+
else
|
|
519
|
+
log("Found method types:")
|
|
520
|
+
filtered_args.each {|args| log(" #{args.map{|a|a.full_name}.inspect}")}
|
|
521
|
+
arg_types.each {|arg| arg.declare(ErrorType.new([["Missing declaration"]]), nil)}
|
|
522
|
+
# TODO else give a more useful error?
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
def infer_override_return_type(target, name, arg_types)
|
|
527
|
+
by_name = target.resolve.find_callable_methods(name, true)
|
|
528
|
+
by_name_and_arity = {}
|
|
529
|
+
by_name.each {|m| by_name_and_arity[m.argument_types] = m if m.argument_types.size == arg_types.size }
|
|
530
|
+
resolved_args = arg_types.map {|a| a.resolve}
|
|
531
|
+
match = by_name_and_arity[resolved_args]
|
|
532
|
+
return cache_and_wrap(match.return_type) if match
|
|
68
533
|
end
|
|
69
534
|
|
|
70
535
|
def define_types(builder)
|
|
@@ -80,10 +545,12 @@ module Mirah::JVM::Types
|
|
|
80
545
|
else
|
|
81
546
|
name = name.getClassName
|
|
82
547
|
end
|
|
548
|
+
elsif name.kind_of?(Type) && name.array?
|
|
549
|
+
array = true
|
|
83
550
|
end
|
|
84
551
|
type = basic_type(scope, name)
|
|
85
|
-
type = type.array_type if array
|
|
86
|
-
type = type.meta if meta
|
|
552
|
+
type = type.array_type if type && array
|
|
553
|
+
type = type.meta if type && meta
|
|
87
554
|
return type
|
|
88
555
|
end
|
|
89
556
|
|
|
@@ -93,8 +560,9 @@ module Mirah::JVM::Types
|
|
|
93
560
|
end
|
|
94
561
|
orig = name
|
|
95
562
|
if name.kind_of? Java::JavaClass
|
|
563
|
+
#TODO is is possible to get here anymore?
|
|
96
564
|
if name.array?
|
|
97
|
-
return type(name.component_type, true)
|
|
565
|
+
return type(scope, name.component_type, true)
|
|
98
566
|
else
|
|
99
567
|
name = name.name
|
|
100
568
|
end
|
|
@@ -108,18 +576,15 @@ module Mirah::JVM::Types
|
|
|
108
576
|
end
|
|
109
577
|
|
|
110
578
|
def find_type(scope, name)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return get_type(name)
|
|
114
|
-
rescue NameError => ex
|
|
115
|
-
saved_ex = ex
|
|
116
|
-
end
|
|
579
|
+
type = get_type(name)
|
|
580
|
+
return type if type
|
|
117
581
|
|
|
118
582
|
if scope
|
|
119
|
-
imports = scope.
|
|
583
|
+
imports = scope.imports
|
|
120
584
|
if imports.include?(name)
|
|
121
585
|
name = imports[name] while imports.include?(name)
|
|
122
|
-
|
|
586
|
+
type = get_type(name)
|
|
587
|
+
return type if type
|
|
123
588
|
end
|
|
124
589
|
|
|
125
590
|
# TODO support inner class names
|
|
@@ -127,44 +592,44 @@ module Mirah::JVM::Types
|
|
|
127
592
|
return package_search(name, scope)
|
|
128
593
|
end
|
|
129
594
|
end
|
|
130
|
-
|
|
595
|
+
return nil
|
|
131
596
|
end
|
|
132
597
|
|
|
133
598
|
def package_search(name, scope)
|
|
134
599
|
packages = []
|
|
135
|
-
|
|
136
|
-
packages.
|
|
600
|
+
current_package = scope.package
|
|
601
|
+
packages << current_package unless current_package.nil? || current_package.empty?
|
|
602
|
+
packages.concat(scope.search_packages)
|
|
137
603
|
packages << 'java.lang'
|
|
138
604
|
packages.each do |package|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
rescue NameError
|
|
142
|
-
end
|
|
605
|
+
type = get_type("#{package}.#{name}")
|
|
606
|
+
return type if type
|
|
143
607
|
end
|
|
144
|
-
|
|
608
|
+
return nil
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
def getBlockType
|
|
612
|
+
@block_type ||= BlockType.new
|
|
145
613
|
end
|
|
146
614
|
|
|
147
615
|
def get_type(full_name)
|
|
148
616
|
type = @known_types[full_name]
|
|
149
617
|
return type.basic_type if type
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
rescue NameError => ex
|
|
618
|
+
mirror = get_mirror(full_name)
|
|
619
|
+
unless mirror
|
|
153
620
|
if full_name =~ /^(.+)\.([^.]+)/
|
|
154
621
|
outer_name = $1
|
|
155
622
|
inner_name = $2
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
rescue NameError
|
|
160
|
-
raise ex
|
|
161
|
-
end
|
|
623
|
+
outer_type = get_type(outer_name)
|
|
624
|
+
return nil if outer_type.nil?
|
|
625
|
+
full_name = "#{outer_type.name}$#{inner_name}"
|
|
162
626
|
mirror = get_mirror(full_name)
|
|
627
|
+
return nil if mirror.nil?
|
|
163
628
|
else
|
|
164
|
-
|
|
629
|
+
return nil
|
|
165
630
|
end
|
|
166
631
|
end
|
|
167
|
-
type = Type.new(mirror).load_extensions
|
|
632
|
+
type = Type.new(self, mirror).load_extensions
|
|
168
633
|
if full_name.include? '$'
|
|
169
634
|
@known_types[full_name.gsub('$', '.')] = type
|
|
170
635
|
end
|
|
@@ -172,83 +637,105 @@ module Mirah::JVM::Types
|
|
|
172
637
|
end
|
|
173
638
|
|
|
174
639
|
def known_type(scope, name)
|
|
175
|
-
basic_type(scope, name)
|
|
640
|
+
basic_type(scope, name)
|
|
176
641
|
end
|
|
177
642
|
|
|
178
643
|
def declare_type(scope, name)
|
|
179
644
|
full_name = name
|
|
180
|
-
package = scope.
|
|
181
|
-
if !name.include?('.')
|
|
182
|
-
|
|
645
|
+
package = scope.package
|
|
646
|
+
if !name.include?('.')
|
|
647
|
+
if package && !package.empty?
|
|
648
|
+
full_name = "#{package}.#{name}"
|
|
649
|
+
else
|
|
650
|
+
scope.on_package_change do
|
|
651
|
+
full_name = "#{scope.package}.#{name}"
|
|
652
|
+
scope.import(full_name, name)
|
|
653
|
+
@known_types[full_name] = @known_types[name]
|
|
654
|
+
end
|
|
655
|
+
end
|
|
183
656
|
end
|
|
184
657
|
if @known_types.include? full_name
|
|
185
658
|
@known_types[full_name]
|
|
186
659
|
else
|
|
187
|
-
scope.
|
|
188
|
-
@known_types[full_name] = TypeDefinition.new(full_name, nil)
|
|
660
|
+
scope.import(full_name, name)
|
|
661
|
+
@known_types[full_name] = TypeDefinition.new(self, scope, full_name, nil)
|
|
189
662
|
end
|
|
190
663
|
end
|
|
191
664
|
|
|
192
|
-
def define_type(node)
|
|
193
|
-
|
|
665
|
+
def define_type(scope, node)
|
|
666
|
+
if node.name.nil?
|
|
667
|
+
outer_node = node.find_ancestor {|n| (n != node && n.kind_of?(ClassDefinition)) || n.kind_of?(Script)}
|
|
668
|
+
if outer_node.kind_of?(ClassDefinition)
|
|
669
|
+
outer_name = outer_node.name.identifier
|
|
670
|
+
else
|
|
671
|
+
outer_name = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(node.position.source.name || 'DashE')
|
|
672
|
+
end
|
|
673
|
+
id = (@anonymous_classes[outer_name] += 1)
|
|
674
|
+
node.name_set(SimpleString.new("#{outer_name}$#{id}"))
|
|
675
|
+
end
|
|
676
|
+
name = node.name.identifier
|
|
194
677
|
full_name = name
|
|
195
|
-
package =
|
|
196
|
-
if !name.include?('.') && !package.empty?
|
|
678
|
+
package = scope.package
|
|
679
|
+
if !name.include?('.') && package && !package.empty?
|
|
197
680
|
full_name = "#{package}.#{name}"
|
|
198
681
|
end
|
|
199
|
-
if @known_types.include? full_name
|
|
682
|
+
if @known_types.include?(full_name) && @known_types[full_name].kind_of?(TypeDefinition)
|
|
200
683
|
existing = @known_types[full_name]
|
|
201
|
-
existing.node
|
|
684
|
+
unless existing.node
|
|
685
|
+
existing.node = node
|
|
686
|
+
existing.scope = scope
|
|
687
|
+
end
|
|
202
688
|
existing
|
|
203
689
|
else
|
|
204
|
-
if
|
|
690
|
+
if InterfaceDeclaration === node
|
|
205
691
|
klass = InterfaceDefinition
|
|
206
692
|
else
|
|
207
693
|
klass = TypeDefinition
|
|
208
694
|
end
|
|
209
|
-
|
|
210
|
-
@known_types[full_name] = klass.new(full_name, node)
|
|
695
|
+
scope.import(full_name, name)
|
|
696
|
+
@known_types[full_name] = klass.new(self, scope, full_name, node)
|
|
211
697
|
end
|
|
212
698
|
end
|
|
213
699
|
|
|
214
|
-
def no_type
|
|
215
|
-
Void
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def unreachable_type
|
|
219
|
-
Unreachable
|
|
220
|
-
end
|
|
221
|
-
|
|
222
700
|
def make_urls(classpath)
|
|
223
701
|
Mirah::Env.decode_paths(classpath).map do |filename|
|
|
224
702
|
java.io.File.new(filename).to_uri.to_url
|
|
225
703
|
end.to_java(java.net.URL)
|
|
226
704
|
end
|
|
227
705
|
|
|
706
|
+
def base_classpath
|
|
707
|
+
Mirah::Env.encode_paths(['.',
|
|
708
|
+
File.dirname(__FILE__) + '/../../../../javalib/mirah-builtins.jar',
|
|
709
|
+
File.dirname(__FILE__) + '/../../../../javalib/mirah-parser.jar',
|
|
710
|
+
File.dirname(__FILE__) + '/../../../../javalib/mirah-bootstrap.jar'])
|
|
711
|
+
end
|
|
712
|
+
|
|
228
713
|
def classpath
|
|
229
|
-
@classpath ||=
|
|
714
|
+
@classpath ||= base_classpath
|
|
230
715
|
end
|
|
231
716
|
|
|
232
717
|
def classpath=(classpath)
|
|
233
|
-
|
|
718
|
+
if classpath
|
|
719
|
+
@classpath = classpath + ":" + base_classpath
|
|
720
|
+
end
|
|
234
721
|
@resource_loader = nil
|
|
235
722
|
end
|
|
236
|
-
|
|
723
|
+
|
|
237
724
|
def resource_loader
|
|
238
725
|
@resource_loader ||= URLClassLoader.new(make_urls(classpath), bootstrap_loader)
|
|
239
726
|
end
|
|
240
|
-
|
|
727
|
+
|
|
241
728
|
def bootstrap_loader
|
|
242
729
|
@bootstrap_loader ||= begin
|
|
243
730
|
parent = if bootclasspath
|
|
244
731
|
Mirah::Util::IsolatedResourceLoader.new(make_urls(bootclasspath))
|
|
245
732
|
end
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
733
|
+
if __FILE__ =~ /^(file:.+jar)!/
|
|
734
|
+
bootstrap_urls = [java.net.URL.new($1)].to_java(java.net.URL)
|
|
735
|
+
else
|
|
736
|
+
bootstrap_jar = File.expand_path("#{__FILE__}/../../../../../javalib/mirah-bootstrap.jar")
|
|
737
|
+
bootstrap_urls = [java.io.File.new(bootstrap_jar).to_uri.to_url].to_java(java.net.URL)
|
|
738
|
+
end
|
|
252
739
|
URLClassLoader.new(bootstrap_urls, parent)
|
|
253
740
|
end
|
|
254
741
|
end
|
|
@@ -258,15 +745,28 @@ module Mirah::JVM::Types
|
|
|
258
745
|
@bootstrap_loader = nil
|
|
259
746
|
@resource_loader = nil
|
|
260
747
|
end
|
|
261
|
-
|
|
748
|
+
|
|
262
749
|
attr_reader :bootclasspath
|
|
263
|
-
|
|
750
|
+
|
|
751
|
+
def mirror_class(klass)
|
|
752
|
+
name = klass.name.tr('.', '/')
|
|
753
|
+
if klass.respond_to?(:resource_as_stream)
|
|
754
|
+
stream = klass.resource_as_stream("/#{name}.class")
|
|
755
|
+
elsif klass.respond_to?(:get_resource_as_stream)
|
|
756
|
+
stream = klass.get_resource_as_stream("/#{name}.class")
|
|
757
|
+
else
|
|
758
|
+
return get_mirror(klass.name)
|
|
759
|
+
end
|
|
760
|
+
BiteScript::ASM::ClassMirror.load(stream)
|
|
761
|
+
end
|
|
762
|
+
|
|
264
763
|
def get_mirror(name)
|
|
265
764
|
@mirrors[name] ||= begin
|
|
266
765
|
classname = name.tr('.', '/')
|
|
267
766
|
stream = resource_loader.getResourceAsStream(classname + ".class")
|
|
268
767
|
if stream
|
|
269
|
-
BiteScript::ASM::ClassMirror.load(stream)
|
|
768
|
+
mirror = BiteScript::ASM::ClassMirror.load(stream)
|
|
769
|
+
mirror if mirror.type.class_name == name
|
|
270
770
|
else
|
|
271
771
|
# TODO(ribrdb) Should this use a separate sourcepath?
|
|
272
772
|
url = resource_loader.getResource(classname + ".java")
|
|
@@ -277,11 +777,41 @@ module Mirah::JVM::Types
|
|
|
277
777
|
@mirrors[mirror.type.class_name] = mirror
|
|
278
778
|
end if mirrors
|
|
279
779
|
@mirrors[name]
|
|
280
|
-
else
|
|
281
|
-
raise NameError, "Class '#{name}' not found."
|
|
282
780
|
end
|
|
283
781
|
end
|
|
284
782
|
end
|
|
285
783
|
end
|
|
784
|
+
|
|
785
|
+
def getAbstractMethods(type)
|
|
786
|
+
methods = []
|
|
787
|
+
unless type.isError
|
|
788
|
+
object = get_type("java.lang.Object")
|
|
789
|
+
interfaces = [type]
|
|
790
|
+
until interfaces.empty?
|
|
791
|
+
interface = interfaces.pop
|
|
792
|
+
abstract_methods = interface.declared_instance_methods.select {|m| m.abstract?}
|
|
793
|
+
methods += abstract_methods.select do |m|
|
|
794
|
+
begin
|
|
795
|
+
# Skip methods defined on Object
|
|
796
|
+
object.java_method(m.name, *m.argument_types)
|
|
797
|
+
false
|
|
798
|
+
rescue NameError
|
|
799
|
+
true
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
interfaces.concat(interface.interfaces)
|
|
803
|
+
end
|
|
804
|
+
# TODO ensure this works with hierarchies of abstract classes
|
|
805
|
+
# reject the methods implemented by the abstract class
|
|
806
|
+
if type.abstract?
|
|
807
|
+
implemented_methods = type.declared_instance_methods.reject{|m| m.abstract?}.map { |m| [m.name, m.argument_types, m.return_type] }
|
|
808
|
+
methods = methods.reject{|m| implemented_methods.include? [m.name, m.argument_types, m.return_type] }
|
|
809
|
+
end
|
|
810
|
+
end
|
|
811
|
+
methods.map do |method|
|
|
812
|
+
MethodType.new(method.name, method.argument_types, method.return_type, false)
|
|
813
|
+
end
|
|
814
|
+
end
|
|
286
815
|
end
|
|
287
816
|
end
|
|
817
|
+
require 'mirah/jvm/types/basic_types'
|