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.
- data/Changelog +27 -0
- data/README +79 -0
- data/Rakefile +24 -0
- data/TODO +14 -0
- data/VERSION +1 -0
- data/benchmarks/bench.rb +129 -0
- data/benchmarks/concretize_test.rb +26 -0
- data/benchmarks/extconf.rb +10 -0
- data/benchmarks/tak_rb.rb +7 -0
- data/benchmarks/tak_so.rb +7 -0
- data/benchmarks/tak_source.rb +16 -0
- data/bin/rb2cx +162 -0
- data/doc/eval2c.txt +246 -0
- data/doc/gen_html.rb +26 -0
- data/doc/html_template +10 -0
- data/doc/index.txt +169 -0
- data/doc/limitations.txt +529 -0
- data/doc/optimizations.txt +185 -0
- data/doc/rb2cx.txt +130 -0
- data/doc/style.css +27 -0
- data/lib/concretizer.rb +3 -0
- data/lib/ruby2cext/c_function.rb +617 -0
- data/lib/ruby2cext/common_node_comp.rb +1412 -0
- data/lib/ruby2cext/compiler.rb +311 -0
- data/lib/ruby2cext/concretize.rb +269 -0
- data/lib/ruby2cext/error.rb +15 -0
- data/lib/ruby2cext/eval2c.rb +126 -0
- data/lib/ruby2cext/parser.rb +36 -0
- data/lib/ruby2cext/plugin.rb +24 -0
- data/lib/ruby2cext/plugins/builtin_methods.rb +817 -0
- data/lib/ruby2cext/plugins/cache_call.rb +293 -0
- data/lib/ruby2cext/plugins/case_optimize.rb +102 -0
- data/lib/ruby2cext/plugins/const_cache.rb +36 -0
- data/lib/ruby2cext/plugins/direct_self_call.rb +70 -0
- data/lib/ruby2cext/plugins/inline_builtin.rb +797 -0
- data/lib/ruby2cext/plugins/inline_methods.rb +68 -0
- data/lib/ruby2cext/plugins/ivar_cache.rb +147 -0
- data/lib/ruby2cext/plugins/require_include.rb +69 -0
- data/lib/ruby2cext/plugins/util.rb +154 -0
- data/lib/ruby2cext/plugins/warnings.rb +121 -0
- data/lib/ruby2cext/scopes.rb +225 -0
- data/lib/ruby2cext/str_to_c_strlit.rb +12 -0
- data/lib/ruby2cext/tools.rb +80 -0
- data/lib/ruby2cext/version.rb +22 -0
- data/results +68 -0
- data/setup.rb +1585 -0
- data/stuff/builtin_methods.rb +69 -0
- data/stuff/builtin_methods_test.rb +37 -0
- data/test/bootstrap.rb +10 -0
- data/test/causes_crash_all_opts.rb +1165 -0
- data/test/eval2c/test_eval2c.rb +37 -0
- data/test/temp_17.rb +16 -0
- data/test/temp_18.rb +8 -0
- data/test/temp_19.rb +8 -0
- data/test/temp_2.rb +7 -0
- data/test/temp_20.rb +5 -0
- data/test/temp_21.rb +161 -0
- data/test/temp_22.rb +7 -0
- data/test/temp_23.rb +7 -0
- data/test/temp_24.rb +219 -0
- data/test/temp_25.rb +7 -0
- data/test/temp_26.rb +11 -0
- data/test/temp_27.rb +11 -0
- data/test/temp_28.rb +9 -0
- data/test/temp_29.rb +9 -0
- data/test/temp_3.rb +0 -0
- data/test/temp_30.rb +0 -0
- data/test/temp_31.rb +10 -0
- data/test/temp_32.rb +10 -0
- data/test/temp_33.rb +15 -0
- data/test/temp_34.rb +15 -0
- data/test/temp_35.rb +7 -0
- data/test/temp_36.rb +7 -0
- data/test/temp_37.rb +10 -0
- data/test/temp_38.rb +10 -0
- data/test/temp_39.rb +0 -0
- data/test/temp_4.rb +7 -0
- data/test/temp_40.rb +50 -0
- data/test/temp_41.rb +50 -0
- data/test/temp_42.rb +8 -0
- data/test/temp_43.rb +8 -0
- data/test/temp_44.rb +0 -0
- data/test/temp_48.rb +7 -0
- data/test/temp_49.rb +7 -0
- data/test/temp_5.rb +7 -0
- data/test/temp_59.rb +7 -0
- data/test/temp_6.rb +7 -0
- data/test/temp_60.rb +7 -0
- data/test/temp_68.rb +239 -0
- data/test/temp_7.rb +7 -0
- data/test/temp_70.rb +7 -0
- data/test/temp_71.rb +7 -0
- data/test/temp_72.rb +13 -0
- data/test/temp_73.rb +7 -0
- data/test/temp_74.rb +7 -0
- data/test/temp_76.rb +7 -0
- data/test/temp_77.rb +13 -0
- data/test/temp_79.rb +7 -0
- data/test/temp_8.rb +14 -0
- data/test/temp_81.rb +14 -0
- data/test/temp_83.rb +0 -0
- data/test/temp_84.rb +7 -0
- data/test/temp_85.rb +7 -0
- data/test/temp_86.rb +14 -0
- data/test/temp_87.rb +7 -0
- data/test/temp_88.rb +7 -0
- data/test/temp_89.rb +7 -0
- data/test/temp_9.rb +14 -0
- data/test/temp_90.rb +0 -0
- data/test/temp_91.rb +7 -0
- data/test/temp_92.rb +7 -0
- data/test/temp_93.rb +7 -0
- data/test/temp_94.rb +7 -0
- data/test/temp_95.rb +7 -0
- data/test/temp_96.rb +0 -0
- data/test/temp_97.rb +0 -0
- data/test/temp_98.rb +7 -0
- data/test/temp_99.rb +7 -0
- data/test/test_concretize.rb +132 -0
- data/test/test_concretize_all.rb +15 -0
- data/test/test_crystalize_block.rb +73 -0
- data/test/test_files/test.rb +615 -0
- data/test/test_files/vmode_test.rb +73 -0
- data/test/test_files/warn_test.rb +35 -0
- data/test/test_syntax.rb +25 -0
- metadata +268 -0
data/doc/limitations.txt
ADDED
@@ -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
|