mirah 0.0.4-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/History.txt +15 -0
  2. data/README.txt +51 -0
  3. data/Rakefile +86 -0
  4. data/bin/duby +10 -0
  5. data/bin/dubyc +10 -0
  6. data/bin/dubyp +10 -0
  7. data/bin/jrubyp +36 -0
  8. data/bin/mirah +9 -0
  9. data/bin/mirah.cmd +1 -0
  10. data/bin/mirahc +9 -0
  11. data/bin/mirahc.cmd +1 -0
  12. data/bin/mirahp +9 -0
  13. data/bin/mirahp.cmd +1 -0
  14. data/examples/ant/example-build.xml +7 -0
  15. data/examples/appengine/Rakefile +19 -0
  16. data/examples/appengine/Readme +29 -0
  17. data/examples/appengine/src/org/mirah/MirahApp.mirah +57 -0
  18. data/examples/appengine/src/org/mirah/list.dhtml +15 -0
  19. data/examples/appengine/war/WEB-INF/lib/dubydatastore.jar +0 -0
  20. data/examples/bintrees.mirah +66 -0
  21. data/examples/construction.mirah +8 -0
  22. data/examples/dynamic.mirah +17 -0
  23. data/examples/edb.mirah +3 -0
  24. data/examples/fib.mirah +16 -0
  25. data/examples/fields.mirah +22 -0
  26. data/examples/fractal.mirah +55 -0
  27. data/examples/java_thing.mirah +13 -0
  28. data/examples/plugins/appengine/Rakefile +55 -0
  29. data/examples/plugins/appengine/lib/com/google/appengine/ext/duby/db/datastore.rb +375 -0
  30. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +336 -0
  31. data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +113 -0
  32. data/examples/simple_class.mirah +12 -0
  33. data/examples/sort_closure.mirah +7 -0
  34. data/examples/swing.mirah +20 -0
  35. data/examples/tak.mirah +15 -0
  36. data/examples/test.edb +9 -0
  37. data/examples/wiki/Rakefile +18 -0
  38. data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +324 -0
  39. data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +42 -0
  40. data/examples/wiki/src/org/mirah/wiki/error.eduby.html +2 -0
  41. data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +69 -0
  42. data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +7 -0
  43. data/examples/wiki/src/org/mirah/wiki/view.eduby.html +15 -0
  44. data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
  45. data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
  46. data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
  47. data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
  48. data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
  49. data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
  50. data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
  51. data/examples/wiki/war/app.yaml +21 -0
  52. data/examples/wiki/war/public/favicon.ico +0 -0
  53. data/examples/wiki/war/public/images/appengine_duby.png +0 -0
  54. data/examples/wiki/war/public/images/back.gif +0 -0
  55. data/examples/wiki/war/public/images/dir.gif +0 -0
  56. data/examples/wiki/war/public/images/file.gif +0 -0
  57. data/examples/wiki/war/public/javascripts/prettify.js +61 -0
  58. data/examples/wiki/war/public/robots.txt +0 -0
  59. data/examples/wiki/war/public/stylesheets/main.css +156 -0
  60. data/examples/wiki/war/public/stylesheets/prettify.css +1 -0
  61. data/examples/wiki/war/public/stylesheets/sh_style.css +66 -0
  62. data/examples/wiki/war/public/stylesheets/source.css +21 -0
  63. data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
  64. data/examples/wiki/war/public/wmd/images/bg.png +0 -0
  65. data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
  66. data/examples/wiki/war/public/wmd/images/bold.png +0 -0
  67. data/examples/wiki/war/public/wmd/images/code.png +0 -0
  68. data/examples/wiki/war/public/wmd/images/h1.png +0 -0
  69. data/examples/wiki/war/public/wmd/images/hr.png +0 -0
  70. data/examples/wiki/war/public/wmd/images/img.png +0 -0
  71. data/examples/wiki/war/public/wmd/images/italic.png +0 -0
  72. data/examples/wiki/war/public/wmd/images/link.png +0 -0
  73. data/examples/wiki/war/public/wmd/images/ol.png +0 -0
  74. data/examples/wiki/war/public/wmd/images/redo.png +0 -0
  75. data/examples/wiki/war/public/wmd/images/separator.png +0 -0
  76. data/examples/wiki/war/public/wmd/images/ul.png +0 -0
  77. data/examples/wiki/war/public/wmd/images/undo.png +0 -0
  78. data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
  79. data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
  80. data/examples/wiki/war/public/wmd/showdown.js +421 -0
  81. data/examples/wiki/war/public/wmd/wmd-base.js +1799 -0
  82. data/examples/wiki/war/public/wmd/wmd-plus.js +311 -0
  83. data/examples/wiki/war/public/wmd/wmd.js +73 -0
  84. data/javalib/JRubyParser.jar +0 -0
  85. data/javalib/dynalang-invoke-0.1.jar +0 -0
  86. data/javalib/mirah-bootstrap.jar +0 -0
  87. data/javalib/mirah-parser.jar +0 -0
  88. data/lib/duby.rb +2 -0
  89. data/lib/mirah.rb +338 -0
  90. data/lib/mirah/appengine_tasks.rb +146 -0
  91. data/lib/mirah/ast.rb +615 -0
  92. data/lib/mirah/ast/call.rb +307 -0
  93. data/lib/mirah/ast/class.rb +311 -0
  94. data/lib/mirah/ast/flow.rb +364 -0
  95. data/lib/mirah/ast/intrinsics.rb +470 -0
  96. data/lib/mirah/ast/literal.rb +154 -0
  97. data/lib/mirah/ast/local.rb +89 -0
  98. data/lib/mirah/ast/method.rb +360 -0
  99. data/lib/mirah/ast/scope.rb +208 -0
  100. data/lib/mirah/ast/structure.rb +226 -0
  101. data/lib/mirah/ast/type.rb +130 -0
  102. data/lib/mirah/compiler.rb +341 -0
  103. data/lib/mirah/env.rb +33 -0
  104. data/lib/mirah/jvm/base.rb +258 -0
  105. data/lib/mirah/jvm/compiler.rb +885 -0
  106. data/lib/mirah/jvm/method_lookup.rb +203 -0
  107. data/lib/mirah/jvm/source_compiler.rb +737 -0
  108. data/lib/mirah/jvm/source_generator/builder.rb +444 -0
  109. data/lib/mirah/jvm/source_generator/loops.rb +110 -0
  110. data/lib/mirah/jvm/source_generator/precompile.rb +188 -0
  111. data/lib/mirah/jvm/source_generator/typer.rb +11 -0
  112. data/lib/mirah/jvm/typer.rb +151 -0
  113. data/lib/mirah/jvm/types.rb +416 -0
  114. data/lib/mirah/jvm/types/basic_types.rb +33 -0
  115. data/lib/mirah/jvm/types/boolean.rb +17 -0
  116. data/lib/mirah/jvm/types/enumerable.rb +65 -0
  117. data/lib/mirah/jvm/types/extensions.rb +86 -0
  118. data/lib/mirah/jvm/types/factory.rb +186 -0
  119. data/lib/mirah/jvm/types/floats.rb +86 -0
  120. data/lib/mirah/jvm/types/integers.rb +171 -0
  121. data/lib/mirah/jvm/types/intrinsics.rb +376 -0
  122. data/lib/mirah/jvm/types/literals.rb +74 -0
  123. data/lib/mirah/jvm/types/methods.rb +614 -0
  124. data/lib/mirah/jvm/types/number.rb +143 -0
  125. data/lib/mirah/nbcompiler.rb +29 -0
  126. data/lib/mirah/plugin/edb.rb +29 -0
  127. data/lib/mirah/plugin/gwt.rb +173 -0
  128. data/lib/mirah/plugin/java.rb +55 -0
  129. data/lib/mirah/transform.rb +266 -0
  130. data/lib/mirah/transform2.rb +728 -0
  131. data/lib/mirah/typer.rb +407 -0
  132. data/lib/mirah_task.rb +107 -0
  133. data/test/test_ast.rb +359 -0
  134. data/test/test_compilation.rb +112 -0
  135. data/test/test_env.rb +42 -0
  136. data/test/test_gwt.rb +58 -0
  137. data/test/test_java_typer.rb +183 -0
  138. data/test/test_javac_compiler.rb +63 -0
  139. data/test/test_jvm_compiler.rb +2607 -0
  140. data/test/test_typer.rb +221 -0
  141. 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