crystalizer 0.2.2

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 (126) hide show
  1. data/Changelog +27 -0
  2. data/README +79 -0
  3. data/Rakefile +24 -0
  4. data/TODO +14 -0
  5. data/VERSION +1 -0
  6. data/benchmarks/bench.rb +129 -0
  7. data/benchmarks/concretize_test.rb +26 -0
  8. data/benchmarks/extconf.rb +10 -0
  9. data/benchmarks/tak_rb.rb +7 -0
  10. data/benchmarks/tak_so.rb +7 -0
  11. data/benchmarks/tak_source.rb +16 -0
  12. data/bin/rb2cx +162 -0
  13. data/doc/eval2c.txt +246 -0
  14. data/doc/gen_html.rb +26 -0
  15. data/doc/html_template +10 -0
  16. data/doc/index.txt +169 -0
  17. data/doc/limitations.txt +529 -0
  18. data/doc/optimizations.txt +185 -0
  19. data/doc/rb2cx.txt +130 -0
  20. data/doc/style.css +27 -0
  21. data/lib/concretizer.rb +3 -0
  22. data/lib/ruby2cext/c_function.rb +617 -0
  23. data/lib/ruby2cext/common_node_comp.rb +1412 -0
  24. data/lib/ruby2cext/compiler.rb +311 -0
  25. data/lib/ruby2cext/concretize.rb +269 -0
  26. data/lib/ruby2cext/error.rb +15 -0
  27. data/lib/ruby2cext/eval2c.rb +126 -0
  28. data/lib/ruby2cext/parser.rb +36 -0
  29. data/lib/ruby2cext/plugin.rb +24 -0
  30. data/lib/ruby2cext/plugins/builtin_methods.rb +817 -0
  31. data/lib/ruby2cext/plugins/cache_call.rb +293 -0
  32. data/lib/ruby2cext/plugins/case_optimize.rb +102 -0
  33. data/lib/ruby2cext/plugins/const_cache.rb +36 -0
  34. data/lib/ruby2cext/plugins/direct_self_call.rb +70 -0
  35. data/lib/ruby2cext/plugins/inline_builtin.rb +797 -0
  36. data/lib/ruby2cext/plugins/inline_methods.rb +68 -0
  37. data/lib/ruby2cext/plugins/ivar_cache.rb +147 -0
  38. data/lib/ruby2cext/plugins/require_include.rb +69 -0
  39. data/lib/ruby2cext/plugins/util.rb +154 -0
  40. data/lib/ruby2cext/plugins/warnings.rb +121 -0
  41. data/lib/ruby2cext/scopes.rb +225 -0
  42. data/lib/ruby2cext/str_to_c_strlit.rb +12 -0
  43. data/lib/ruby2cext/tools.rb +80 -0
  44. data/lib/ruby2cext/version.rb +22 -0
  45. data/results +68 -0
  46. data/setup.rb +1585 -0
  47. data/stuff/builtin_methods.rb +69 -0
  48. data/stuff/builtin_methods_test.rb +37 -0
  49. data/test/bootstrap.rb +10 -0
  50. data/test/causes_crash_all_opts.rb +1165 -0
  51. data/test/eval2c/test_eval2c.rb +37 -0
  52. data/test/temp_17.rb +16 -0
  53. data/test/temp_18.rb +8 -0
  54. data/test/temp_19.rb +8 -0
  55. data/test/temp_2.rb +7 -0
  56. data/test/temp_20.rb +5 -0
  57. data/test/temp_21.rb +161 -0
  58. data/test/temp_22.rb +7 -0
  59. data/test/temp_23.rb +7 -0
  60. data/test/temp_24.rb +219 -0
  61. data/test/temp_25.rb +7 -0
  62. data/test/temp_26.rb +11 -0
  63. data/test/temp_27.rb +11 -0
  64. data/test/temp_28.rb +9 -0
  65. data/test/temp_29.rb +9 -0
  66. data/test/temp_3.rb +0 -0
  67. data/test/temp_30.rb +0 -0
  68. data/test/temp_31.rb +10 -0
  69. data/test/temp_32.rb +10 -0
  70. data/test/temp_33.rb +15 -0
  71. data/test/temp_34.rb +15 -0
  72. data/test/temp_35.rb +7 -0
  73. data/test/temp_36.rb +7 -0
  74. data/test/temp_37.rb +10 -0
  75. data/test/temp_38.rb +10 -0
  76. data/test/temp_39.rb +0 -0
  77. data/test/temp_4.rb +7 -0
  78. data/test/temp_40.rb +50 -0
  79. data/test/temp_41.rb +50 -0
  80. data/test/temp_42.rb +8 -0
  81. data/test/temp_43.rb +8 -0
  82. data/test/temp_44.rb +0 -0
  83. data/test/temp_48.rb +7 -0
  84. data/test/temp_49.rb +7 -0
  85. data/test/temp_5.rb +7 -0
  86. data/test/temp_59.rb +7 -0
  87. data/test/temp_6.rb +7 -0
  88. data/test/temp_60.rb +7 -0
  89. data/test/temp_68.rb +239 -0
  90. data/test/temp_7.rb +7 -0
  91. data/test/temp_70.rb +7 -0
  92. data/test/temp_71.rb +7 -0
  93. data/test/temp_72.rb +13 -0
  94. data/test/temp_73.rb +7 -0
  95. data/test/temp_74.rb +7 -0
  96. data/test/temp_76.rb +7 -0
  97. data/test/temp_77.rb +13 -0
  98. data/test/temp_79.rb +7 -0
  99. data/test/temp_8.rb +14 -0
  100. data/test/temp_81.rb +14 -0
  101. data/test/temp_83.rb +0 -0
  102. data/test/temp_84.rb +7 -0
  103. data/test/temp_85.rb +7 -0
  104. data/test/temp_86.rb +14 -0
  105. data/test/temp_87.rb +7 -0
  106. data/test/temp_88.rb +7 -0
  107. data/test/temp_89.rb +7 -0
  108. data/test/temp_9.rb +14 -0
  109. data/test/temp_90.rb +0 -0
  110. data/test/temp_91.rb +7 -0
  111. data/test/temp_92.rb +7 -0
  112. data/test/temp_93.rb +7 -0
  113. data/test/temp_94.rb +7 -0
  114. data/test/temp_95.rb +7 -0
  115. data/test/temp_96.rb +0 -0
  116. data/test/temp_97.rb +0 -0
  117. data/test/temp_98.rb +7 -0
  118. data/test/temp_99.rb +7 -0
  119. data/test/test_concretize.rb +132 -0
  120. data/test/test_concretize_all.rb +15 -0
  121. data/test/test_crystalize_block.rb +73 -0
  122. data/test/test_files/test.rb +615 -0
  123. data/test/test_files/vmode_test.rb +73 -0
  124. data/test/test_files/warn_test.rb +35 -0
  125. data/test/test_syntax.rb +25 -0
  126. metadata +268 -0
