6
#include "eval_intern.h"
8
NORETURN(static VALUE rb_f_throw _((int, VALUE *)));
12
* throw(symbol [, obj])
14
* Transfers control to the end of the active +catch+ block
15
* waiting for _symbol_. Raises +NameError+ if there
16
* is no +catch+ block for the symbol. The optional second
17
* parameter supplies a return value for the +catch+ block,
18
* which otherwise defaults to +nil+. For examples, see
19
* <code>Kernel::catch</code>.
23
rb_f_throw(int argc, VALUE *argv)
26
rb_thread_t *th = GET_THREAD();
27
struct rb_vm_tag *tt = th->tag;
29
rb_scan_args(argc, argv, "11", &tag, &value);
30
tag = ID2SYM(rb_to_id(tag));
40
rb_name_error(SYM2ID(tag), "uncaught throw `%s'",
41
rb_id2name(SYM2ID(tag)));
43
rb_trap_restore_mask();
48
return Qnil; /* not reached */
53
rb_throw(const char *tag, VALUE val)
57
argv[0] = ID2SYM(rb_intern(tag));
64
* catch(symbol) {| | block } > obj
66
* +catch+ executes its block. If a +throw+ is
67
* executed, Ruby searches up its stack for a +catch+ block
68
* with a tag corresponding to the +throw+'s
69
* _symbol_. If found, that block is terminated, and
70
* +catch+ returns the value given to +throw+. If
71
* +throw+ is not called, the block terminates normally, and
72
* the value of +catch+ is the value of the last expression
73
* evaluated. +catch+ expressions may be nested, and the
74
* +throw+ call need not be in lexical scope.
78
* throw :done if n <= 0
83
* catch(:done) { routine(3) }
94
rb_f_catch(VALUE dmy, VALUE tag)
97
VALUE val = Qnil; /* OK */
98
rb_thread_t *th = GET_THREAD();
100
tag = ID2SYM(rb_to_id(tag));
105
if ((state = EXEC_TAG()) == 0) {
106
val = rb_yield_0(1, &tag);
108
else if (state == TAG_THROW && th->errinfo == tag) {
109
val = th->tag->retval;
123
return rb_funcall(Qnil, rb_intern("catch"), 1, tag);
127
rb_catch(const char *tag, VALUE (*func)(), VALUE data)
129
return rb_iterate((VALUE (*)_((VALUE)))catch_i, ID2SYM(rb_intern(tag)),
136
static void call_end_proc _((VALUE data));
139
call_end_proc(VALUE data)
142
proc_invoke(data, rb_ary_new2(0), Qundef, 0);
147
* at_exit { block } -> proc
149
* Converts _block_ to a +Proc+ object (and therefore
150
* binds it at the point of call) and registers it for execution when
151
* the program exits. If multiple handlers are registered, they are
152
* executed in reverse order of registration.
154
* def do_at_exit(str1)
155
* at_exit { print str1 }
157
* at_exit { puts "cruel world" }
158
* do_at_exit("goodbye ")
163
* goodbye cruel world
171
if (!rb_block_given_p()) {
172
rb_raise(rb_eArgError, "called without a block");
174
proc = rb_block_proc();
175
rb_set_end_proc(call_end_proc, proc);
179
struct end_proc_data {
183
struct end_proc_data *next;
186
static struct end_proc_data *end_procs, *ephemeral_end_procs, *tmp_end_procs;
189
rb_set_end_proc(void (*func)(VALUE), VALUE data)
191
struct end_proc_data *link = ALLOC(struct end_proc_data);
192
struct end_proc_data **list;
193
rb_thread_t *th = GET_THREAD();
195
if (th->top_wrapper) {
196
list = &ephemeral_end_procs;
204
link->safe = rb_safe_level();
209
rb_mark_end_proc(void)
211
struct end_proc_data *link;
215
rb_gc_mark(link->data);
218
link = ephemeral_end_procs;
220
rb_gc_mark(link->data);
223
link = tmp_end_procs;
225
rb_gc_mark(link->data);
231
rb_exec_end_proc(void)
233
struct end_proc_data *link, *tmp;
235
volatile int safe = rb_safe_level();
237
while (ephemeral_end_procs) {
238
tmp_end_procs = link = ephemeral_end_procs;
239
ephemeral_end_procs = 0;
242
if ((status = EXEC_TAG()) == 0) {
243
rb_set_safe_level_force(link->safe);
244
(*link->func) (link->data);
248
error_handle(status);
251
tmp_end_procs = link = link->next;
256
tmp_end_procs = link = end_procs;
260
if ((status = EXEC_TAG()) == 0) {
261
rb_set_safe_level_force(link->safe);
262
(*link->func) (link->data);
266
error_handle(status);
269
tmp_end_procs = link = link->next;
273
rb_set_safe_level_force(safe);
279
rb_define_global_function("catch", rb_f_catch, 1);
280
rb_define_global_function("throw", rb_f_throw, -1);
281
rb_define_global_function("at_exit", rb_f_at_exit, 0);