mirah 0.0.4-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 +15 -0
- data/README.txt +51 -0
- data/Rakefile +86 -0
- data/bin/duby +10 -0
- data/bin/dubyc +10 -0
- data/bin/dubyp +10 -0
- data/bin/jrubyp +36 -0
- data/bin/mirah +9 -0
- data/bin/mirah.cmd +1 -0
- data/bin/mirahc +9 -0
- data/bin/mirahc.cmd +1 -0
- data/bin/mirahp +9 -0
- data/bin/mirahp.cmd +1 -0
- data/examples/ant/example-build.xml +7 -0
- data/examples/appengine/Rakefile +19 -0
- data/examples/appengine/Readme +29 -0
- data/examples/appengine/src/org/mirah/MirahApp.mirah +57 -0
- data/examples/appengine/src/org/mirah/list.dhtml +15 -0
- data/examples/appengine/war/WEB-INF/lib/dubydatastore.jar +0 -0
- data/examples/bintrees.mirah +66 -0
- data/examples/construction.mirah +8 -0
- data/examples/dynamic.mirah +17 -0
- data/examples/edb.mirah +3 -0
- data/examples/fib.mirah +16 -0
- data/examples/fields.mirah +22 -0
- data/examples/fractal.mirah +55 -0
- data/examples/java_thing.mirah +13 -0
- data/examples/plugins/appengine/Rakefile +55 -0
- data/examples/plugins/appengine/lib/com/google/appengine/ext/duby/db/datastore.rb +375 -0
- data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +336 -0
- data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +113 -0
- data/examples/simple_class.mirah +12 -0
- data/examples/sort_closure.mirah +7 -0
- data/examples/swing.mirah +20 -0
- data/examples/tak.mirah +15 -0
- data/examples/test.edb +9 -0
- data/examples/wiki/Rakefile +18 -0
- data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +324 -0
- data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +42 -0
- data/examples/wiki/src/org/mirah/wiki/error.eduby.html +2 -0
- data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +69 -0
- data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +7 -0
- data/examples/wiki/src/org/mirah/wiki/view.eduby.html +15 -0
- data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
- data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
- data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
- data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
- data/examples/wiki/war/app.yaml +21 -0
- data/examples/wiki/war/public/favicon.ico +0 -0
- data/examples/wiki/war/public/images/appengine_duby.png +0 -0
- data/examples/wiki/war/public/images/back.gif +0 -0
- data/examples/wiki/war/public/images/dir.gif +0 -0
- data/examples/wiki/war/public/images/file.gif +0 -0
- data/examples/wiki/war/public/javascripts/prettify.js +61 -0
- data/examples/wiki/war/public/robots.txt +0 -0
- data/examples/wiki/war/public/stylesheets/main.css +156 -0
- data/examples/wiki/war/public/stylesheets/prettify.css +1 -0
- data/examples/wiki/war/public/stylesheets/sh_style.css +66 -0
- data/examples/wiki/war/public/stylesheets/source.css +21 -0
- data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
- data/examples/wiki/war/public/wmd/images/bg.png +0 -0
- data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
- data/examples/wiki/war/public/wmd/images/bold.png +0 -0
- data/examples/wiki/war/public/wmd/images/code.png +0 -0
- data/examples/wiki/war/public/wmd/images/h1.png +0 -0
- data/examples/wiki/war/public/wmd/images/hr.png +0 -0
- data/examples/wiki/war/public/wmd/images/img.png +0 -0
- data/examples/wiki/war/public/wmd/images/italic.png +0 -0
- data/examples/wiki/war/public/wmd/images/link.png +0 -0
- data/examples/wiki/war/public/wmd/images/ol.png +0 -0
- data/examples/wiki/war/public/wmd/images/redo.png +0 -0
- data/examples/wiki/war/public/wmd/images/separator.png +0 -0
- data/examples/wiki/war/public/wmd/images/ul.png +0 -0
- data/examples/wiki/war/public/wmd/images/undo.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
- data/examples/wiki/war/public/wmd/showdown.js +421 -0
- data/examples/wiki/war/public/wmd/wmd-base.js +1799 -0
- data/examples/wiki/war/public/wmd/wmd-plus.js +311 -0
- data/examples/wiki/war/public/wmd/wmd.js +73 -0
- data/javalib/JRubyParser.jar +0 -0
- data/javalib/dynalang-invoke-0.1.jar +0 -0
- data/javalib/mirah-bootstrap.jar +0 -0
- data/javalib/mirah-parser.jar +0 -0
- data/lib/duby.rb +2 -0
- data/lib/mirah.rb +338 -0
- data/lib/mirah/appengine_tasks.rb +146 -0
- data/lib/mirah/ast.rb +615 -0
- data/lib/mirah/ast/call.rb +307 -0
- data/lib/mirah/ast/class.rb +311 -0
- data/lib/mirah/ast/flow.rb +364 -0
- data/lib/mirah/ast/intrinsics.rb +470 -0
- data/lib/mirah/ast/literal.rb +154 -0
- data/lib/mirah/ast/local.rb +89 -0
- data/lib/mirah/ast/method.rb +360 -0
- data/lib/mirah/ast/scope.rb +208 -0
- data/lib/mirah/ast/structure.rb +226 -0
- data/lib/mirah/ast/type.rb +130 -0
- data/lib/mirah/compiler.rb +341 -0
- data/lib/mirah/env.rb +33 -0
- data/lib/mirah/jvm/base.rb +258 -0
- data/lib/mirah/jvm/compiler.rb +885 -0
- data/lib/mirah/jvm/method_lookup.rb +203 -0
- data/lib/mirah/jvm/source_compiler.rb +737 -0
- data/lib/mirah/jvm/source_generator/builder.rb +444 -0
- data/lib/mirah/jvm/source_generator/loops.rb +110 -0
- data/lib/mirah/jvm/source_generator/precompile.rb +188 -0
- data/lib/mirah/jvm/source_generator/typer.rb +11 -0
- data/lib/mirah/jvm/typer.rb +151 -0
- data/lib/mirah/jvm/types.rb +416 -0
- data/lib/mirah/jvm/types/basic_types.rb +33 -0
- data/lib/mirah/jvm/types/boolean.rb +17 -0
- data/lib/mirah/jvm/types/enumerable.rb +65 -0
- data/lib/mirah/jvm/types/extensions.rb +86 -0
- data/lib/mirah/jvm/types/factory.rb +186 -0
- data/lib/mirah/jvm/types/floats.rb +86 -0
- data/lib/mirah/jvm/types/integers.rb +171 -0
- data/lib/mirah/jvm/types/intrinsics.rb +376 -0
- data/lib/mirah/jvm/types/literals.rb +74 -0
- data/lib/mirah/jvm/types/methods.rb +614 -0
- data/lib/mirah/jvm/types/number.rb +143 -0
- data/lib/mirah/nbcompiler.rb +29 -0
- data/lib/mirah/plugin/edb.rb +29 -0
- data/lib/mirah/plugin/gwt.rb +173 -0
- data/lib/mirah/plugin/java.rb +55 -0
- data/lib/mirah/transform.rb +266 -0
- data/lib/mirah/transform2.rb +728 -0
- data/lib/mirah/typer.rb +407 -0
- data/lib/mirah_task.rb +107 -0
- data/test/test_ast.rb +359 -0
- data/test/test_compilation.rb +112 -0
- data/test/test_env.rb +42 -0
- data/test/test_gwt.rb +58 -0
- data/test/test_java_typer.rb +183 -0
- data/test/test_javac_compiler.rb +63 -0
- data/test/test_jvm_compiler.rb +2607 -0
- data/test/test_typer.rb +221 -0
- metadata +235 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
module Duby
|
|
2
|
+
module JVM
|
|
3
|
+
module MethodLookup
|
|
4
|
+
# dummy log; it's expected the inclusion target will have it
|
|
5
|
+
def log(msg); end
|
|
6
|
+
|
|
7
|
+
def find_method(mapped_type, name, mapped_params, meta)
|
|
8
|
+
raise ArgumentError if mapped_params.any? {|p| p.nil?}
|
|
9
|
+
if name == 'new'
|
|
10
|
+
if meta
|
|
11
|
+
name = "<init>"
|
|
12
|
+
constructor = true
|
|
13
|
+
else
|
|
14
|
+
constructor = false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
if constructor
|
|
20
|
+
method = mapped_type.constructor(*mapped_params)
|
|
21
|
+
else
|
|
22
|
+
method = mapped_type.java_method(name, *mapped_params)
|
|
23
|
+
end
|
|
24
|
+
rescue NameError
|
|
25
|
+
# exact args failed, do a deeper search
|
|
26
|
+
log "No exact match for #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})"
|
|
27
|
+
|
|
28
|
+
method = find_jls(mapped_type, name, mapped_params, meta, constructor)
|
|
29
|
+
|
|
30
|
+
unless method
|
|
31
|
+
log "Failed to locate method #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})"
|
|
32
|
+
return nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
log "Found method #{method.declaring_class.name}.#{name}(#{method.argument_types.map(&:name).join ', '}) from #{mapped_type.name}"
|
|
37
|
+
return method
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def find_jls(mapped_type, name, mapped_params, meta, constructor)
|
|
41
|
+
if constructor
|
|
42
|
+
by_name = mapped_type.unmeta.declared_constructors
|
|
43
|
+
elsif meta
|
|
44
|
+
by_name = mapped_type.declared_class_methods(name)
|
|
45
|
+
else
|
|
46
|
+
by_name = []
|
|
47
|
+
cls = mapped_type
|
|
48
|
+
while cls
|
|
49
|
+
by_name += cls.declared_instance_methods(name)
|
|
50
|
+
cls = cls.superclass
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
# filter by arity
|
|
54
|
+
by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size}
|
|
55
|
+
|
|
56
|
+
phase1_methods = phase1(mapped_params, by_name_and_arity)
|
|
57
|
+
|
|
58
|
+
if phase1_methods.size > 1
|
|
59
|
+
method_list = phase1_methods.map do |m|
|
|
60
|
+
|
|
61
|
+
"#{m.name}(#{m.parameter_types.map(&:name).join(', ')})"
|
|
62
|
+
end.join("\n")
|
|
63
|
+
raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{method_list}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
phase1_methods[0] ||
|
|
67
|
+
phase2(mapped_params, by_name) ||
|
|
68
|
+
phase3(mapped_params, by_name) ||
|
|
69
|
+
field_lookup(mapped_params, mapped_type, meta, name) ||
|
|
70
|
+
inner_class(mapped_params, mapped_type, meta, name)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def phase1(mapped_params, potentials)
|
|
74
|
+
log "Beginning JLS phase 1 search with params (#{mapped_params.map(&:name)})"
|
|
75
|
+
|
|
76
|
+
# cycle through methods looking for more specific matches; gather matches of equal specificity
|
|
77
|
+
methods = potentials.inject([]) do |currents, potential|
|
|
78
|
+
method_params = potential.argument_types
|
|
79
|
+
raise "Bad arguments for method #{potential.declaring_class}.#{potential.name}" unless method_params.all?
|
|
80
|
+
|
|
81
|
+
# exact match always wins; duplicates not possible
|
|
82
|
+
if each_is_exact(mapped_params, method_params)
|
|
83
|
+
return [potential]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# otherwise, check for potential match and compare to current
|
|
87
|
+
# TODO: missing ambiguity check; picks last method of equal specificity
|
|
88
|
+
if each_is_exact_or_subtype_or_convertible(mapped_params, method_params)
|
|
89
|
+
if currents.size > 0
|
|
90
|
+
if is_more_specific?(potential.argument_types, currents[0].argument_types)
|
|
91
|
+
# potential is better, dump all currents
|
|
92
|
+
currents = [potential]
|
|
93
|
+
elsif is_more_specific?(currents[0].argument_types, potential.argument_types)
|
|
94
|
+
# currents are better, try next potential
|
|
95
|
+
#next
|
|
96
|
+
else
|
|
97
|
+
# equal specificity, append to currents
|
|
98
|
+
currents << potential
|
|
99
|
+
end
|
|
100
|
+
else
|
|
101
|
+
# no previous matches, use potential
|
|
102
|
+
currents = [potential]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
currents
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
methods
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def is_more_specific?(potential, current)
|
|
113
|
+
each_is_exact_or_subtype_or_convertible(potential, current)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def phase2(mapped_params, potentials)
|
|
117
|
+
nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def phase3(mapped_params, potentials)
|
|
121
|
+
nil
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def field_lookup(mapped_params, mapped_type, meta, name)
|
|
125
|
+
log("Attempting #{meta ? 'static' : 'instance'} field lookup for '#{name}' on class #{mapped_type}")
|
|
126
|
+
# if we get to this point, the potentials do not match, so we ignore them
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# search for a field of the given name
|
|
130
|
+
if name =~ /_set$/
|
|
131
|
+
# setter
|
|
132
|
+
setter = true
|
|
133
|
+
name = name[0..-5]
|
|
134
|
+
field = mapped_type.field_setter(name)
|
|
135
|
+
else
|
|
136
|
+
# getter
|
|
137
|
+
setter = false
|
|
138
|
+
|
|
139
|
+
# field accesses don't take arguments
|
|
140
|
+
return if mapped_params.size > 0
|
|
141
|
+
field = mapped_type.field_getter(name)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
return nil unless field
|
|
145
|
+
|
|
146
|
+
if (meta && !field.static?) ||
|
|
147
|
+
(!meta && field.static?)
|
|
148
|
+
field == nil
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# check accessibility
|
|
152
|
+
# TODO: protected field access check appropriate to current type
|
|
153
|
+
if setter
|
|
154
|
+
raise "cannot set final field '#{name}' on class #{mapped_type}" if field.final?
|
|
155
|
+
end
|
|
156
|
+
raise "cannot access field '#{name}' on class #{mapped_type}" unless field.public?
|
|
157
|
+
|
|
158
|
+
field
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def inner_class(params, type, meta, name)
|
|
162
|
+
return unless params.size == 0 && meta
|
|
163
|
+
log("Attempting inner class lookup for '#{name}' on #{type}")
|
|
164
|
+
type.inner_class_getter(name)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def each_is_exact(incoming, target)
|
|
168
|
+
incoming.each_with_index do |in_type, i|
|
|
169
|
+
target_type = target[i]
|
|
170
|
+
|
|
171
|
+
# exact match
|
|
172
|
+
return false unless target_type == in_type
|
|
173
|
+
end
|
|
174
|
+
return true
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def each_is_exact_or_subtype_or_convertible(incoming, target)
|
|
178
|
+
incoming.each_with_index do |in_type, i|
|
|
179
|
+
target_type = target[i]
|
|
180
|
+
|
|
181
|
+
# exact match
|
|
182
|
+
next if target_type == in_type
|
|
183
|
+
|
|
184
|
+
# primitive is safely convertible
|
|
185
|
+
if target_type.primitive?
|
|
186
|
+
if in_type.primitive?
|
|
187
|
+
next if primitive_convertible? in_type, target_type
|
|
188
|
+
end
|
|
189
|
+
return false
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# object type is assignable
|
|
193
|
+
return false unless target_type.assignable_from? in_type
|
|
194
|
+
end
|
|
195
|
+
return true
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def primitive_convertible?(in_type, target_type)
|
|
199
|
+
in_type.convertible_to?(target_type)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
require 'mirah'
|
|
2
|
+
require 'mirah/ast'
|
|
3
|
+
require 'mirah/jvm/types'
|
|
4
|
+
require 'mirah/jvm/compiler'
|
|
5
|
+
require 'mirah/jvm/source_generator/builder'
|
|
6
|
+
require 'mirah/jvm/source_generator/precompile'
|
|
7
|
+
require 'mirah/jvm/source_generator/loops'
|
|
8
|
+
|
|
9
|
+
class String
|
|
10
|
+
def compile(compiler, expression)
|
|
11
|
+
compiler.method.print self if expression
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Duby
|
|
16
|
+
module Compiler
|
|
17
|
+
class JavaSource < JVMCompilerBase
|
|
18
|
+
JVMTypes = Duby::JVM::Types
|
|
19
|
+
attr_accessor :lvalue
|
|
20
|
+
|
|
21
|
+
Operators = [
|
|
22
|
+
'+', '-', '+@', '-@', '/', '%', '*', '<',
|
|
23
|
+
'<=', '==', '!=', '>=', '>',
|
|
24
|
+
'<<', '>>', '>>>', '|', '&', '^', '~'
|
|
25
|
+
]
|
|
26
|
+
ArrayOps = [
|
|
27
|
+
'[]', '[]=', 'length'
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
ImplicitReturn = Struct.new(:value)
|
|
31
|
+
|
|
32
|
+
def initialize
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def file_builder(filename)
|
|
37
|
+
Duby::JavaSource::Builder.new(filename, self)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def output_type
|
|
41
|
+
"source files"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def define_method(node)
|
|
45
|
+
base_define_method(node, false) do |method, _|
|
|
46
|
+
with :method => method do
|
|
47
|
+
log "Starting new method #{node.name}"
|
|
48
|
+
@method.start
|
|
49
|
+
|
|
50
|
+
prepare_binding(node) do
|
|
51
|
+
declare_locals(node.static_scope)
|
|
52
|
+
unless @method.type.nil? || @method.type.void?
|
|
53
|
+
self.return(ImplicitReturn.new(node.body))
|
|
54
|
+
else
|
|
55
|
+
node.body.compile(self, false) if node.body
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
log "Method #{node.name} complete!"
|
|
60
|
+
@method.stop
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def annotate(node, annotations)
|
|
66
|
+
node.annotate(annotations)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def define_optarg_chain(name, arg, return_type,
|
|
70
|
+
args_for_opt, arg_types_for_opt)
|
|
71
|
+
# declare all args so they get their values
|
|
72
|
+
@method.print "return " unless @method.type.nil? || @method.type.void?
|
|
73
|
+
@method.print "this." unless @static
|
|
74
|
+
@method.print "#{name}("
|
|
75
|
+
@method.print args_for_opt.map(&:name).join(', ')
|
|
76
|
+
@method.print ', 'if args_for_opt.size > 0
|
|
77
|
+
arg.value.compile(self, true)
|
|
78
|
+
|
|
79
|
+
# invoke the next one in the chain
|
|
80
|
+
@method.print ");\n"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def constructor(node)
|
|
84
|
+
super(node, false) do |method, _|
|
|
85
|
+
with :method => method do
|
|
86
|
+
@method.start
|
|
87
|
+
if node.delegate_args
|
|
88
|
+
delegate = if node.calls_super
|
|
89
|
+
"super"
|
|
90
|
+
else
|
|
91
|
+
"this"
|
|
92
|
+
end
|
|
93
|
+
method.print "#{delegate}("
|
|
94
|
+
node.delegate_args.each_with_index do |arg, index|
|
|
95
|
+
method.print ', ' unless index == 0
|
|
96
|
+
raise "Invalid constructor argument #{arg}" unless arg.expr?(self)
|
|
97
|
+
arg.compile(self, true)
|
|
98
|
+
end
|
|
99
|
+
method.puts ");"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
prepare_binding(node) do
|
|
103
|
+
declare_locals(node.static_scope)
|
|
104
|
+
node.body.compile(self, false) if node.body
|
|
105
|
+
end
|
|
106
|
+
method.stop
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def prepare_binding(scope)
|
|
112
|
+
if scope.has_binding?
|
|
113
|
+
type = scope.binding_type
|
|
114
|
+
@binding = @bindings[type]
|
|
115
|
+
@method.puts "#{type.to_source} $binding = new #{type.to_source}();"
|
|
116
|
+
end
|
|
117
|
+
begin
|
|
118
|
+
yield
|
|
119
|
+
ensure
|
|
120
|
+
if scope.has_binding?
|
|
121
|
+
@binding.stop
|
|
122
|
+
@binding = nil
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def define_closure(class_def, expression)
|
|
128
|
+
compiler = ClosureCompiler.new(@file, @type, self)
|
|
129
|
+
compiler.define_class(class_def, expression)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def return(node)
|
|
133
|
+
if @method.type.nil? || @method.type.void?
|
|
134
|
+
@method.puts 'return;'
|
|
135
|
+
return
|
|
136
|
+
end
|
|
137
|
+
if node.value.expr?(self)
|
|
138
|
+
@method.print 'return '
|
|
139
|
+
node.value.compile(self, true)
|
|
140
|
+
@method.puts ';'
|
|
141
|
+
else
|
|
142
|
+
store_value('return ', node.value)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def _raise(node)
|
|
147
|
+
if node.expr?(self)
|
|
148
|
+
@method.print 'throw '
|
|
149
|
+
node.compile(self, true)
|
|
150
|
+
@method.puts ';'
|
|
151
|
+
else
|
|
152
|
+
store_value('throw ', node)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def rescue(node, expression)
|
|
157
|
+
@method.block 'try' do
|
|
158
|
+
maybe_store(node.body, expression)
|
|
159
|
+
end
|
|
160
|
+
node.clauses.each do |clause|
|
|
161
|
+
clause.types.each do |type|
|
|
162
|
+
name = scoped_local_name(clause.name || 'tmp$ex', clause.static_scope)
|
|
163
|
+
@method.declare_local(type, name, false)
|
|
164
|
+
@method.block "catch (#{type.to_source} #{name})" do
|
|
165
|
+
declare_locals(clause.static_scope)
|
|
166
|
+
maybe_store(clause.body, expression)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def ensure(node, expression)
|
|
173
|
+
@method.block 'try' do
|
|
174
|
+
maybe_store(node.body, expression)
|
|
175
|
+
end
|
|
176
|
+
@method.block 'finally' do
|
|
177
|
+
node.clause.compile(self, false)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def line(num)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def declare_local(name, type)
|
|
185
|
+
@method.declare_local(type, name)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def declare_field(name, type, annotations)
|
|
189
|
+
@class.declare_field(name, type, @static, 'private', annotations)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def local(scope, name, type)
|
|
193
|
+
name = scoped_local_name(name, scope)
|
|
194
|
+
@method.print name
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def field(name, type, annotations)
|
|
198
|
+
name = name[1..-1] if name =~ /^@/
|
|
199
|
+
declare_field(name, type, annotations)
|
|
200
|
+
@method.print "#{this}.#{name}"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def this(method=nil)
|
|
204
|
+
if method && method.static?
|
|
205
|
+
method.declaring_class.name
|
|
206
|
+
elsif @self_scope && @self_scope.self_node
|
|
207
|
+
scoped_local_name('self', @self_scope)
|
|
208
|
+
else
|
|
209
|
+
@static ? @class.class_name : 'this'
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def declare_locals(scope)
|
|
214
|
+
scope.locals.each do |name|
|
|
215
|
+
full_name = scoped_local_name(name, scope)
|
|
216
|
+
unless scope.captured?(name) || method.local?(full_name)
|
|
217
|
+
declare_local(full_name, scope.local_type(name))
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def local_assign(scope, name, type, expression, value)
|
|
223
|
+
simple = value.expr?(self)
|
|
224
|
+
value = value.precompile(self)
|
|
225
|
+
name = scoped_local_name(name, scope)
|
|
226
|
+
if method.local?(name)
|
|
227
|
+
if expression
|
|
228
|
+
if simple
|
|
229
|
+
@method.print '('
|
|
230
|
+
else
|
|
231
|
+
@method.print @lvalue
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
@method.print "#{name} = "
|
|
235
|
+
value.compile(self, true)
|
|
236
|
+
if simple && expression
|
|
237
|
+
@method.print ')'
|
|
238
|
+
else
|
|
239
|
+
@method.puts ';'
|
|
240
|
+
end
|
|
241
|
+
else
|
|
242
|
+
@method.declare_local(type, name) do
|
|
243
|
+
value.compile(self, true)
|
|
244
|
+
end
|
|
245
|
+
if expression
|
|
246
|
+
@method.puts "#{@lvalue}#{name};"
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def field_declare(name, type, annotations)
|
|
252
|
+
name = name[1..-1] if name =~ /^@/
|
|
253
|
+
declare_field(name, type, annotations)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def local_declare(scope, name, type)
|
|
257
|
+
name = scoped_local_name(name, scope)
|
|
258
|
+
declare_local(name, type)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def field_assign(name, type, expression, value, annotations)
|
|
262
|
+
name = name[1..-1] if name =~ /^@/
|
|
263
|
+
declare_field(name, type, annotations)
|
|
264
|
+
lvalue = "#{@lvalue if expression}#{this}.#{name} = "
|
|
265
|
+
store_value(lvalue, value)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def captured_local_declare(scope, name, type)
|
|
269
|
+
unless declared_captures[name]
|
|
270
|
+
declared_captures[name] = type
|
|
271
|
+
@binding.declare_field(name, type, false, '')
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def captured_local(scope, name, type)
|
|
276
|
+
captured_local_declare(scope, name, type)
|
|
277
|
+
@method.print "$binding.#{name}"
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def captured_local_assign(node, expression)
|
|
281
|
+
scope, name, type = node.containing_scope, node.name, node.inferred_type
|
|
282
|
+
captured_local_declare(scope, name, type)
|
|
283
|
+
lvalue = "#{@lvalue if expression}$binding.#{name} = "
|
|
284
|
+
store_value(lvalue, node.value)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def store_value(lvalue, value)
|
|
288
|
+
if value.is_a? String
|
|
289
|
+
@method.puts "#{lvalue}#{value};"
|
|
290
|
+
elsif value.expr?(self)
|
|
291
|
+
@method.print lvalue
|
|
292
|
+
value.compile(self, true)
|
|
293
|
+
@method.puts ';'
|
|
294
|
+
else
|
|
295
|
+
with :lvalue => lvalue do
|
|
296
|
+
value.compile(self, true)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def assign(name, value)
|
|
302
|
+
store_value("#{name} = ", value)
|
|
303
|
+
name
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def maybe_store(value, expression)
|
|
307
|
+
if expression
|
|
308
|
+
store_value(@lvalue, value)
|
|
309
|
+
else
|
|
310
|
+
value.compile(self, false)
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def body(body, expression)
|
|
315
|
+
super(body, expression) do |last|
|
|
316
|
+
maybe_store(last, expression)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def scoped_body(scope, expression)
|
|
321
|
+
@method.block do
|
|
322
|
+
super
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def branch_expression(node)
|
|
327
|
+
node.condition.compile(self, true)
|
|
328
|
+
@method.print ' ? ('
|
|
329
|
+
if node.body
|
|
330
|
+
node.body.compile(self, true)
|
|
331
|
+
else
|
|
332
|
+
@method.print @method.init_value(node.inferred_type)
|
|
333
|
+
end
|
|
334
|
+
@method.print ') : ('
|
|
335
|
+
if node.else
|
|
336
|
+
node.else.compile(self, true)
|
|
337
|
+
else
|
|
338
|
+
@method.print @method.init_value(node.inferred_type)
|
|
339
|
+
end
|
|
340
|
+
@method.print ')'
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def branch(node, expression)
|
|
344
|
+
if expression && node.expr?(self)
|
|
345
|
+
return branch_expression(node)
|
|
346
|
+
end
|
|
347
|
+
predicate = node.condition.predicate.precompile(self)
|
|
348
|
+
@method.print 'if ('
|
|
349
|
+
predicate.compile(self, true)
|
|
350
|
+
@method.block ")" do
|
|
351
|
+
if node.body
|
|
352
|
+
maybe_store(node.body, expression)
|
|
353
|
+
elsif expression
|
|
354
|
+
store_value(@lvalue, @method.init_value(node.inferred_type))
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
if node.else || expression
|
|
358
|
+
@method.block 'else' do
|
|
359
|
+
if node.else
|
|
360
|
+
maybe_store(node.else, expression)
|
|
361
|
+
else
|
|
362
|
+
store_value(@lvalue, @method.init_value(node.inferred_type))
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def loop(loop, expression)
|
|
369
|
+
if loop.redo? || loop.post || !loop.condition.predicate.expr?(self)
|
|
370
|
+
loop = ComplexWhileLoop.new(loop, self)
|
|
371
|
+
else
|
|
372
|
+
loop = SimpleWhileLoop.new(loop, self)
|
|
373
|
+
end
|
|
374
|
+
with(:loop => loop) do
|
|
375
|
+
loop.compile(expression)
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def expr?(target, params)
|
|
380
|
+
!([target] + params).any? {|x| x.kind_of? Duby::AST::TempValue}
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def operator(target, op, params, expression)
|
|
384
|
+
simple = expr?(target, params)
|
|
385
|
+
if expression && !simple
|
|
386
|
+
@method.print @lvalue
|
|
387
|
+
end
|
|
388
|
+
if params.size == 0
|
|
389
|
+
# unary operator
|
|
390
|
+
op = op[0,1]
|
|
391
|
+
@method.print op
|
|
392
|
+
target.compile(self, true)
|
|
393
|
+
else
|
|
394
|
+
@method.print '('
|
|
395
|
+
other = params[0]
|
|
396
|
+
target.compile(self, true)
|
|
397
|
+
@method.print " #{op} "
|
|
398
|
+
other.compile(self, true)
|
|
399
|
+
@method.print ')'
|
|
400
|
+
end
|
|
401
|
+
unless expression && simple
|
|
402
|
+
@method.puts ';'
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
def precompile_nodes(nodes)
|
|
407
|
+
if nodes.all? {|n| n.expr?(self)}
|
|
408
|
+
nodes
|
|
409
|
+
else
|
|
410
|
+
nodes.map do |node|
|
|
411
|
+
tempval = node.precompile(self)
|
|
412
|
+
if node == tempval && !node.kind_of?(Duby::AST::Literal)
|
|
413
|
+
tempval = node.temp(self)
|
|
414
|
+
end
|
|
415
|
+
tempval
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def compile_args(call)
|
|
421
|
+
precompile_nodes(call.parameters)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def self_type
|
|
425
|
+
type = AST.type(nil, @class.name.tr('/', '.'))
|
|
426
|
+
type = type.meta if @static
|
|
427
|
+
type
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def super_call(call, expression)
|
|
431
|
+
super_method_call(this, call, compile_args(call), expression)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def cast(call, expression)
|
|
435
|
+
args = compile_args(call)
|
|
436
|
+
simple = call.expr?(self)
|
|
437
|
+
@method.print @lvalue if expression && !simple
|
|
438
|
+
@method.print "((#{call.inferred_type.to_source})("
|
|
439
|
+
args.each{|arg| arg.compile(self, true)}
|
|
440
|
+
@method.print "))"
|
|
441
|
+
@method.puts ';' unless simple && expression
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def self_call(call, expression)
|
|
445
|
+
if call.cast?
|
|
446
|
+
cast(call, expression)
|
|
447
|
+
else
|
|
448
|
+
type = call.scope.static_scope.self_type
|
|
449
|
+
type = type.meta if (@static && type == @type)
|
|
450
|
+
params = call.parameters.map do |param|
|
|
451
|
+
param.inferred_type
|
|
452
|
+
end
|
|
453
|
+
method = type.get_method(call.name, params)
|
|
454
|
+
method_call(this(method), call, compile_args(call), expression)
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
def call(call, expression)
|
|
459
|
+
return cast(call, expression) if call.cast?
|
|
460
|
+
if Duby::AST::Constant === call.target
|
|
461
|
+
target = call.target.inferred_type.to_source
|
|
462
|
+
else
|
|
463
|
+
target = call.precompile_target(self)
|
|
464
|
+
end
|
|
465
|
+
params = compile_args(call)
|
|
466
|
+
|
|
467
|
+
if Operators.include? call.name
|
|
468
|
+
operator(target, call.name, params, expression)
|
|
469
|
+
elsif call.target.inferred_type.array? && ArrayOps.include?(call.name)
|
|
470
|
+
array_op(target, call.name, params, expression)
|
|
471
|
+
elsif call.name == 'nil?'
|
|
472
|
+
operator(target, '==', ['null'], expression)
|
|
473
|
+
else
|
|
474
|
+
method_call(target, call, params, expression)
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def array_op(target, name, args, expression)
|
|
479
|
+
simple = expr?(target, args)
|
|
480
|
+
index, value = args
|
|
481
|
+
if expression && !simple
|
|
482
|
+
@method.print @lvalue
|
|
483
|
+
end
|
|
484
|
+
target.compile(self, true)
|
|
485
|
+
if name == 'length'
|
|
486
|
+
@method.print '.length'
|
|
487
|
+
else
|
|
488
|
+
@method.print '['
|
|
489
|
+
index.compile(self, true)
|
|
490
|
+
@method.print ']'
|
|
491
|
+
if name == '[]='
|
|
492
|
+
@method.print " = "
|
|
493
|
+
value.compile(self, true)
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
unless simple && expression
|
|
497
|
+
@method.puts ';'
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def break(node)
|
|
502
|
+
error("break outside of loop", node) unless @loop
|
|
503
|
+
@loop.break
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def next(node)
|
|
507
|
+
error("next outside of loop", node) unless @loop
|
|
508
|
+
@loop.next
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
def redo(node)
|
|
512
|
+
error("redo outside of loop", node) unless @loop
|
|
513
|
+
@loop.redo
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# TODO: merge cleanly with method_call logic
|
|
517
|
+
def super_method_call(target, call, params, expression)
|
|
518
|
+
simple = call.expr?(self)
|
|
519
|
+
method = call.method(self)
|
|
520
|
+
unless simple || method.return_type.void?
|
|
521
|
+
@method.print @lvalue if expression
|
|
522
|
+
end
|
|
523
|
+
if method.constructor?
|
|
524
|
+
@method.print "super("
|
|
525
|
+
else
|
|
526
|
+
@method.print "super.#{method.name}("
|
|
527
|
+
end
|
|
528
|
+
params.each_with_index do |param, index|
|
|
529
|
+
@method.print ', ' unless index == 0
|
|
530
|
+
param.compile(self, true)
|
|
531
|
+
end
|
|
532
|
+
if simple && expression
|
|
533
|
+
@method.print ')'
|
|
534
|
+
else
|
|
535
|
+
@method.puts ');'
|
|
536
|
+
end
|
|
537
|
+
if method.return_type.void? && expression
|
|
538
|
+
@method.print @lvalue
|
|
539
|
+
if method.static?
|
|
540
|
+
@method.puts 'null;'
|
|
541
|
+
else
|
|
542
|
+
target.compile(self, true)
|
|
543
|
+
@method.puts ';'
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
def method_call(target, call, params, expression)
|
|
550
|
+
simple = call.expr?(self)
|
|
551
|
+
method = call.method(self)
|
|
552
|
+
unless simple || method.return_type.void?
|
|
553
|
+
@method.print @lvalue if expression
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
# preamble
|
|
557
|
+
if method.constructor?
|
|
558
|
+
@method.print "new "
|
|
559
|
+
target.compile(self, true)
|
|
560
|
+
@method.print '('
|
|
561
|
+
elsif method.field?
|
|
562
|
+
target.compile(self, true)
|
|
563
|
+
@method.print ".#{method.name}"
|
|
564
|
+
if method.argument_types.size == 1
|
|
565
|
+
@method.print " = ("
|
|
566
|
+
end
|
|
567
|
+
elsif Duby::JVM::Types::Intrinsic === method
|
|
568
|
+
method.call(self, call, expression)
|
|
569
|
+
return
|
|
570
|
+
else
|
|
571
|
+
target.compile(self, true)
|
|
572
|
+
@method.print ".#{method.name}("
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
# args
|
|
576
|
+
params.each_with_index do |param, index|
|
|
577
|
+
@method.print ', ' unless index == 0
|
|
578
|
+
param.compile(self, true)
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# postamble
|
|
582
|
+
if !method.field? || (method.field? && method.argument_types.size == 1)
|
|
583
|
+
if simple && expression
|
|
584
|
+
@method.print ')'
|
|
585
|
+
else
|
|
586
|
+
@method.puts ');'
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
# cleanup
|
|
591
|
+
if method.return_type.void? && expression
|
|
592
|
+
@method.print @lvalue
|
|
593
|
+
if method.static?
|
|
594
|
+
@method.puts 'null;'
|
|
595
|
+
else
|
|
596
|
+
target.compile(self, true)
|
|
597
|
+
@method.puts ';'
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def temp(expression, value=nil)
|
|
603
|
+
value ||= expression
|
|
604
|
+
type = value.inferred_type
|
|
605
|
+
if value.expr?(self)
|
|
606
|
+
@method.tmp(type) do
|
|
607
|
+
value.compile(self, true)
|
|
608
|
+
end
|
|
609
|
+
else
|
|
610
|
+
assign(@method.tmp(type), value)
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
def empty_array(type, size)
|
|
615
|
+
sizevar = size.precompile(self)
|
|
616
|
+
@method.print "#{@lvalue unless size.expr?(self)}new #{type.name}["
|
|
617
|
+
sizevar.compile(self, true)
|
|
618
|
+
@method.print ']'
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
def string(value)
|
|
622
|
+
@method.print value.inspect
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
def boolean(value)
|
|
626
|
+
@method.print value ? 'true' : 'false'
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def regexp(value, flags = 0)
|
|
630
|
+
@method.print "java.util.regex.Pattern.compile("
|
|
631
|
+
@method.print value.inspect
|
|
632
|
+
@method.print ")"
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
def array(node, expression)
|
|
636
|
+
if expression
|
|
637
|
+
# create unmodifiable list from array (simplest way to do this in Java source)
|
|
638
|
+
@method.print "java.util.Collections.unmodifiableList(java.util.Arrays.asList("
|
|
639
|
+
|
|
640
|
+
# elements, as expressions
|
|
641
|
+
comma = false
|
|
642
|
+
node.children.each do |n|
|
|
643
|
+
@method.print ", " if comma
|
|
644
|
+
n.compile(self, true)
|
|
645
|
+
comma = true
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
@method.print("))")
|
|
649
|
+
else
|
|
650
|
+
# elements, as non-expressions
|
|
651
|
+
# TODO: ensure they're all reference types!
|
|
652
|
+
node.children.each do |n|
|
|
653
|
+
n.compile(self, false)
|
|
654
|
+
end
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
def build_string(orig_nodes, expression)
|
|
659
|
+
if expression
|
|
660
|
+
nodes = precompile_nodes(orig_nodes)
|
|
661
|
+
simple = nodes.equal?(orig_nodes)
|
|
662
|
+
if !simple
|
|
663
|
+
@method.print(lvalue)
|
|
664
|
+
end
|
|
665
|
+
first = true
|
|
666
|
+
unless nodes[0].kind_of?(Duby::AST::String)
|
|
667
|
+
@method.print '""'
|
|
668
|
+
first = false
|
|
669
|
+
end
|
|
670
|
+
nodes.each do |node|
|
|
671
|
+
@method.print ' + ' unless first
|
|
672
|
+
first = false
|
|
673
|
+
node.compile(self, true)
|
|
674
|
+
end
|
|
675
|
+
@method.puts ';' unless simple
|
|
676
|
+
else
|
|
677
|
+
orig_nodes.each {|n| n.compile(self, false)}
|
|
678
|
+
end
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
def to_string(body, expression)
|
|
682
|
+
body.compile(self, expression)
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
def null
|
|
686
|
+
@method.print 'null'
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
def binding_reference
|
|
690
|
+
@method.print '$binding'
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def real_self
|
|
694
|
+
@method.print 'this'
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
def print(node)
|
|
698
|
+
value = node.parameters[0]
|
|
699
|
+
value = value && value.precompile(self)
|
|
700
|
+
if node.println
|
|
701
|
+
@method.print "System.out.println("
|
|
702
|
+
else
|
|
703
|
+
@method.print "System.out.print("
|
|
704
|
+
end
|
|
705
|
+
value.compile(self, true) if value
|
|
706
|
+
@method.puts ');'
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
class ClosureCompiler < JavaSource
|
|
710
|
+
def initialize(file, type, parent)
|
|
711
|
+
@file = file
|
|
712
|
+
@type = type
|
|
713
|
+
@parent = parent
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
def prepare_binding(scope)
|
|
717
|
+
if scope.has_binding?
|
|
718
|
+
type = scope.binding_type
|
|
719
|
+
@binding = @parent.get_binding(type)
|
|
720
|
+
@method.puts("#{type.to_source} $binding = this.binding;")
|
|
721
|
+
end
|
|
722
|
+
begin
|
|
723
|
+
yield
|
|
724
|
+
ensure
|
|
725
|
+
if scope.has_binding?
|
|
726
|
+
@binding = nil
|
|
727
|
+
end
|
|
728
|
+
end
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
def declared_captures
|
|
732
|
+
@parent.declared_captures(@binding)
|
|
733
|
+
end
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
end
|