@@ -0,0 +1,529 @@
1
+
2
+ h1. Ruby2CExtension Limitations
3
+
4
+ Ruby2CExtension has some limitations. Some things do not work "by design"
5
+ other things don't work because they are not (yet) implemented.
6
+
7
+ Generally Ruby2CExtension tries to match Ruby's semantics as close as
8
+ possible, so if a Ruby file doesn't fail to compile and doesn't have any of
9
+ the issues described below, then the compiled C extension should just work and
10
+ behave exactly as the Ruby code would.
11
+
12
+
13
+ h2. Warnings and Exceptions
14
+
15
+ Not all warnings that Ruby code might emit are reproduced in the compiled C
16
+ extension.
17
+
18
+ Ruby2CExtension also omits some checks that might raise exceptions for Ruby
19
+ code (it won't warn or raise exceptions on wrong argument count in lambdas for
20
+ example).
21
+
22
+ As a rule of thumb: if Ruby code works without warnings then the compiled C
23
+ extension will also work without warnings, but if the Ruby code emits
24
+ warnings, then the compiled C extension might emit less warnings.
25
+
26
+ Also, sometimes the compiled C extension will raise slightly different
27
+ exceptions than the Ruby code would.
28
+
29
+
30
+ h2. C Extension Limitations
31
+
32
+ Because the compiled code is a C extension, it will also behave like a C
33
+ extension:
34
+
35
+ * backtraces will look like backtraces of C extensions (i.e. no line
36
+ numbers, ...)
37
+ * a trace proc set with @set_trace_func@ will only get C extension events
38
+ (@"c-call"@, @"c-return"@, @"raise"@), instead of the usual Ruby code events
39
+
40
+
41
+ h2. Arity
42
+
43
+ All methods and procs defined in Ruby code that is compiled to a C extension
44
+ will return @-1@ as @arity@. So if your Ruby code depends on the method
45
+ @arity@, you might have to change it.
46
+
47
+
48
+ h2. Continuations
49
+
50
+ Continuations (@callcc@) are possible in compiled Ruby code, but you might see
51
+ wrong behavior with local variables (i.e. they will have an old value),
52
+ depending on whether these local variables are needed for a closure or not.
53
+
54
+ In short, you probably should not use continuations in Ruby code that you want
55
+ to compile to a C extension.
56
+
57
+
58
+ h2. Scope
59
+
60
+ In Ruby every scope (class scope, methods, ...) has an associated C struct
61
+ SCOPE, which stores the local variables (including @$~@ and @$_@) for that
62
+ scope. Methods that are implemented in a C extension don't get such a SCOPE,
63
+ because it is expensive to set up and they don't need it (they just use
64
+ variables on the stack).
65
+
66
+ That means that the methods in Ruby code that is compiled to a C extension
67
+ won't get a SCOPE either, which is usually no problem because local variables
68
+ are handled differently anyway. It only gets a problem, if the code uses
69
+ methods that work with the current SCOPE. Here are some of these methods:
70
+
71
+ * @local_variables@
72
+ * @eval@
73
+ * @binding@
74
+
75
+ These methods will work, but they will see the SCOPE of the nearest Ruby code
76
+ scope. This is also true for @$_@ and @$~@ (and the derived @$&@, @$`@, @$'@,
77
+ @$1@, ...). Example:
78
+
79
+ PRE
80
+ def bar
81
+ a = 2
82
+ "xxx" =~ /./ # changes $~ of the nearest Ruby code scope
83
+ p eval("a") # won't return 2 (a's value), instead it will be evaled in the
84
+ # nearest Ruby code scope
85
+ local_variables # returns local variables of the nearest Ruby code scope
86
+ end
87
+ PREEND
88
+
89
+ If bar is compiled into a C extension and then called from the following Ruby
90
+ code:
91
+
92
+ PRE
93
+ a = b = 42
94
+ $~ = nil
95
+ p bar
96
+ p $~
97
+ PREEND
98
+
99
+ Then it will output
100
+
101
+ PRE
102
+ 42
103
+ ["a", "b"]
104
+ #<MatchData: ...>
105
+ PREEND
106
+
107
+ instead of the expected
108
+
109
+ PRE
110
+ 2
111
+ ["a"]
112
+ nil
113
+ PREEND
114
+
115
+ Another consequence is that if compiled methods call each other, they will all
116
+ share the same @$_@ and @$~@ (those of the nearest Ruby code scope). This
117
+ might make some code behave unexpectedly.
118
+
119
+
120
+ h2. Vmode
121
+
122
+ The so called vmode is also associated with the Ruby SCOPE (though not
123
+ directly stored inside the SCOPE struct). The vmode is set by the methods
124
+ @private@, @protected@, @public@ and @module_function@ and determines which
125
+ visibility newly defined methods get.
126
+
127
+ Ruby2CExtension can not (easily) access Ruby's internal vmode, instead it
128
+ tries to figure out at compile time what visibility a method defined using
129
+ @def@ will get. But be careful with @Module#define_method@ and
130
+ @Module#attr*@: those methods will use Ruby's internal vmode.
131
+
132
+ So, there are actually two different vmodes at work for compiled Ruby
133
+ code: the vmode that Ruby2CExtension uses at compile time to guess which
134
+ visibility methods defined with @def@ get and Ruby's internal vmode at
135
+ runtime which is used by @Module#define_method@ and @Module#attr*@.
136
+
137
+ Ruby2CExtension's compile time vmode heuristic works by replacing calls to the
138
+ vmode changing methods with @nil@ and instead changing the compile time vmode.
139
+ The calls are only replaced if they are without receiver and without
140
+ arguments. And it also depends on where the calls are made:
141
+
142
+ In the *toplevel scope* only calls to @private@ and @public@ are replaced, the
143
+ default vmode in the toplevel scope is private.
144
+
145
+ In a *module scope* calls to @private@, @protected@, @public@ and
146
+ @module_function@ are replaced, the default vmode in a module scope is public.
147
+
148
+ In a *class scope* calls to @private@, @protected@ and @public@ are replaced,
149
+ the default vmode in a class scope is public.
150
+
151
+ In *methods* and *blocks* no calls are replaced and all methods defined with
152
+ @def@ will be public.
153
+
154
+ If your code doesn't do anything tricky, then the compile time heuristic
155
+ should just work as expected. Here is an example:
156
+
157
+ PRE
158
+ # start of file
159
+ # default vmode is private
160
+ def m1; end # private
161
+
162
+ public # this call will be replaced with nil
163
+ # vmode is now public
164
+ def m2; end # public
165
+
166
+ class A
167
+ # default vmode is public
168
+ def m2; end # public
169
+
170
+ private # this call will be replaced with nil
171
+ # vmode is now private
172
+ def m3 # private
173
+ def foo # public, because it is in a method
174
+ end
175
+ end
176
+
177
+ end
178
+
179
+ protected # this call is not replaced and will probably fail because
180
+ # #protected is not defined at toplevel
181
+
182
+ # end of file
183
+ PREEND
184
+
185
+ Here is an example, where it fails:
186
+
187
+ PRE
188
+ class A
189
+ def pub; end # public
190
+
191
+ private if nil # Ruby2CExtension replaces the call to private with nil
192
+ # vmode is now private
193
+
194
+ def pub2; end # will be private in the compiled C extension
195
+ end
196
+ PREEND
197
+
198
+ But this should be a pretty uncommon case. The visibility of methods defined
199
+ using @def@ should be correct for most Ruby code.
200
+
201
+ It is a bit more complicated for methods/attributes defined using
202
+ @define_method@ or the @attr*@ methods. Their visibility is determined by
203
+ Ruby's internal vmode at run time.
204
+
205
+ As explained above, C extension code does not get its own SCOPE, so it also
206
+ doesn't get its own vmode. When a C extension is <code>require</code>d, Ruby
207
+ sets the vmode to public before loading the C extension. All the class/module
208
+ scopes that are executed during the @require@ are executed in the same SCOPE
209
+ and so also with the same vmode.
210
+
211
+ Because all the vmode changing method calls are replaced with @nil@, Ruby's
212
+ internal vmode will probably stay public all the time and so all
213
+ methods/attributes defined using @define_method@ or the @attr*@ methods will
214
+ be public. Here is an example:
215
+
216
+ PRE
217
+ # Ruby's internal vmode is public
218
+ class A
219
+ # still the same internal vmode, still public
220
+ define_method(:a) {} # public
221
+
222
+ private # is replaced with nil, does not affect Ruby's internal vmode, only affects the
223
+ # level given to method b, just below
224
+ def b; end # private
225
+
226
+ # but Ruby's internal vmode is still public
227
+ define_method(:c) {} # public, which is wrong
228
+ attr_accessor :d, :e # also public, which is wrong
229
+
230
+ def c; end # private, which is right
231
+ end
232
+ PREEND
233
+
234
+ If those methods really need another visibility, then it can be changed
235
+ explicitly:
236
+
237
+ PRE
238
+ class A
239
+ define_method(:a) {}
240
+ private :a
241
+ end
242
+ PREEND
243
+
244
+ TODO do that automatically.
245
+
246
+ In methods the internal vmode is that of the nearest Ruby SCOPE (as explained
247
+ above), so it is usually unpredictable. And additionally calling one of the
248
+ vmode changing methods will also affect the SCOPE of the caller:
249
+
250
+ PRE
251
+ # in compiled C extension
252
+ def my_private
253
+ private
254
+ end
255
+ PREEND
256
+
257
+ PRE
258
+ # in Ruby code
259
+ class A
260
+ def a;end # public
261
+ my_private
262
+ def b;end # private, but would be public if the above code was not compiled
263
+ end
264
+ PREEND
265
+
266
+ To be safe, don't use the vmode changing methods without arguments inside
267
+ methods, instead set the visibility explicitly (e.g. @private :a@).
268
+
269
+
270
+ h2. Cref
271
+
272
+ The so called cref is another Ruby internal that Ruby2CExtension has to
273
+ emulate. The cref is a linked list that describes the current lexical
274
+ class/module nesting. Example:
275
+
276
+ PRE
277
+ class A
278
+ class B
279
+ # cref here is B -> A -> Object
280
+ end
281
+ # cref here is A -> Object
282
+ module C
283
+ # cref here is C -> A -> Object
284
+ end
285
+ end
286
+ # cref here is Object
287
+ PREEND
288
+
289
+ The current cref is used for constant and class variable lookup and for @def@,
290
+ @undef@ and @alias@.
291
+
292
+ Ruby2CExtension emulates cref with the same semantics as Ruby. There are only
293
+ two problems.
294
+
295
+ First, when a method is defined in Ruby code, it saves the current cref for
296
+ later use. From C it isn't possible to store an extra value when defining a
297
+ method, so Ruby2CExtension works around this problem by storing the cref in a
298
+ global variable. But there is still a problem when a @def@ is used/run
299
+ multiple times, because the cref can differ each time.
300
+
301
+ So if a @def@ that requires a cref is used multiple times, then the compiled C
302
+ extension will raise an exception (this is the only case where code compiled
303
+ with Ruby2CExtension raises an exception that Ruby wouldn't raise). If a @def@
304
+ doesn't need a cref, then everything is fine and it can be used multiple
305
+ times. Examples:
306
+
307
+ PRE
308
+ ["a", "b"].each { |s|
309
+ class << s
310
+ def bar; self; end # is OK, doesn't need cref
311
+ end
312
+ }
313
+
314
+ ["a", "b"].each { |s|
315
+ class << s
316
+ def baz; Array.new(self); end # fails the 2nd time
317
+ end
318
+ }
319
+ PREEND
320
+
321
+ The second case fails because the constant lookup for @Array@ needs a cref. If
322
+ you really need this to work, then you can use @::Array@ instead of @Array@,
323
+ because that won't need a cref.
324
+
325
+ Again in the usual case everything should be fine and if you really need to
326
+ use a @def@ that requires a cref multiple times, then you might be able to
327
+ modify it so that it won't need a cref.
328
+
329
+ The second problem that arises from Ruby2CExtension emulating crefs is that
330
+ methods that access Ruby's internal cref, will see the wrong cref and thus
331
+ not behave as expected. Those methods are @Module.nesting@, @Module.constants@
332
+ (but @Module#constants@ works), @autoload@ and @autoload?@ (use
333
+ @Module#autoload@ and @Module#autoload?@ instead).
334
+
335
+
336
+ h2. Block Pass
337
+
338
+ There currently is no way to pass a Proc instance as the block parameter to a
339
+ method call on the C side, i.e. there is no way to do the following from C:
340
+
341
+ PRE
342
+ def foo(proc)
343
+ bar(&proc)
344
+ end
345
+ PREEND
346
+
347
+ Ruby2CExtension works around this by compiling the above to something similar
348
+ to this:
349
+
350
+ PRE
351
+ def foo(proc)
352
+ tmp_proc = proc.to_proc
353
+ bar { |*arg| tmp_proc.call(*arg) }
354
+ end
355
+ PREEND
356
+
357
+ The downside of this workaround is that it doesn't work (as expected) with
358
+ methods like @instance_eval@ and it is problematic if a proc is passed deep
359
+ into a recursive method, because that block will then be wrapped multiple
360
+ times.
361
+
362
+ This issue might be fixed if a future Ruby version provides a way to cleanly
363
+ pass a proc to a method call.
364
+
365
+
366
+ h2. Block Argument Semantics
367
+
368
+ Block argument semantics are a bit tricky, but Ruby2CExtension should get it
369
+ right for most cases, here are two cases where the result is wrong:
370
+
371
+ PRE
372
+ def t1(*a); yield *a; end
373
+ p t1([1, 2]) { |a| a }
374
+
375
+ def bl_pa_tst(); p yield([1, 2]); end
376
+ pc = proc { |*a| a }
377
+ bl_pa_tst(&pc)
378
+ bl_pa_tst { |*a| a }
379
+ PREEND
380
+
381
+ Ruby outputs:
382
+
383
+ PRE
384
+ [1, 2]
385
+ [[1, 2]]
386
+ [[1, 2]]
387
+ PREEND
388
+
389
+ The compiled C extension outputs:
390
+
391
+ PRE
392
+ [[1, 2]]
393
+ [1, 2]
394
+ [1, 2]
395
+ PREEND
396
+
397
+ But again, for most cases it should just work and maybe it will get better in
398
+ future Ruby2CExtension versions.
399
+
400
+
401
+ h2. @super@ with implicit arguments and optional arguments
402
+
403
+ In a compiled C extension @super@ with implicit arguments will not use
404
+ optional arguments that have not been given by the original caller. Example:
405
+
406
+ PRE
407
+ class A
408
+ def foo(*a)
409
+ p a
410
+ end
411
+ end
412
+
413
+ class B < A
414
+ def foo(a = nil)
415
+ super
416
+ end
417
+ end
418
+
419
+ B.new.foo
420
+ PREEND
421
+
422
+ In Ruby this code will output @[nil]@, in the compiled form it will output
423
+ @[]@.
424
+
425
+
426
+ h2. Not Supported Features
427
+
428
+ Ruby files that use one or more of the above described problematic things will
429
+ usually compile just fine and fail or behave wrong at runtime. In contrast,
430
+ the following things will be catched at compile time. Most of them are just
431
+ not supported yet and might be added later.
432
+
433
+
434
+ h3. Control Flow
435
+
436
+ Most of the things that are not supported are related to control flow. Ruby
437
+ implements most of its control flow using @setjmp()@ and @longjmp()@. Most of
438
+ this is in @eval.c@ and there is no real API to access it, so Ruby2CExtension
439
+ has to do some tricks to make control flow work. For most cases workarounds
440
+ are implemented, but some of the harder cases are not (yet) supported.
441
+
442
+ The first thing that isn't supported is @return@ from inside a block. Also
443
+ @break@ with a value from inside a block is not supported (but @break@ without
444
+ a value is):
445
+
446
+ PRE
447
+ def foo
448
+ bar(1, 2, 3) {
449
+ next # works
450
+ next 42 # works
451
+ redo # works
452
+ break # works
453
+ break 42 # does not work
454
+ return # does not work
455
+ return 42 # does not work
456
+ }
457
+ return # works
458
+ return 42 # works
459
+ end
460
+ PREEND
461
+
462
+ For @while@/@until@ loops everything works.
463
+
464
+ Another problematic area in Ruby2CExtension 0.1.0 was control flow "through" a
465
+ @rescue@ or @ensure@ clause. This is mostly implemented now, only in @ensure@
466
+ clauses it still does not work (it _does_ work in @ensure@ bodies):
467
+
468
+ PRE
469
+ def foo
470
+ while bar?
471
+ begin
472
+ next # works
473
+ next 42 # works
474
+ redo # works
475
+ break # works
476
+ break 42 # works
477
+ return # works
478
+ return 42 # works
479
+ rescue
480
+ next # works
481
+ next 42 # works
482
+ redo # works
483
+ break # works
484
+ break 42 # works
485
+ return # works
486
+ return 42 # works
487
+ ensure
488
+ next # does not work
489
+ next 42 # does not work
490
+ redo # does not work
491
+ break # does not work
492
+ break 42 # does not work
493
+ return # does not work
494
+ return 42 # does not work
495
+ end
496
+ end
497
+ end
498
+ PREEND
499
+
500
+
501
+ h3. @defined?@
502
+
503
+ The @defined?@ statement is also not fully supported, it works for most of the
504
+ common cases like constants, global variables, instance variables, class
505
+ variables and @$~@ (and derived). Ruby2CExtension fails at compile time if a
506
+ case is not supported.
507
+
508
+
509
+ h3. @super@ with implicit arguments in Ruby 1.8.5 and later
510
+
511
+ For Ruby 1.8.5 @super@ with implicit arguments is only supported in methods (not in blocks or
512
+ @rescue@/@ensure@ clauses). For Ruby 1.8.4 @super@ with implicit arguments is
513
+ supported everywhere.
514
+
515
+ To work around this problem, just specify the arguments explicitly:
516
+
517
+ PRE
518
+ def foo(a, b)
519
+ 3.times { super(a, b) }
520
+ end
521
+ PREEND
522
+
523
+ instead of:
524
+
525
+ PRE
526
+ def foo(a, b)
527
+ 3.times { super }
528
+ end
529
+ PREEND