crystalizer 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|