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.
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,444 @@
1
+ require 'mirah/jvm/types'
2
+
3
+ module Duby
4
+ class JVM::Types::Type
5
+ def to_source
6
+ java_name = name
7
+ java_name = java_name.tr('$', '.')
8
+ "#{java_name}#{'[]' if array?}"
9
+ end
10
+ end
11
+
12
+ module JavaSource
13
+ JVMTypes ||= Duby::JVM::Types
14
+
15
+ class Builder
16
+ attr_accessor :package, :classes, :filename, :compiler
17
+
18
+ def initialize(filename, compiler)
19
+ @filename = filename
20
+ @classes = {}
21
+ @compiler = compiler
22
+ end
23
+
24
+ def define_class(name, opts={})
25
+ superclass = opts[:superclass]
26
+ interfaces = opts[:interfaces]
27
+ abstract = opts[:abstract]
28
+ cls = ClassBuilder.new(self, name, superclass, interfaces, abstract)
29
+ container = self
30
+ if name.include? ?$
31
+ path = name.split '$'
32
+ name = path.pop
33
+ path.each do |piece|
34
+ container = container.classes[piece]
35
+ end
36
+ end
37
+ container.classes[name] = cls
38
+ end
39
+
40
+ def public_interface(name, *interfaces)
41
+ cls = InterfaceBuilder.new(self, name, interfaces)
42
+ @classes[name] = cls
43
+ cls
44
+ end
45
+
46
+ def generate
47
+ @classes.values.each do |cls|
48
+ yield cls.filename, cls
49
+ end
50
+ end
51
+ end
52
+
53
+ class Output
54
+ def initialize
55
+ @out = ""
56
+ @indent = 0
57
+ end
58
+
59
+ def puts(*lines)
60
+ lines.each do |line|
61
+ print_indent
62
+ @out << line.to_s
63
+ @out << "\n"
64
+ @indented = false
65
+ end
66
+ end
67
+
68
+ def print_indent
69
+ @indent ||= 0
70
+ @out << (' ' * @indent) unless @indented
71
+ @indented = true
72
+ end
73
+
74
+ def print(str)
75
+ print_indent
76
+ @out << str.to_s
77
+ end
78
+
79
+ def indent
80
+ @indent += 2
81
+ end
82
+
83
+ def dedent
84
+ @indent -= 2
85
+ end
86
+
87
+ def <<(other)
88
+ other.to_s.each_line do |line|
89
+ print_indent
90
+ print(line)
91
+ @indented = false
92
+ end
93
+ end
94
+
95
+ def to_s
96
+ @out
97
+ end
98
+ end
99
+
100
+ module Helper
101
+ def puts(*args)
102
+ @out.puts(*args)
103
+ end
104
+
105
+ def print(*args)
106
+ @out.print(*args)
107
+ end
108
+
109
+ def indent
110
+ @out.indent
111
+ end
112
+
113
+ def dedent
114
+ @out.dedent
115
+ end
116
+
117
+ def block(line='')
118
+ puts line + " {"
119
+ indent
120
+ yield
121
+ dedent
122
+ puts "}"
123
+ end
124
+
125
+ def init_value(type)
126
+ # TODO move this to types?
127
+ case type
128
+ when JVMTypes::Boolean
129
+ 'false'
130
+ when JVMTypes::PrimitiveType, JVMTypes::NarrowingType
131
+ '0'
132
+ else
133
+ 'null'
134
+ end
135
+ end
136
+
137
+ def annotate(annotations)
138
+ annotations.each do |annotation|
139
+ print "@#{annotation.name.gsub("$", ".")}("
140
+ first = true
141
+ annotation.values.each do |name, value|
142
+ print ", " unless first
143
+ first = false
144
+ print "#{name}="
145
+ print annotation_value(value)
146
+ end
147
+ puts ")"
148
+ end
149
+ end
150
+
151
+ def annotation_value(value)
152
+ case value
153
+ when Java::JavaLang::String
154
+ value.to_s.inspect
155
+ when Array
156
+ values = value.map{|x|annotation_value(x)}.join(", ")
157
+ "{#{values}}"
158
+ when BiteScript::ASM::Type
159
+ value.getClassName.gsub("$", ".")
160
+ else
161
+ raise "Unsupported annotation value #{value.inspect}"
162
+ end
163
+ end
164
+ end
165
+
166
+ class ClassBuilder
167
+ include Helper
168
+ include Duby::Compiler::JVM::JVMLogger
169
+ attr_reader :package, :name, :superclass, :filename, :class_name, :out
170
+ attr_reader :interfaces, :abstract
171
+ def initialize(builder, name, superclass, interfaces, abstract)
172
+ @builder = builder
173
+ @package = builder.package
174
+ if @package
175
+ @name = "#{@package}.#{name}"
176
+ else
177
+ @name = name
178
+ end
179
+ if name =~ %r{[/.]}
180
+ pieces = name.split(%r{[/.]})
181
+ name = pieces.pop
182
+ @package = pieces.join('.')
183
+ end
184
+ @class_name = name
185
+ if @class_name =~ /\$([^$]+)/
186
+ @class_name = $1
187
+ @static = true
188
+ @inner_class = true
189
+ end
190
+ @superclass = superclass || JVMTypes::Object
191
+ @interfaces = interfaces
192
+ @filename = "#{name}.java"
193
+ @filename = "#{package.tr('.', '/')}/#{@filename}" if @package
194
+ @out = Output.new
195
+ @stopped = false
196
+ @methods = []
197
+ @fields = {}
198
+ @inner_classes = {}
199
+ @abstract = abstract
200
+ start
201
+ end
202
+
203
+ def compiler
204
+ @builder.compiler
205
+ end
206
+
207
+ def classes
208
+ @inner_classes
209
+ end
210
+
211
+ def start
212
+ unless @inner_class
213
+ puts "// Generated from #{@builder.filename}"
214
+ puts "package #{package};" if package
215
+ end
216
+ end
217
+
218
+ def finish_declaration
219
+ return if @declaration_finished
220
+ @declaration_finished = true
221
+ modifiers = "public#{' static' if @static}#{' abstract' if @abstract}"
222
+ print "#{modifiers} class #{class_name} extends #{superclass.name}"
223
+ unless @interfaces.empty?
224
+ print " implements "
225
+ @interfaces.each_with_index do |interface, index|
226
+ print ', ' unless index == 0
227
+ print interface.to_source
228
+ end
229
+ end
230
+ puts " {"
231
+ indent
232
+ end
233
+
234
+ def stop
235
+ finish_declaration
236
+ return if @stopped
237
+ @methods.each do |method|
238
+ @out << method.out
239
+ end
240
+ @inner_classes.values.each do |inner_class|
241
+ @out << inner_class.out
242
+ end
243
+ log "Class #{name} complete (#{@out.to_s.size})"
244
+ @stopped = true
245
+ dedent
246
+ puts "}"
247
+ log "Class #{name} complete (#{@out.to_s.size})"
248
+ end
249
+
250
+ def main
251
+ build_method('main', :public, :static, [], JVMTypes::Void,
252
+ [JVMTypes::String.array_type, 'argv'])
253
+ end
254
+
255
+ def declare_field(name, type, static, access='private', annotations=[])
256
+ finish_declaration
257
+ return if @fields[name]
258
+ static = static ? ' static' : ''
259
+ annotate(annotations)
260
+ puts "#{access}#{static} #{type.to_source} #{name};"
261
+ @fields[name] = true
262
+ end
263
+
264
+ def build_method(name, visibility, static, exceptions, type, *args)
265
+ finish_declaration
266
+ type ||= Duby::AST::type(nil, :void)
267
+ @methods << MethodBuilder.new(self,
268
+ :name => name,
269
+ :visibility => visibility,
270
+ :static => static,
271
+ :return => type,
272
+ :args => args,
273
+ :exceptions => exceptions)
274
+ @methods[-1]
275
+ end
276
+
277
+ def build_constructor(visibility, exceptions, *args)
278
+ finish_declaration
279
+ @methods << MethodBuilder.new(self,
280
+ :name => class_name,
281
+ :visibility => visibility,
282
+ :args => args,
283
+ :exceptions => exceptions)
284
+ @methods[-1]
285
+ end
286
+
287
+ def generate
288
+ stop
289
+ @out.to_s
290
+ end
291
+ end
292
+
293
+ class InterfaceBuilder < ClassBuilder
294
+ def initialize(builder, name, interfaces)
295
+ super(builder, name, nil, interfaces, true)
296
+ end
297
+
298
+ def finish_declaration
299
+ return if @declaration_finished
300
+ @declaration_finished = true
301
+ print "public interface #{class_name}"
302
+ unless @interfaces.empty?
303
+ print " extends "
304
+ @interfaces.each_with_index do |interface, index|
305
+ print ', ' unless index == 0
306
+ print interface.to_source
307
+ end
308
+ end
309
+ puts " {"
310
+ indent
311
+ end
312
+
313
+ def build_method(name, visibility, static, exceptions, type, *args)
314
+ raise "Interfaces can't have static methods" if static
315
+ finish_declaration
316
+ type ||= Duby::AST::type(nil, :void)
317
+ @methods << MethodBuilder.new(self,
318
+ :name => name,
319
+ :visibility => visibility,
320
+ :return => type,
321
+ :args => args,
322
+ :abstract => true,
323
+ :exceptions => exceptions)
324
+ @methods[-1]
325
+ end
326
+ end
327
+
328
+ class MethodBuilder
329
+ include Helper
330
+
331
+ attr_accessor :name, :type, :out
332
+
333
+ def initialize(cls, options)
334
+ @class = cls
335
+ @compiler = cls.compiler
336
+ @out = Output.new
337
+ @visibility = options[:visibility]
338
+ @name = options[:name]
339
+ @type = options[:return]
340
+ @typename = @type && @type.to_source
341
+ @locals = {}
342
+ @args = options[:args].map do |arg|
343
+ unless arg.kind_of? Array
344
+ arg = [arg.inferred_type, arg.name]
345
+ end
346
+ @locals[arg[1]] = arg[0]
347
+ arg
348
+ end
349
+ @static = options[:static] ? ' static' : nil
350
+ @abstract = options[:abstract] && ' abstract'
351
+ @exceptions = options[:exceptions] || []
352
+ @temps = 0
353
+ end
354
+
355
+ def start
356
+ print "#{@visibility}#{@static}#{@abstract} #{@typename} #{@name}("
357
+ @args.each_with_index do |(type, name), i|
358
+ print ', ' unless i == 0
359
+ print "#{type.to_source} #{name}"
360
+ end
361
+ print ')'
362
+ unless @exceptions.empty?
363
+ print ' throws '
364
+ @exceptions.each_with_index do |exception, i|
365
+ print ', ' unless i == 0
366
+ print exception.name
367
+ end
368
+ end
369
+ if @abstract
370
+ puts ";"
371
+ def self.puts(*args); end
372
+ def self.print(*args); end
373
+ else
374
+ puts " {"
375
+ end
376
+ indent
377
+ end
378
+
379
+ def stop
380
+ dedent
381
+ puts "}"
382
+ end
383
+
384
+ def declare_local(type, name, initialize=true)
385
+ unless @locals[name]
386
+ if initialize
387
+ print "#{type.to_source} #{name} = "
388
+ if block_given?
389
+ yield self
390
+ else
391
+ print init_value(type)
392
+ end
393
+ puts ';'
394
+ end
395
+ @locals[name] = type
396
+ end
397
+ name
398
+ end
399
+
400
+ def local?(name)
401
+ !!@locals[name]
402
+ end
403
+
404
+ def tmp(type, &block)
405
+ @temps += 1
406
+ declare_local(type, "temp$#{@temps}", &block)
407
+ end
408
+
409
+ def label
410
+ @temps += 1
411
+ "label#{@temps}"
412
+ end
413
+
414
+ def push_int(value)
415
+ print value
416
+ end
417
+
418
+ def ldc_float(value)
419
+ print "(float)#{value}"
420
+ end
421
+
422
+ def ldc_double(value)
423
+ print value
424
+ end
425
+
426
+ def ldc_class(type)
427
+ print "#{type.to_source}.class"
428
+ end
429
+
430
+ def instanceof(type)
431
+ print " instanceof #{type.to_source}"
432
+ end
433
+
434
+ def method_missing(name, *args)
435
+ if name.to_s =~ /.const_(m)?(\d)/
436
+ print '-' if $1
437
+ print $2
438
+ else
439
+ super
440
+ end
441
+ end
442
+ end
443
+ end
444
+ end
@@ -0,0 +1,110 @@
1
+ class Duby::Compiler::JavaSource < Duby::Compiler::JVMCompilerBase
2
+ class SimpleWhileLoop
3
+ attr_reader :compiler, :loop
4
+ def initialize(loop, compiler)
5
+ @loop = loop
6
+ @compiler = compiler
7
+ end
8
+
9
+ def break
10
+ compiler.method.puts "break;"
11
+ end
12
+
13
+ def next
14
+ compiler.method.puts "continue;"
15
+ end
16
+
17
+ def redo
18
+ raise "#{self.class.name} doesn't support redo"
19
+ end
20
+
21
+ def compile(expression)
22
+ prepare
23
+ @loop.init.compile(compiler, false) if @loop.init?
24
+ @start.call
25
+ compiler.method.block do
26
+ @loop.pre.compile(compiler, false) if @loop.pre?
27
+ compile_body
28
+ @loop.post.compile(compiler, false) if @loop.post?
29
+ end
30
+ if @end_check
31
+ @end_check.call
32
+ compiler.method.puts ';'
33
+ end
34
+ if expression
35
+ compiler.method.puts "#{compiler.lvalue}null;"
36
+ end
37
+ end
38
+
39
+ def compile_body
40
+ loop.body.compile(compiler, false) if loop.body
41
+ end
42
+
43
+ def prepare
44
+ predicate = loop.condition.predicate.precompile(compiler)
45
+ negative = loop.negative ? '!' : ''
46
+ check = lambda do
47
+ compiler.method.print "while (#{negative}"
48
+ predicate.compile(compiler, true)
49
+ compiler.method.print ')'
50
+ end
51
+ if loop.check_first
52
+ @start = check
53
+ else
54
+ @start = lambda {compiler.method.print 'do'}
55
+ @end_check = check
56
+ end
57
+ end
58
+ end
59
+
60
+ module Redoable
61
+ def compile_with_redo(block)
62
+ @redo = compiler.method.tmp(JVMTypes::Boolean)
63
+ compiler.method.puts "#{@inner}:"
64
+ compiler.method.block "do" do
65
+ compiler.method.puts "#{@redo} = false;"
66
+ block.compile(compiler, false) if block
67
+ end
68
+ compiler.method.puts "while (#{@redo});"
69
+ end
70
+
71
+ def break
72
+ compiler.method.puts "break #{@outer};"
73
+ end
74
+
75
+ def next
76
+ compiler.method.puts "break #{@inner};"
77
+ end
78
+
79
+ def redo
80
+ compiler.method.puts "#{@redo} = true;"
81
+ compiler.method.puts "continue #{@inner};"
82
+ end
83
+ end
84
+
85
+ class ComplexWhileLoop < SimpleWhileLoop
86
+ include Redoable
87
+ def prepare
88
+ super
89
+ @outer = compiler.method.label
90
+ @inner = compiler.method.label
91
+ @complex_predicate = !loop.condition.predicate.expr?(compiler)
92
+ super_start = @start
93
+ @start = lambda do
94
+ compiler.method.puts "#{@outer}:"
95
+ super_start.call
96
+ end
97
+ end
98
+
99
+ def compile_body
100
+ if @loop.redo?
101
+ compile_with_redo(@loop.body)
102
+ else
103
+ compiler.method.puts "#{@inner}:"
104
+ compiler.method.block do
105
+ loop.body.compile(compiler, false) if loop.body
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end