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
|
@@ -1,58 +1,90 @@
|
|
|
1
|
-
|
|
1
|
+
require 'mirah/jvm/types/ast_ext'
|
|
2
|
+
|
|
3
|
+
module Mirah
|
|
2
4
|
module JVM
|
|
3
5
|
module Compiler
|
|
4
6
|
class JVMBytecode < Base
|
|
5
7
|
java_import java.lang.System
|
|
6
8
|
java_import java.io.PrintStream
|
|
7
9
|
include Mirah::JVM::MethodLookup
|
|
10
|
+
include Mirah::Logging::Logged
|
|
8
11
|
Types = Mirah::JVM::Types
|
|
9
|
-
|
|
12
|
+
java_import 'mirah.lang.ast.Node'
|
|
13
|
+
java_import 'mirah.lang.ast.Array'
|
|
14
|
+
java_import 'mirah.lang.ast.Annotation'
|
|
15
|
+
java_import 'mirah.lang.ast.MethodDefinition'
|
|
16
|
+
java_import 'mirah.lang.ast.ConstructorDefinition'
|
|
17
|
+
java_import 'mirah.lang.ast.Ensure'
|
|
18
|
+
java_import 'mirah.lang.ast.Call'
|
|
19
|
+
java_import 'mirah.lang.ast.Loop'
|
|
20
|
+
java_import 'mirah.lang.ast.FunctionalCall'
|
|
21
|
+
java_import 'mirah.lang.ast.Super'
|
|
22
|
+
java_import 'mirah.lang.ast.ZSuper'
|
|
23
|
+
java_import 'mirah.lang.ast.ImplicitSelf'
|
|
24
|
+
java_import 'mirah.lang.ast.NodeList'
|
|
25
|
+
java_import 'mirah.lang.ast.SimpleString'
|
|
26
|
+
java_import 'mirah.lang.ast.StringConcat'
|
|
27
|
+
java_import 'org.mirah.typer.TypeFuture'
|
|
28
|
+
|
|
29
|
+
class FunctionalCall
|
|
30
|
+
attr_accessor :target
|
|
31
|
+
end
|
|
32
|
+
class Super
|
|
33
|
+
attr_accessor :target, :name
|
|
34
|
+
end
|
|
35
|
+
|
|
10
36
|
class << self
|
|
11
37
|
attr_accessor :verbose
|
|
12
|
-
|
|
13
|
-
def log(message)
|
|
14
|
-
puts "* [#{name}] #{message}" if JVMBytecode.verbose
|
|
15
|
-
end
|
|
16
|
-
|
|
38
|
+
|
|
17
39
|
def classname_from_filename(filename)
|
|
18
40
|
basename = File.basename(filename).sub(/\.(duby|mirah)$/, '')
|
|
19
41
|
basename.split(/[_-]/).map{|x| x[0...1].upcase + x[1..-1]}.join
|
|
20
42
|
end
|
|
21
43
|
end
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def log(message); JVMBytecode.log(message); end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class ImplicitSelf
|
|
28
|
-
attr_reader :inferred_type
|
|
29
|
-
|
|
30
|
-
def initialize(type)
|
|
31
|
-
@inferred_type = type
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def compile(compiler, expression)
|
|
35
|
-
compiler.compile_self if expression
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def initialize
|
|
44
|
+
|
|
45
|
+
def initialize(config, scoper, typer)
|
|
40
46
|
super
|
|
41
47
|
@jump_scope = []
|
|
42
48
|
end
|
|
43
|
-
|
|
49
|
+
|
|
50
|
+
def logger_name
|
|
51
|
+
"org.mirah.ruby.JVM.Compiler.JVMBytecode"
|
|
52
|
+
end
|
|
53
|
+
|
|
44
54
|
def file_builder(filename)
|
|
45
55
|
builder = BiteScript::FileBuilder.new(filename)
|
|
46
|
-
|
|
56
|
+
builder.to_widen do |_a, _b|
|
|
57
|
+
a = @typer.type_system.get_type(_a.tr('/', '.'))
|
|
58
|
+
b = @typer.type_system.get_type(_b.tr('/', '.'))
|
|
59
|
+
a_ancestors = []
|
|
60
|
+
while a
|
|
61
|
+
a_ancestors << a.name
|
|
62
|
+
a = a.superclass
|
|
63
|
+
end
|
|
64
|
+
b_ancestors = []
|
|
65
|
+
while b
|
|
66
|
+
b_ancestors << b.name
|
|
67
|
+
b = b.superclass
|
|
68
|
+
end
|
|
69
|
+
intersection = (a_ancestors & b_ancestors)
|
|
70
|
+
if intersection.size == 0
|
|
71
|
+
puts "#{_a} => #{a}, #{_b} => #{b}"
|
|
72
|
+
puts "#{a_ancestors.inspect} & #{b_ancestors.inspect} = []"
|
|
73
|
+
'java/lang/Object'
|
|
74
|
+
else
|
|
75
|
+
intersection[0].gsub('.', '/')
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
@typer.type_system.define_types(builder)
|
|
47
79
|
builder
|
|
48
80
|
end
|
|
49
|
-
|
|
81
|
+
|
|
50
82
|
def output_type
|
|
51
83
|
"classes"
|
|
52
84
|
end
|
|
53
|
-
|
|
85
|
+
|
|
54
86
|
def push_jump_scope(node)
|
|
55
|
-
raise "Not a node" unless
|
|
87
|
+
raise "Not a node" unless Node === node
|
|
56
88
|
begin
|
|
57
89
|
@jump_scope << node
|
|
58
90
|
yield
|
|
@@ -60,39 +92,40 @@ module Mirah
|
|
|
60
92
|
@jump_scope.pop
|
|
61
93
|
end
|
|
62
94
|
end
|
|
63
|
-
|
|
95
|
+
|
|
64
96
|
def find_ensures(before)
|
|
65
97
|
found = []
|
|
66
98
|
@jump_scope.reverse_each do |scope|
|
|
67
|
-
if
|
|
99
|
+
if Ensure === scope
|
|
68
100
|
found << scope
|
|
69
101
|
end
|
|
70
102
|
break if before === scope
|
|
71
103
|
end
|
|
72
104
|
found
|
|
73
105
|
end
|
|
74
|
-
|
|
106
|
+
|
|
75
107
|
def begin_main
|
|
76
108
|
# declare argv variable
|
|
77
|
-
@method.local('argv',
|
|
109
|
+
@method.local('argv', @typer.type_system.type(nil, 'string', true))
|
|
78
110
|
end
|
|
79
|
-
|
|
111
|
+
|
|
80
112
|
def finish_main
|
|
81
113
|
@method.returnvoid
|
|
82
114
|
end
|
|
83
|
-
|
|
84
|
-
def prepare_binding(
|
|
115
|
+
|
|
116
|
+
def prepare_binding(node)
|
|
117
|
+
scope = introduced_scope(node)
|
|
85
118
|
if scope.has_binding?
|
|
86
119
|
type = scope.binding_type
|
|
87
120
|
@binding = @bindings[type]
|
|
88
121
|
@method.new type
|
|
89
122
|
@method.dup
|
|
90
123
|
@method.invokespecial type, "<init>", [@method.void]
|
|
91
|
-
if
|
|
92
|
-
|
|
93
|
-
name = param.name
|
|
94
|
-
param_type = param
|
|
95
|
-
if scope.
|
|
124
|
+
if node.respond_to? :arguments
|
|
125
|
+
node.arguments.required.each do |param|
|
|
126
|
+
name = param.name.identifier
|
|
127
|
+
param_type = inferred_type(param)
|
|
128
|
+
if scope.captured?(param.name.identifier)
|
|
96
129
|
@method.dup
|
|
97
130
|
type.load(@method, @method.local(name, param_type))
|
|
98
131
|
@method.putfield(type, name, param_type)
|
|
@@ -110,146 +143,183 @@ module Mirah
|
|
|
110
143
|
end
|
|
111
144
|
end
|
|
112
145
|
end
|
|
113
|
-
|
|
114
|
-
def
|
|
146
|
+
|
|
147
|
+
def visitMethodDefinition(node, expression)
|
|
115
148
|
push_jump_scope(node) do
|
|
116
|
-
base_define_method(node
|
|
117
|
-
return if @class.interface?
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
149
|
+
base_define_method(node) do |method, arg_types|
|
|
150
|
+
return if @class.interface? || node.annotated_abstract?
|
|
151
|
+
is_static = self.static || node.kind_of?(StaticMethodDefinition)
|
|
152
|
+
|
|
153
|
+
log "Starting new #{is_static ? 'static ' : ''}method #{node.name.identifier}(#{arg_types})"
|
|
154
|
+
args = visit(node.arguments, true)
|
|
155
|
+
method_body(method, args, node, inferred_type(node).returnType)
|
|
156
|
+
log "Method #{node.name.identifier}(#{arg_types}) complete!"
|
|
123
157
|
end
|
|
124
158
|
end
|
|
125
159
|
end
|
|
126
|
-
|
|
160
|
+
|
|
127
161
|
def define_optarg_chain(name, arg, return_type,
|
|
128
162
|
args_for_opt, arg_types_for_opt)
|
|
129
163
|
# declare all args so they get their values
|
|
130
164
|
@method.aload(0) unless @static
|
|
131
165
|
args_for_opt.each do |req_arg|
|
|
132
|
-
req_arg.
|
|
166
|
+
inferred_type(req_arg).load(@method, @method.local(req_arg.name.identifier, inferred_type(req_arg)))
|
|
133
167
|
end
|
|
134
|
-
arg.value
|
|
135
|
-
|
|
168
|
+
visit(arg.value, true)
|
|
169
|
+
|
|
136
170
|
# invoke the next one in the chain
|
|
137
171
|
if @static
|
|
138
|
-
@method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [arg
|
|
172
|
+
@method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [inferred_type(arg)])
|
|
139
173
|
else
|
|
140
|
-
@method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [arg
|
|
174
|
+
@method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [inferred_type(arg)])
|
|
141
175
|
end
|
|
142
|
-
|
|
176
|
+
|
|
143
177
|
return_type.return(@method)
|
|
144
178
|
end
|
|
145
|
-
|
|
146
|
-
def
|
|
179
|
+
|
|
180
|
+
def visitConstructorDefinition(node, expression)
|
|
147
181
|
push_jump_scope(node) do
|
|
148
182
|
super(node, true) do |method, args|
|
|
149
|
-
method_body(method, args, node,
|
|
183
|
+
method_body(method, args, node, @typer.type_system.type(nil, 'void')) do
|
|
150
184
|
method.aload 0
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
185
|
+
scope = introduced_scope(node)
|
|
186
|
+
if node.body.size > 0 &&
|
|
187
|
+
(node.body(0).kind_of?(Super) || node.body(0).kind_of?(ZSuper))
|
|
188
|
+
super_node = node.body(0)
|
|
189
|
+
delegate_class = @type.superclass
|
|
190
|
+
delegate_types = []
|
|
191
|
+
if super_node.kind_of?(ZSuper)
|
|
192
|
+
[node.arguments.required,
|
|
193
|
+
node.arguments.optional,
|
|
194
|
+
node.arguments.required2
|
|
195
|
+
].each do |args|
|
|
196
|
+
args.each do |arg|
|
|
197
|
+
arg_type = inferred_type(arg)
|
|
198
|
+
delegate_types << arg_type
|
|
199
|
+
local(scope, arg.name.identifier, arg_type)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
154
202
|
else
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
203
|
+
super_node.parameters.each do |param|
|
|
204
|
+
param_type = inferred_type(param)
|
|
205
|
+
delegate_types << param_type
|
|
206
|
+
visit(param, true)
|
|
207
|
+
end
|
|
159
208
|
end
|
|
160
209
|
constructor = delegate_class.constructor(*delegate_types)
|
|
161
|
-
node.delegate_args.each do |arg|
|
|
162
|
-
arg.compile(self, true)
|
|
163
|
-
end
|
|
164
210
|
method.invokespecial(
|
|
165
211
|
delegate_class, "<init>",
|
|
166
212
|
[@method.void, *constructor.argument_types])
|
|
167
213
|
else
|
|
168
|
-
|
|
214
|
+
unless (node.body.size > 0 &&
|
|
215
|
+
node.body(0).kind_of?(FunctionalCall) &&
|
|
216
|
+
node.body(0).name.identifier == 'initialize')
|
|
217
|
+
method.invokespecial @class.superclass, "<init>", [@method.void]
|
|
218
|
+
end
|
|
169
219
|
end
|
|
170
220
|
end
|
|
171
221
|
end
|
|
172
222
|
end
|
|
173
223
|
end
|
|
174
|
-
|
|
224
|
+
|
|
175
225
|
def method_body(method, args, node, return_type)
|
|
176
226
|
body = node.body
|
|
177
227
|
with(:method => method,
|
|
178
228
|
:declared_locals => {}) do
|
|
179
|
-
|
|
229
|
+
|
|
180
230
|
method.start
|
|
181
|
-
|
|
182
|
-
scope = node
|
|
183
|
-
|
|
231
|
+
|
|
232
|
+
scope = introduced_scope(node)
|
|
233
|
+
|
|
184
234
|
# declare all args so they get their values
|
|
185
235
|
if args
|
|
186
|
-
args.each {|arg| declare_local(scope, arg.name, arg
|
|
236
|
+
args.each {|arg| declare_local(scope, arg.name.identifier, inferred_type(arg))}
|
|
187
237
|
end
|
|
188
238
|
declare_locals(scope)
|
|
189
|
-
|
|
239
|
+
|
|
190
240
|
yield if block_given?
|
|
191
|
-
|
|
241
|
+
|
|
192
242
|
prepare_binding(node) do
|
|
193
|
-
expression = return_type !=
|
|
194
|
-
|
|
243
|
+
expression = return_type.name != 'void'
|
|
244
|
+
if body
|
|
245
|
+
if expression
|
|
246
|
+
body_type = inferred_type(body)
|
|
247
|
+
unless return_type.assignableFrom(body_type)
|
|
248
|
+
error("Invalid return type #{body_type.name}, expected #{return_type.name}", body)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
visit(body, expression)
|
|
252
|
+
end
|
|
195
253
|
end
|
|
196
|
-
|
|
254
|
+
|
|
197
255
|
return_type.return(@method)
|
|
198
|
-
|
|
256
|
+
|
|
199
257
|
@method.stop
|
|
200
258
|
end
|
|
201
259
|
end
|
|
202
|
-
|
|
203
|
-
def
|
|
204
|
-
compiler = ClosureCompiler.new(@file, @type, self)
|
|
205
|
-
compiler.
|
|
260
|
+
|
|
261
|
+
def visitClosureDefinition(class_def, expression)
|
|
262
|
+
compiler = ClosureCompiler.new(@config, @file, @type, self, @scoper, @typer)
|
|
263
|
+
compiler.visitClassDefinition(class_def, expression)
|
|
206
264
|
end
|
|
207
|
-
|
|
208
|
-
def
|
|
265
|
+
|
|
266
|
+
def visitInterfaceDeclaration(class_def, expression)
|
|
267
|
+
visitClassDefinition(class_def, expression)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def visitIf(iff, expression)
|
|
209
271
|
elselabel = @method.label
|
|
210
272
|
donelabel = @method.label
|
|
211
|
-
|
|
273
|
+
|
|
212
274
|
# this is ugly...need a better way to abstract the idea of compiling a
|
|
213
275
|
# conditional branch while still fitting into JVM opcodes
|
|
214
|
-
predicate = iff.condition
|
|
215
|
-
|
|
276
|
+
predicate = iff.condition
|
|
277
|
+
body = iff.body
|
|
278
|
+
elseBody = iff.elseBody
|
|
279
|
+
if body.is_a?(NodeList) && body.size == 0
|
|
280
|
+
body = nil
|
|
281
|
+
end
|
|
282
|
+
if elseBody.is_a?(NodeList) && elseBody.size == 0
|
|
283
|
+
elseBody = nil
|
|
284
|
+
end
|
|
285
|
+
if body || expression
|
|
216
286
|
jump_if_not(predicate, elselabel)
|
|
217
|
-
|
|
218
|
-
if
|
|
219
|
-
|
|
287
|
+
|
|
288
|
+
if body
|
|
289
|
+
visit(body, expression)
|
|
220
290
|
elsif expression
|
|
221
|
-
iff.
|
|
291
|
+
inferred_type(iff).init_value(@method)
|
|
222
292
|
end
|
|
223
|
-
|
|
293
|
+
|
|
224
294
|
@method.goto(donelabel)
|
|
225
295
|
else
|
|
226
296
|
jump_if(predicate, donelabel)
|
|
227
297
|
end
|
|
228
|
-
|
|
298
|
+
|
|
229
299
|
elselabel.set!
|
|
230
|
-
|
|
231
|
-
if
|
|
232
|
-
|
|
300
|
+
|
|
301
|
+
if elseBody
|
|
302
|
+
visit(elseBody, expression)
|
|
233
303
|
elsif expression
|
|
234
|
-
iff.
|
|
304
|
+
inferred_type(iff).init_value(@method)
|
|
235
305
|
end
|
|
236
|
-
|
|
306
|
+
|
|
237
307
|
donelabel.set!
|
|
238
308
|
end
|
|
239
|
-
|
|
240
|
-
def
|
|
309
|
+
|
|
310
|
+
def visitLoop(loop, expression)
|
|
241
311
|
push_jump_scope(loop) do
|
|
242
312
|
with(:break_label => @method.label,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
predicate = loop.condition
|
|
246
|
-
|
|
247
|
-
loop.init
|
|
248
|
-
|
|
313
|
+
:redo_label => @method.label,
|
|
314
|
+
:next_label => @method.label) do
|
|
315
|
+
predicate = loop.condition
|
|
316
|
+
|
|
317
|
+
visit(loop.init, false)
|
|
318
|
+
|
|
249
319
|
pre_label = @redo_label
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
@next_label.set! unless loop.
|
|
320
|
+
|
|
321
|
+
unless loop.skipFirstCheck
|
|
322
|
+
@next_label.set! unless loop.post_size > 0
|
|
253
323
|
if loop.negative
|
|
254
324
|
# if condition, exit
|
|
255
325
|
jump_if(predicate, @break_label)
|
|
@@ -258,22 +328,20 @@ module Mirah
|
|
|
258
328
|
jump_if_not(predicate, @break_label)
|
|
259
329
|
end
|
|
260
330
|
end
|
|
261
|
-
|
|
262
|
-
if loop.
|
|
331
|
+
|
|
332
|
+
if loop.pre_size > 0
|
|
263
333
|
pre_label = method.label
|
|
264
334
|
pre_label.set!
|
|
265
|
-
loop.pre
|
|
335
|
+
visit(loop.pre, false)
|
|
266
336
|
end
|
|
267
|
-
|
|
268
|
-
|
|
337
|
+
|
|
338
|
+
|
|
269
339
|
@redo_label.set!
|
|
270
|
-
loop.body
|
|
271
|
-
|
|
272
|
-
if loop.
|
|
273
|
-
@method.goto(@next_label)
|
|
274
|
-
else
|
|
340
|
+
visit(loop.body, false) if loop.body
|
|
341
|
+
|
|
342
|
+
if loop.skipFirstCheck || loop.post_size > 0
|
|
275
343
|
@next_label.set!
|
|
276
|
-
loop.post
|
|
344
|
+
visit(loop.post, false)
|
|
277
345
|
if loop.negative
|
|
278
346
|
# if not condition, continue
|
|
279
347
|
jump_if_not(predicate, pre_label)
|
|
@@ -281,149 +349,217 @@ module Mirah
|
|
|
281
349
|
# if condition, continue
|
|
282
350
|
jump_if(predicate, pre_label)
|
|
283
351
|
end
|
|
352
|
+
else
|
|
353
|
+
@method.goto(@next_label)
|
|
284
354
|
end
|
|
285
|
-
|
|
355
|
+
|
|
286
356
|
@break_label.set!
|
|
287
|
-
|
|
357
|
+
|
|
288
358
|
# loops always evaluate to null
|
|
289
359
|
@method.aconst_null if expression
|
|
290
360
|
end
|
|
291
361
|
end
|
|
292
362
|
end
|
|
293
|
-
|
|
294
|
-
def
|
|
363
|
+
|
|
364
|
+
def visitBreak(node, expression)
|
|
295
365
|
error("break outside of loop", node) unless @break_label
|
|
296
|
-
handle_ensures(find_ensures(
|
|
366
|
+
handle_ensures(find_ensures(Loop))
|
|
367
|
+
set_position node.position
|
|
297
368
|
@method.goto(@break_label)
|
|
298
369
|
end
|
|
299
|
-
|
|
300
|
-
def
|
|
370
|
+
|
|
371
|
+
def visitNext(node, expression)
|
|
301
372
|
error("next outside of loop", node) unless @next_label
|
|
302
|
-
handle_ensures(find_ensures(
|
|
373
|
+
handle_ensures(find_ensures(Loop))
|
|
374
|
+
set_position node.position
|
|
303
375
|
@method.goto(@next_label)
|
|
304
376
|
end
|
|
305
|
-
|
|
306
|
-
def
|
|
377
|
+
|
|
378
|
+
def visitRedo(node, expression)
|
|
307
379
|
error("redo outside of loop", node) unless @redo_label
|
|
308
|
-
handle_ensures(find_ensures(
|
|
380
|
+
handle_ensures(find_ensures(Loop))
|
|
381
|
+
set_position node.position
|
|
309
382
|
@method.goto(@redo_label)
|
|
310
383
|
end
|
|
311
|
-
|
|
384
|
+
|
|
312
385
|
def jump_if(predicate, target)
|
|
313
|
-
|
|
314
|
-
|
|
386
|
+
type = inferred_type(predicate)
|
|
387
|
+
if type.primitive?
|
|
388
|
+
raise "Expected boolean, found #{type}" unless type.name == 'boolean'
|
|
315
389
|
end
|
|
316
|
-
if
|
|
390
|
+
if Call === predicate
|
|
317
391
|
method = extract_method(predicate)
|
|
318
392
|
if method.respond_to? :jump_if
|
|
319
393
|
method.jump_if(self, predicate, target)
|
|
320
394
|
return
|
|
321
395
|
end
|
|
322
396
|
end
|
|
323
|
-
predicate
|
|
324
|
-
|
|
397
|
+
visit(predicate, true)
|
|
398
|
+
if type.primitive?
|
|
399
|
+
@method.ifne(target)
|
|
400
|
+
else
|
|
401
|
+
@method.ifnonnull(target)
|
|
402
|
+
end
|
|
325
403
|
end
|
|
326
|
-
|
|
404
|
+
|
|
327
405
|
def jump_if_not(predicate, target)
|
|
328
|
-
|
|
329
|
-
|
|
406
|
+
type = inferred_type(predicate)
|
|
407
|
+
if type.primitive?
|
|
408
|
+
raise "Expected boolean, found #{type}" unless type.name == 'boolean'
|
|
330
409
|
end
|
|
331
|
-
if
|
|
410
|
+
if Call === predicate
|
|
332
411
|
method = extract_method(predicate)
|
|
333
412
|
if method.respond_to? :jump_if_not
|
|
334
413
|
method.jump_if_not(self, predicate, target)
|
|
335
414
|
return
|
|
336
415
|
end
|
|
337
416
|
end
|
|
338
|
-
predicate
|
|
339
|
-
|
|
417
|
+
visit(predicate, true)
|
|
418
|
+
if type.primitive?
|
|
419
|
+
@method.ifeq(target)
|
|
420
|
+
else
|
|
421
|
+
@method.ifnull(target)
|
|
422
|
+
end
|
|
340
423
|
end
|
|
341
|
-
|
|
424
|
+
|
|
342
425
|
def extract_method(call)
|
|
343
|
-
target = call.target
|
|
426
|
+
target = inferred_type(call.target)
|
|
344
427
|
params = call.parameters.map do |param|
|
|
345
|
-
param
|
|
428
|
+
inferred_type(param)
|
|
429
|
+
end
|
|
430
|
+
target.get_method(call.name.identifier, params)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def visitAttrAssign(call, expression)
|
|
434
|
+
target = inferred_type(call.target)
|
|
435
|
+
value_type = inferred_type(call.value)
|
|
436
|
+
setter = "#{call.name.identifier}_set"
|
|
437
|
+
method = target.get_method(setter, [value_type])
|
|
438
|
+
if method
|
|
439
|
+
method.call(self, call, expression, [call.value])
|
|
440
|
+
else
|
|
441
|
+
target = inferred_type(call.target)
|
|
442
|
+
raise "Missing method #{target.full_name}.#{setter}(#{value_type.full_name})"
|
|
346
443
|
end
|
|
347
|
-
target.get_method(call.name, params)
|
|
348
444
|
end
|
|
349
|
-
|
|
350
|
-
def
|
|
351
|
-
return cast(call, expression) if call.cast?
|
|
445
|
+
|
|
446
|
+
def visitCall(call, expression)
|
|
352
447
|
method = extract_method(call)
|
|
353
448
|
if method
|
|
354
449
|
method.call(self, call, expression)
|
|
355
450
|
else
|
|
356
|
-
|
|
451
|
+
params = call.parameters.map do |param|
|
|
452
|
+
inferred_type(param)
|
|
453
|
+
end
|
|
454
|
+
target = inferred_type(call.target)
|
|
455
|
+
raise "Missing method #{target}.#{call.name.identifier}(#{params.join ', '})"
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def visitVarargsArray type, parameters
|
|
460
|
+
@method.push_int parameters.size
|
|
461
|
+
@method.anewarray type.component_type
|
|
462
|
+
parameters.each.with_index do |value, i|
|
|
463
|
+
@method.dup
|
|
464
|
+
@method.push_int i
|
|
465
|
+
visit(value, true)
|
|
466
|
+
in_type = inferred_type(value)
|
|
467
|
+
if in_type.primitive? && in_type != type.component_type
|
|
468
|
+
in_type.compile_widen(@method, type.component_type)
|
|
469
|
+
end
|
|
470
|
+
@method.aastore
|
|
357
471
|
end
|
|
358
472
|
end
|
|
359
|
-
|
|
360
|
-
def
|
|
361
|
-
|
|
362
|
-
type = fcall.
|
|
473
|
+
|
|
474
|
+
def visitFunctionalCall(fcall, expression)
|
|
475
|
+
scope = get_scope(fcall)
|
|
476
|
+
type = get_scope(fcall).self_type.resolve
|
|
363
477
|
type = type.meta if (@static && type == @type)
|
|
364
|
-
fcall.target = ImplicitSelf.new
|
|
365
|
-
|
|
478
|
+
fcall.target = ImplicitSelf.new
|
|
479
|
+
fcall.target.parent = fcall
|
|
480
|
+
@typer.infer(fcall.target)
|
|
481
|
+
|
|
366
482
|
params = fcall.parameters.map do |param|
|
|
367
|
-
param
|
|
483
|
+
inferred_type(param)
|
|
484
|
+
end
|
|
485
|
+
name = fcall.name.identifier
|
|
486
|
+
chained_constructor = false
|
|
487
|
+
if name == 'initialize'
|
|
488
|
+
if scope.context.kind_of?(ConstructorDefinition) &&
|
|
489
|
+
scope.context.body(0) == fcall
|
|
490
|
+
name = '<init>'
|
|
491
|
+
chained_constructor = true
|
|
492
|
+
end
|
|
368
493
|
end
|
|
369
|
-
|
|
494
|
+
|
|
495
|
+
method = type.get_method(name, params)
|
|
370
496
|
unless method
|
|
371
497
|
target = static ? @class.name : 'self'
|
|
372
|
-
|
|
373
|
-
raise NameError, "No method %s.%s(%s)
|
|
374
|
-
[target, fcall.name, params.join(', ')
|
|
498
|
+
|
|
499
|
+
raise NameError, "No method %s.%s(%s)" %
|
|
500
|
+
[target, fcall.name.identifier, params.join(', ')]
|
|
501
|
+
end
|
|
502
|
+
if chained_constructor
|
|
503
|
+
method.call(self, fcall, expression, nil, true)
|
|
504
|
+
else
|
|
505
|
+
method.call(self, fcall, expression)
|
|
375
506
|
end
|
|
376
|
-
method.call(self, fcall, expression)
|
|
377
507
|
end
|
|
378
|
-
|
|
379
|
-
def
|
|
508
|
+
|
|
509
|
+
def visitSuper(sup, expression)
|
|
510
|
+
mdef = sup.findAncestor(MethodDefinition.java_class)
|
|
511
|
+
# FIXME Horrible hack
|
|
512
|
+
return if mdef.kind_of?(ConstructorDefinition)
|
|
380
513
|
type = @type.superclass
|
|
381
|
-
|
|
382
|
-
|
|
514
|
+
super_type = @typer.type_system.getSuperClass(get_scope(sup).self_type)
|
|
515
|
+
@typer.infer(sup.target)
|
|
516
|
+
|
|
517
|
+
sup.name = mdef.name.identifier
|
|
518
|
+
|
|
519
|
+
# TODO ZSuper
|
|
383
520
|
params = sup.parameters.map do |param|
|
|
384
|
-
param
|
|
521
|
+
inferred_type(param)
|
|
385
522
|
end
|
|
386
523
|
method = type.get_method(sup.name, params)
|
|
387
524
|
unless method
|
|
388
|
-
|
|
389
525
|
raise NameError, "No method %s.%s(%s)" %
|
|
390
526
|
[type, sup.name, params.join(', ')]
|
|
391
527
|
end
|
|
392
|
-
method.call_special(self, sup, expression)
|
|
528
|
+
method.call_special(self, ImplicitSelf.new, type, sup.parameters, expression)
|
|
393
529
|
end
|
|
394
|
-
|
|
395
|
-
def
|
|
530
|
+
|
|
531
|
+
def visitCast(fcall, expression)
|
|
396
532
|
# casting operation, not a call
|
|
397
|
-
castee = fcall.
|
|
398
|
-
|
|
533
|
+
castee = fcall.value
|
|
534
|
+
|
|
399
535
|
# TODO move errors to inference phase
|
|
400
|
-
source_type_name = castee.
|
|
401
|
-
target_type_name = fcall.
|
|
402
|
-
if castee.
|
|
403
|
-
if fcall.
|
|
536
|
+
source_type_name = inferred_type(castee).name
|
|
537
|
+
target_type_name = inferred_type(fcall).name
|
|
538
|
+
if inferred_type(castee).primitive?
|
|
539
|
+
if inferred_type(fcall).primitive?
|
|
404
540
|
if source_type_name == 'boolean' && target_type_name != "boolean"
|
|
405
|
-
raise
|
|
541
|
+
raise TypeError.new "not a boolean type: #{inferred_type(castee)}"
|
|
406
542
|
end
|
|
407
543
|
# ok
|
|
408
544
|
primitive = true
|
|
409
545
|
else
|
|
410
|
-
raise
|
|
546
|
+
raise TypeError.new "Cannot cast #{inferred_type(castee)} to #{inferred_type(fcall)}: not a reference type."
|
|
411
547
|
end
|
|
412
|
-
elsif fcall.
|
|
413
|
-
raise
|
|
548
|
+
elsif inferred_type(fcall).primitive?
|
|
549
|
+
raise TypeError.new "not a primitive type: #{inferred_type(castee)}"
|
|
414
550
|
else
|
|
415
551
|
# ok
|
|
416
552
|
primitive = false
|
|
417
553
|
end
|
|
418
|
-
|
|
419
|
-
castee
|
|
554
|
+
|
|
555
|
+
visit(castee, expression)
|
|
420
556
|
if expression
|
|
421
557
|
if primitive
|
|
422
558
|
source_type_name = 'int' if %w[byte short char].include? source_type_name
|
|
423
559
|
if (source_type_name != 'int') && (%w[byte short char].include? target_type_name)
|
|
424
560
|
target_type_name = 'int'
|
|
425
561
|
end
|
|
426
|
-
|
|
562
|
+
|
|
427
563
|
if source_type_name != target_type_name
|
|
428
564
|
if RUBY_VERSION == "1.9"
|
|
429
565
|
@method.send "#{source_type_name[0]}2#{target_type_name[0]}"
|
|
@@ -433,76 +569,117 @@ module Mirah
|
|
|
433
569
|
end
|
|
434
570
|
else
|
|
435
571
|
if (source_type_name != target_type_name ||
|
|
436
|
-
castee.
|
|
437
|
-
@method.checkcast fcall
|
|
572
|
+
inferred_type(castee).array? != inferred_type(fcall).array?)
|
|
573
|
+
@method.checkcast inferred_type(fcall)
|
|
438
574
|
end
|
|
439
575
|
end
|
|
440
576
|
end
|
|
441
577
|
end
|
|
442
|
-
|
|
443
|
-
def
|
|
578
|
+
|
|
579
|
+
def visitNodeList(body, expression)
|
|
444
580
|
# last element is an expression only if the body is an expression
|
|
445
581
|
super(body, expression) do |last|
|
|
446
|
-
|
|
582
|
+
if last
|
|
583
|
+
visit(last, expression)
|
|
584
|
+
elsif expression
|
|
585
|
+
inferred_type(body).init_value(method)
|
|
586
|
+
end
|
|
447
587
|
end
|
|
448
588
|
end
|
|
449
|
-
|
|
450
|
-
def local(scope, name, type)
|
|
451
|
-
type.load(@method, @method.local(scoped_local_name(name, scope), type))
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
def local_assign(scope, name, type, expression, value)
|
|
455
|
-
declare_local(scope, name, type)
|
|
456
|
-
|
|
457
|
-
value.compile(self, true)
|
|
458
|
-
|
|
459
|
-
# if expression, dup the value we're assigning
|
|
460
|
-
@method.dup if expression
|
|
461
|
-
|
|
462
|
-
type.store(@method, @method.local(scoped_local_name(name, scope), type))
|
|
463
|
-
end
|
|
464
|
-
|
|
589
|
+
|
|
465
590
|
def declared_locals
|
|
466
591
|
@declared_locals ||= {}
|
|
467
592
|
end
|
|
468
|
-
|
|
593
|
+
|
|
469
594
|
def annotate(builder, annotations)
|
|
470
595
|
annotations.each do |annotation|
|
|
471
|
-
|
|
472
|
-
type =
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
596
|
+
next if annotation.type.typeref.name.start_with?('org.mirah.jvm.')
|
|
597
|
+
type = inferred_type(annotation)
|
|
598
|
+
mirror = type.jvm_type
|
|
599
|
+
if mirror.respond_to?(:getDeclaredAnnotation)
|
|
600
|
+
retention = mirror.getDeclaredAnnotation('java.lang.annotation.Retention')
|
|
601
|
+
else
|
|
602
|
+
raise "Unsupported annotation #{mirror} (#{mirror.class})"
|
|
603
|
+
end
|
|
604
|
+
next if retention && retention.value.name == 'SOURCE'
|
|
605
|
+
runtime_retention = (retention && retention.value.name == 'RUNTIME')
|
|
606
|
+
builder.annotate(mirror, runtime_retention) do |visitor|
|
|
607
|
+
annotation.values.each do |entry|
|
|
608
|
+
annotation_value(get_scope(annotation), type, visitor,
|
|
609
|
+
entry.key.identifier, entry.value)
|
|
476
610
|
end
|
|
477
611
|
end
|
|
478
612
|
end
|
|
479
613
|
end
|
|
480
|
-
|
|
481
|
-
def annotation_value(builder, name, value)
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
value.values.each do |name, value|
|
|
488
|
-
annotation_value(child, name, value)
|
|
614
|
+
|
|
615
|
+
def annotation_value(scope, type, builder, name, value)
|
|
616
|
+
if name
|
|
617
|
+
value_type = type.unmeta.java_method(name).return_type
|
|
618
|
+
if value_type.array?
|
|
619
|
+
unless value.kind_of?(Array)
|
|
620
|
+
raise "#{type.name}.#{name} should be an Array, got #{value.class}"
|
|
489
621
|
end
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
annotation_value(array, nil, item)
|
|
622
|
+
builder.array(name) do |child|
|
|
623
|
+
value.values.each do |item|
|
|
624
|
+
annotation_value(scope, value_type.component_type, child, nil, item)
|
|
625
|
+
end
|
|
495
626
|
end
|
|
627
|
+
return
|
|
496
628
|
end
|
|
497
629
|
else
|
|
498
|
-
|
|
630
|
+
value_type = type
|
|
631
|
+
end
|
|
632
|
+
primitive_classes = {
|
|
633
|
+
'Z' => java.lang.Boolean,
|
|
634
|
+
'B' => java.lang.Byte,
|
|
635
|
+
'C' => java.lang.Character,
|
|
636
|
+
'S' => java.lang.Short,
|
|
637
|
+
'I' => java.lang.Integer,
|
|
638
|
+
'J' => java.lang.Long,
|
|
639
|
+
'F' => java.lang.Float,
|
|
640
|
+
'D' => java.lang.Double,
|
|
641
|
+
}
|
|
642
|
+
descriptor = BiteScript::Signature::class_id(value_type)
|
|
643
|
+
case descriptor
|
|
644
|
+
when 'Ljava/lang/String;'
|
|
645
|
+
string_value = if value.kind_of?(StringConcat)
|
|
646
|
+
value.strings.map {|x| x.identifier}.join
|
|
647
|
+
else
|
|
648
|
+
value.identifier
|
|
649
|
+
end
|
|
650
|
+
builder.visit(name, string_value)
|
|
651
|
+
when 'Ljava/lang/Class;'
|
|
652
|
+
mirror = @typer.type_system.type(scope, value.typeref.name)
|
|
653
|
+
klass = if value.typeref.isArray
|
|
654
|
+
BiteScript::ASM::Type.get("[#{mirror.type.descriptor}")
|
|
655
|
+
else
|
|
656
|
+
mirror
|
|
657
|
+
end
|
|
658
|
+
builder.visit(name, klass)
|
|
659
|
+
when *primitive_classes.keys
|
|
660
|
+
klass = primitive_classes[descriptor]
|
|
661
|
+
builder.visit(name, klass.new(value.value))
|
|
662
|
+
else
|
|
663
|
+
if value_type.jvm_type.enum?
|
|
664
|
+
builder.enum(name, value_type, value.identifier)
|
|
665
|
+
elsif value_type.jvm_type.annotation?
|
|
666
|
+
subtype = inferred_type(value)
|
|
667
|
+
mirror = subtype.jvm_type
|
|
668
|
+
builder.annotation(name, mirror) do |child|
|
|
669
|
+
value.values.each do |entry|
|
|
670
|
+
annotation_value(scope, subtype, child, entry.key.identifier, entry.value)
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
else
|
|
674
|
+
raise "Unsupported annotation #{descriptor} #{name} = #{value.class}"
|
|
675
|
+
end
|
|
499
676
|
end
|
|
500
677
|
end
|
|
501
|
-
|
|
678
|
+
|
|
502
679
|
def declared?(scope, name)
|
|
503
680
|
declared_locals.include?(scoped_local_name(name, scope))
|
|
504
681
|
end
|
|
505
|
-
|
|
682
|
+
|
|
506
683
|
def declare_local(scope, name, type)
|
|
507
684
|
# TODO confirm types are compatible
|
|
508
685
|
name = scoped_local_name(name, scope)
|
|
@@ -511,29 +688,34 @@ module Mirah
|
|
|
511
688
|
index = @method.local(name, type)
|
|
512
689
|
end
|
|
513
690
|
end
|
|
514
|
-
|
|
515
|
-
def local_declare(scope, name, type)
|
|
516
|
-
end
|
|
517
|
-
|
|
691
|
+
|
|
518
692
|
def declare_locals(scope)
|
|
519
693
|
scope.locals.each do |name|
|
|
520
694
|
unless scope.captured?(name) || declared?(scope, name)
|
|
521
695
|
type = scope.local_type(name)
|
|
696
|
+
type = type.resolve if type.kind_of?(TypeFuture)
|
|
522
697
|
declare_local(scope, name, type)
|
|
523
698
|
type.init_value(@method)
|
|
524
699
|
type.store(@method, @method.local(scoped_local_name(name, scope), type))
|
|
525
700
|
end
|
|
526
701
|
end
|
|
527
702
|
end
|
|
528
|
-
|
|
703
|
+
|
|
529
704
|
def get_binding(type)
|
|
530
705
|
@bindings[type]
|
|
531
706
|
end
|
|
532
|
-
|
|
707
|
+
|
|
533
708
|
def declared_captures(binding=nil)
|
|
534
709
|
@captured_locals[binding || @binding]
|
|
535
710
|
end
|
|
536
|
-
|
|
711
|
+
|
|
712
|
+
def visitLocalDeclaration(local, expression)
|
|
713
|
+
scope = get_scope(local)
|
|
714
|
+
if scope.has_binding? && scope.captured?(local.name.identifier)
|
|
715
|
+
captured_local_declare(scope, local.name.identifier, inferred_type(local))
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
|
|
537
719
|
def captured_local_declare(scope, name, type)
|
|
538
720
|
unless declared_captures[name]
|
|
539
721
|
declared_captures[name] = type
|
|
@@ -541,44 +723,85 @@ module Mirah
|
|
|
541
723
|
@binding.protected_field(name, type)
|
|
542
724
|
end
|
|
543
725
|
end
|
|
544
|
-
|
|
726
|
+
|
|
727
|
+
def visitLocalAccess(local, expression)
|
|
728
|
+
if expression
|
|
729
|
+
set_position(local.position)
|
|
730
|
+
scope = get_scope(local)
|
|
731
|
+
if scope.has_binding? && scope.captured?(local.name.identifier)
|
|
732
|
+
captured_local(scope, local.name.identifier, inferred_type(local))
|
|
733
|
+
else
|
|
734
|
+
local(containing_scope(local), local.name.identifier, inferred_type(local))
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
def local(scope, name, type)
|
|
740
|
+
type.load(@method, @method.local(scoped_local_name(name, scope), type))
|
|
741
|
+
end
|
|
742
|
+
|
|
545
743
|
def captured_local(scope, name, type)
|
|
546
744
|
captured_local_declare(scope, name, type)
|
|
547
745
|
binding_reference
|
|
548
746
|
@method.getfield(scope.binding_type, name, type)
|
|
549
747
|
end
|
|
550
|
-
|
|
748
|
+
|
|
749
|
+
def visitLocalAssignment(local, expression)
|
|
750
|
+
scope = get_scope(local)
|
|
751
|
+
if scope.has_binding? && scope.captured?(local.name.identifier)
|
|
752
|
+
captured_local_assign(local, expression)
|
|
753
|
+
else
|
|
754
|
+
local_assign(local, expression)
|
|
755
|
+
end
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
def local_assign(local, expression)
|
|
759
|
+
name = local.name.identifier
|
|
760
|
+
type = inferred_type(local)
|
|
761
|
+
scope = containing_scope(local)
|
|
762
|
+
declare_local(scope, name, type)
|
|
763
|
+
|
|
764
|
+
visit(local.value, true)
|
|
765
|
+
|
|
766
|
+
# if expression, dup the value we're assigning
|
|
767
|
+
@method.dup if expression
|
|
768
|
+
set_position(local.position)
|
|
769
|
+
type.store(@method, @method.local(scoped_local_name(name, scope), type))
|
|
770
|
+
end
|
|
771
|
+
|
|
551
772
|
def captured_local_assign(node, expression)
|
|
552
|
-
scope, name, type = node
|
|
773
|
+
scope, name, type = containing_scope(node), node.name.identifier, inferred_type(node)
|
|
553
774
|
captured_local_declare(scope, name, type)
|
|
554
775
|
binding_reference
|
|
555
|
-
node.value
|
|
776
|
+
visit(node.value, true)
|
|
556
777
|
@method.dup_x2 if expression
|
|
778
|
+
set_position(node.position)
|
|
557
779
|
@method.putfield(scope.binding_type, name, type)
|
|
558
780
|
end
|
|
559
|
-
|
|
560
|
-
def field
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
declare_field(name, real_type,
|
|
566
|
-
|
|
781
|
+
|
|
782
|
+
def visitFieldAccess(field, expression)
|
|
783
|
+
return nil unless expression
|
|
784
|
+
name = field.name.identifier
|
|
785
|
+
|
|
786
|
+
real_type = declared_fields[name] || inferred_type(field)
|
|
787
|
+
declare_field(name, real_type, [], field.isStatic)
|
|
788
|
+
|
|
789
|
+
set_position(field.position)
|
|
567
790
|
# load self object unless static
|
|
568
|
-
method.aload 0 unless static ||
|
|
569
|
-
|
|
570
|
-
if static ||
|
|
571
|
-
@method.getstatic(@class, name,
|
|
791
|
+
method.aload 0 unless static || field.isStatic
|
|
792
|
+
|
|
793
|
+
if static || field.isStatic
|
|
794
|
+
@method.getstatic(@class, name, inferred_type(field))
|
|
572
795
|
else
|
|
573
|
-
@method.getfield(@class, name,
|
|
796
|
+
@method.getfield(@class, name, inferred_type(field))
|
|
574
797
|
end
|
|
575
798
|
end
|
|
576
|
-
|
|
799
|
+
|
|
577
800
|
def declared_fields
|
|
578
801
|
@declared_fields ||= {}
|
|
579
802
|
@declared_fields[@class] ||= {}
|
|
580
803
|
end
|
|
581
|
-
|
|
804
|
+
|
|
582
805
|
def declare_field(name, type, annotations, static_field)
|
|
583
806
|
# TODO confirm types are compatible
|
|
584
807
|
unless declared_fields[name]
|
|
@@ -591,71 +814,74 @@ module Mirah
|
|
|
591
814
|
annotate(field, annotations)
|
|
592
815
|
end
|
|
593
816
|
end
|
|
594
|
-
|
|
595
|
-
def
|
|
596
|
-
name
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
value.compile(self, true)
|
|
817
|
+
|
|
818
|
+
def visitFieldDeclaration(decl, expression)
|
|
819
|
+
declare_field(decl.name.identifier, inferred_type(decl), decl.annotations, decl.isStatic)
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
def visitFieldAssign(field, expression)
|
|
823
|
+
name = field.name.identifier
|
|
824
|
+
|
|
825
|
+
real_type = declared_fields[name] || inferred_type(field)
|
|
826
|
+
|
|
827
|
+
declare_field(name, real_type, field.annotations, field.isStatic)
|
|
828
|
+
|
|
829
|
+
method.aload 0 unless static || field.isStatic
|
|
830
|
+
visit(field.value, true)
|
|
609
831
|
if expression
|
|
610
832
|
instruction = 'dup'
|
|
611
|
-
instruction << '2' if
|
|
612
|
-
instruction << '_x1' unless static ||
|
|
833
|
+
instruction << '2' if real_type.wide?
|
|
834
|
+
instruction << '_x1' unless static || field.isStatic
|
|
613
835
|
method.send instruction
|
|
614
836
|
end
|
|
615
|
-
|
|
616
|
-
if static ||
|
|
837
|
+
set_position(field.position)
|
|
838
|
+
if static || field.isStatic
|
|
617
839
|
@method.putstatic(@class, name, real_type)
|
|
618
840
|
else
|
|
619
841
|
@method.putfield(@class, name, real_type)
|
|
620
842
|
end
|
|
621
843
|
end
|
|
622
|
-
|
|
623
|
-
def string
|
|
624
|
-
|
|
844
|
+
|
|
845
|
+
def visitSimpleString(string, expression)
|
|
846
|
+
set_position(string.position)
|
|
847
|
+
@method.ldc(string.value) if expression
|
|
625
848
|
end
|
|
626
|
-
|
|
627
|
-
def
|
|
849
|
+
|
|
850
|
+
def visitStringConcat(strcat, expression)
|
|
851
|
+
set_position(strcat.position)
|
|
628
852
|
if expression
|
|
629
853
|
# could probably be more efficient with non-default constructor
|
|
630
|
-
builder_class =
|
|
854
|
+
builder_class = @typer.type_system.type(nil, 'java.lang.StringBuilder')
|
|
631
855
|
@method.new builder_class
|
|
632
856
|
@method.dup
|
|
633
857
|
@method.invokespecial builder_class, "<init>", [@method.void]
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
node
|
|
637
|
-
method = find_method(builder_class, "append", [node
|
|
858
|
+
|
|
859
|
+
strcat.strings.each do |node|
|
|
860
|
+
visit(node, true)
|
|
861
|
+
method = find_method(builder_class, "append", [inferred_type(node)], nil, false)
|
|
638
862
|
if method
|
|
639
863
|
@method.invokevirtual builder_class, "append", [method.return_type, *method.argument_types]
|
|
640
864
|
else
|
|
641
|
-
log "Could not find a match for #{java::lang::StringBuilder}.append(#{node
|
|
865
|
+
log "Could not find a match for #{java::lang::StringBuilder}.append(#{inferred_type(node)})"
|
|
642
866
|
fail "Could not compile"
|
|
643
867
|
end
|
|
644
868
|
end
|
|
645
|
-
|
|
869
|
+
|
|
646
870
|
# convert to string
|
|
871
|
+
set_position(strcat.position)
|
|
647
872
|
@method.invokevirtual java::lang::StringBuilder.java_class, "toString", [@method.string]
|
|
648
873
|
else
|
|
649
|
-
|
|
650
|
-
node
|
|
874
|
+
strcat.strings.each do |node|
|
|
875
|
+
visit(node, false)
|
|
651
876
|
end
|
|
652
877
|
end
|
|
653
878
|
end
|
|
654
|
-
|
|
655
|
-
def
|
|
879
|
+
|
|
880
|
+
def visitStringEval(node, expression)
|
|
656
881
|
if expression
|
|
657
|
-
|
|
658
|
-
|
|
882
|
+
visit(node.value, true)
|
|
883
|
+
set_position(node.position)
|
|
884
|
+
inferred_type(node.value).box(@method) if inferred_type(node.value).primitive?
|
|
659
885
|
null = method.label
|
|
660
886
|
done = method.label
|
|
661
887
|
method.dup
|
|
@@ -667,78 +893,151 @@ module Mirah
|
|
|
667
893
|
method.ldc("null")
|
|
668
894
|
done.set!
|
|
669
895
|
else
|
|
670
|
-
|
|
896
|
+
visit(node.value, false)
|
|
671
897
|
end
|
|
672
898
|
end
|
|
673
|
-
|
|
674
|
-
def
|
|
675
|
-
|
|
899
|
+
|
|
900
|
+
def visitBoolean(node, expression)
|
|
901
|
+
if expression
|
|
902
|
+
set_position(node.position)
|
|
903
|
+
node.value ? @method.iconst_1 : @method.iconst_0
|
|
904
|
+
end
|
|
676
905
|
end
|
|
677
|
-
|
|
678
|
-
def
|
|
906
|
+
|
|
907
|
+
def visitRegex(node, expression)
|
|
679
908
|
# TODO: translate flags to Java-appropriate values
|
|
680
|
-
|
|
681
|
-
|
|
909
|
+
if node.strings_size == 1
|
|
910
|
+
visit(node.strings(0), expression)
|
|
911
|
+
else
|
|
912
|
+
visitStringConcat(node, expression)
|
|
913
|
+
end
|
|
914
|
+
if expression
|
|
915
|
+
set_position(node.position)
|
|
916
|
+
@method.invokestatic java::util::regex::Pattern, "compile", [java::util::regex::Pattern, @method.string]
|
|
917
|
+
end
|
|
682
918
|
end
|
|
683
|
-
|
|
684
|
-
def
|
|
919
|
+
|
|
920
|
+
def visitArray(node, expression)
|
|
921
|
+
set_position(node.position)
|
|
685
922
|
if expression
|
|
686
923
|
# create basic arraylist
|
|
687
924
|
@method.new java::util::ArrayList
|
|
688
925
|
@method.dup
|
|
689
|
-
@method.ldc_int node.
|
|
926
|
+
@method.ldc_int node.values_size
|
|
690
927
|
@method.invokespecial java::util::ArrayList, "<init>", [@method.void, @method.int]
|
|
691
|
-
|
|
928
|
+
|
|
692
929
|
# elements, as expressions
|
|
693
930
|
# TODO: ensure they're all reference types!
|
|
694
|
-
node.
|
|
931
|
+
node.values.each do |n|
|
|
695
932
|
@method.dup
|
|
696
|
-
n
|
|
933
|
+
visit(n, true)
|
|
697
934
|
# TODO this feels like it should be in the node.compile itself
|
|
698
|
-
if n.
|
|
699
|
-
n.
|
|
935
|
+
if inferred_type(n).primitive?
|
|
936
|
+
inferred_type(n).box(@method)
|
|
700
937
|
end
|
|
701
938
|
@method.invokeinterface java::util::List, "add", [@method.boolean, @method.object]
|
|
702
939
|
@method.pop
|
|
703
940
|
end
|
|
704
|
-
|
|
941
|
+
|
|
705
942
|
# make it unmodifiable
|
|
706
943
|
@method.invokestatic java::util::Collections, "unmodifiableList", [java::util::List, java::util::List]
|
|
707
944
|
else
|
|
708
945
|
# elements, as non-expressions
|
|
709
946
|
# TODO: ensure they're all reference types!
|
|
710
|
-
node.
|
|
711
|
-
n
|
|
947
|
+
node.values.each do |n|
|
|
948
|
+
visit(n, true)
|
|
712
949
|
# TODO this feels like it should be in the node.compile itself
|
|
713
|
-
if n.
|
|
714
|
-
n.
|
|
950
|
+
if inferred_type(n).primitive?
|
|
951
|
+
inferred_type(n).box(@method)
|
|
715
952
|
end
|
|
716
953
|
end
|
|
717
954
|
end
|
|
718
955
|
end
|
|
719
|
-
|
|
720
|
-
def
|
|
721
|
-
|
|
956
|
+
|
|
957
|
+
def visitHash(node, expression)
|
|
958
|
+
set_position(node.position)
|
|
959
|
+
if expression
|
|
960
|
+
# create basic arraylist
|
|
961
|
+
@method.new java::util::HashMap
|
|
962
|
+
@method.dup
|
|
963
|
+
@method.ldc_int [node.size / 0.75, 16].max.to_i
|
|
964
|
+
@method.invokespecial java::util::HashMap, "<init>", [@method.void, @method.int]
|
|
965
|
+
|
|
966
|
+
node.each do |e|
|
|
967
|
+
@method.dup
|
|
968
|
+
[e.key, e.value].each do |n|
|
|
969
|
+
visit(n, true)
|
|
970
|
+
# TODO this feels like it should be in the node.compile itself
|
|
971
|
+
if inferred_type(n).primitive?
|
|
972
|
+
inferred_type(n).box(@method)
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
@method.invokeinterface java::util::Map, "put", [@method.object, @method.object, @method.object]
|
|
976
|
+
@method.pop
|
|
977
|
+
end
|
|
978
|
+
else
|
|
979
|
+
# elements, as non-expressions
|
|
980
|
+
node.each do |n|
|
|
981
|
+
visit(n.key, false)
|
|
982
|
+
visit(n.value, false)
|
|
983
|
+
end
|
|
984
|
+
end
|
|
722
985
|
end
|
|
723
|
-
|
|
986
|
+
|
|
987
|
+
def visitNot(node, expression)
|
|
988
|
+
visit(node.value, expression)
|
|
989
|
+
if expression
|
|
990
|
+
set_position(node.position)
|
|
991
|
+
type = inferred_type(node.value)
|
|
992
|
+
done = @method.label
|
|
993
|
+
else_label = @method.label
|
|
994
|
+
if type.primitive?
|
|
995
|
+
@method.ifeq else_label
|
|
996
|
+
else
|
|
997
|
+
@method.ifnull else_label
|
|
998
|
+
end
|
|
999
|
+
@method.iconst_0
|
|
1000
|
+
@method.goto done
|
|
1001
|
+
else_label.set!
|
|
1002
|
+
@method.iconst_1
|
|
1003
|
+
done.set!
|
|
1004
|
+
end
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
def visitNull(node, expression)
|
|
1008
|
+
if expression
|
|
1009
|
+
set_position(node.position)
|
|
1010
|
+
@method.aconst_null
|
|
1011
|
+
end
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
def visitImplicitNil(node, expression)
|
|
1015
|
+
visitNull(node, expression)
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
def visitBindingReference(node, expression)
|
|
1019
|
+
binding_reference
|
|
1020
|
+
end
|
|
1021
|
+
|
|
724
1022
|
def binding_reference
|
|
725
1023
|
@method.aload(@method.local('$binding'))
|
|
726
1024
|
end
|
|
727
|
-
|
|
1025
|
+
|
|
728
1026
|
def real_self
|
|
729
1027
|
method.aload(0)
|
|
730
1028
|
end
|
|
731
|
-
|
|
732
|
-
def
|
|
733
|
-
|
|
1029
|
+
|
|
1030
|
+
def set_position(position)
|
|
1031
|
+
# TODO support positions from multiple files
|
|
1032
|
+
@method.line(position.start_line - 1) if @method && position
|
|
734
1033
|
end
|
|
735
|
-
|
|
1034
|
+
|
|
736
1035
|
def print(print_node)
|
|
737
1036
|
@method.getstatic System, "out", PrintStream
|
|
738
|
-
print_node.parameters.each {|param| param
|
|
739
|
-
params = print_node.parameters.map {|param| param.
|
|
1037
|
+
print_node.parameters.each {|param| visit(param, true)}
|
|
1038
|
+
params = print_node.parameters.map {|param| inferred_type(param).jvm_type}
|
|
740
1039
|
method_name = print_node.println ? "println" : "print"
|
|
741
|
-
method = find_method(PrintStream.java_class, method_name, params, false)
|
|
1040
|
+
method = find_method(PrintStream.java_class, method_name, params, nil, false)
|
|
742
1041
|
if (method)
|
|
743
1042
|
@method.invokevirtual(
|
|
744
1043
|
PrintStream,
|
|
@@ -749,57 +1048,63 @@ module Mirah
|
|
|
749
1048
|
fail "Could not compile"
|
|
750
1049
|
end
|
|
751
1050
|
end
|
|
752
|
-
|
|
753
|
-
def
|
|
754
|
-
return_node.value
|
|
755
|
-
handle_ensures(find_ensures(
|
|
756
|
-
return_node.
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
1051
|
+
|
|
1052
|
+
def visitReturn(return_node, expression)
|
|
1053
|
+
visit(return_node.value, true) if return_node.value
|
|
1054
|
+
handle_ensures(find_ensures(MethodDefinition))
|
|
1055
|
+
set_position return_node.position
|
|
1056
|
+
inferred_type(return_node).return(@method)
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1059
|
+
def visitRaise(node, expression)
|
|
1060
|
+
visit(node.args(0), true)
|
|
1061
|
+
set_position(node.position)
|
|
761
1062
|
@method.athrow
|
|
762
1063
|
end
|
|
763
|
-
|
|
764
|
-
def
|
|
1064
|
+
|
|
1065
|
+
def visitRescue(rescue_node, expression)
|
|
765
1066
|
start = @method.label.set!
|
|
766
1067
|
body_end = @method.label
|
|
767
1068
|
done = @method.label
|
|
768
|
-
rescue_node.body
|
|
1069
|
+
visit(rescue_node.body, expression && rescue_node.else_clause.size == 0)
|
|
769
1070
|
body_end.set!
|
|
770
|
-
rescue_node.
|
|
1071
|
+
visit(rescue_node.else_clause, expression) if rescue_node.else_clause.size > 0
|
|
771
1072
|
return if start.label.offset == body_end.label.offset
|
|
772
1073
|
@method.goto(done)
|
|
773
1074
|
rescue_node.clauses.each do |clause|
|
|
774
1075
|
target = @method.label.set!
|
|
775
1076
|
if clause.name
|
|
776
|
-
|
|
1077
|
+
types = clause.types.map {|t| inferred_type(t)}
|
|
1078
|
+
widened_type = types.inject {|a, b| a.widen(b)}
|
|
1079
|
+
@method.astore(declare_local(introduced_scope(clause), clause.name.identifier, widened_type))
|
|
777
1080
|
else
|
|
778
1081
|
@method.pop
|
|
779
1082
|
end
|
|
780
|
-
declare_locals(clause
|
|
781
|
-
clause.body
|
|
1083
|
+
declare_locals(introduced_scope(clause))
|
|
1084
|
+
visit(clause.body, expression)
|
|
782
1085
|
@method.goto(done)
|
|
783
1086
|
clause.types.each do |type|
|
|
1087
|
+
type = inferred_type(type)
|
|
784
1088
|
@method.trycatch(start, body_end, target, type)
|
|
785
1089
|
end
|
|
786
1090
|
end
|
|
787
1091
|
done.set!
|
|
788
1092
|
end
|
|
789
|
-
|
|
1093
|
+
|
|
790
1094
|
def handle_ensures(nodes)
|
|
791
1095
|
nodes.each do |ensure_node|
|
|
792
|
-
ensure_node.
|
|
1096
|
+
visit(ensure_node.ensureClause, false)
|
|
793
1097
|
end
|
|
794
1098
|
end
|
|
795
|
-
|
|
796
|
-
def
|
|
797
|
-
|
|
1099
|
+
|
|
1100
|
+
def visitEnsure(node, expression)
|
|
1101
|
+
# TODO this doesn't appear to be used
|
|
1102
|
+
#node.state = @method.label # Save the ensure target for JumpNodes
|
|
798
1103
|
start = @method.label.set!
|
|
799
1104
|
body_end = @method.label
|
|
800
1105
|
done = @method.label
|
|
801
1106
|
push_jump_scope(node) do
|
|
802
|
-
node.body
|
|
1107
|
+
visit(node.body, expression) # First compile the body
|
|
803
1108
|
end
|
|
804
1109
|
body_end.set!
|
|
805
1110
|
handle_ensures([node]) # run the ensure clause
|
|
@@ -810,27 +1115,34 @@ module Mirah
|
|
|
810
1115
|
@method.athrow
|
|
811
1116
|
done.set!
|
|
812
1117
|
end
|
|
813
|
-
|
|
814
|
-
def
|
|
815
|
-
|
|
816
|
-
|
|
1118
|
+
|
|
1119
|
+
def visitEmptyArray(node, expression)
|
|
1120
|
+
if expression
|
|
1121
|
+
visit(node.size, true)
|
|
1122
|
+
type = @typer.type_system.get(@scoper.getScope(node), node.type).resolve
|
|
1123
|
+
type.newarray(@method)
|
|
1124
|
+
end
|
|
817
1125
|
end
|
|
818
|
-
|
|
1126
|
+
|
|
819
1127
|
class ClosureCompiler < JVMBytecode
|
|
820
|
-
def initialize(file, type, parent)
|
|
1128
|
+
def initialize(config, file, type, parent, scoper, typer)
|
|
1129
|
+
super(config, scoper, typer)
|
|
821
1130
|
@file = file
|
|
822
1131
|
@type = type
|
|
823
1132
|
@jump_scope = []
|
|
824
1133
|
@parent = parent
|
|
825
1134
|
end
|
|
826
|
-
|
|
827
|
-
def prepare_binding(
|
|
1135
|
+
|
|
1136
|
+
def prepare_binding(node)
|
|
1137
|
+
scope = introduced_scope(node)
|
|
828
1138
|
if scope.has_binding?
|
|
829
1139
|
type = scope.binding_type
|
|
830
1140
|
@binding = @parent.get_binding(type)
|
|
831
1141
|
@method.aload 0
|
|
832
1142
|
@method.getfield(@class, 'binding', @binding)
|
|
833
1143
|
type.store(@method, @method.local('$binding', type))
|
|
1144
|
+
else
|
|
1145
|
+
log "No binding for #{node} (#{scope.has_binding?} #{scope.parent} #{scope.parent && scope.parent.has_binding?})"
|
|
834
1146
|
end
|
|
835
1147
|
begin
|
|
836
1148
|
yield
|
|
@@ -840,7 +1152,7 @@ module Mirah
|
|
|
840
1152
|
end
|
|
841
1153
|
end
|
|
842
1154
|
end
|
|
843
|
-
|
|
1155
|
+
|
|
844
1156
|
def declared_captures
|
|
845
1157
|
@parent.declared_captures(@binding)
|
|
846
1158
|
end
|
|
@@ -848,4 +1160,4 @@ module Mirah
|
|
|
848
1160
|
end
|
|
849
1161
|
end
|
|
850
1162
|
end
|
|
851
|
-
end
|
|
1163
|
+
end
|