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,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