Permalink
Browse files

implemented catch/throw

  • Loading branch information...
1 parent 186530a commit 755b4642517c40ff06bfda5d45290ffa52ccac5b @lrz lrz committed Apr 6, 2009
Showing with 75 additions and 7 deletions.
  1. +65 −0 roxor.cpp
  2. +2 −0 roxor.h
  3. +8 −7 vm_eval.c
View
@@ -418,6 +418,7 @@ class RoxorVM
rb_vm_block_t *previous_block;
bool parse_in_eval;
+ CFMutableDictionaryRef catch_jmp_bufs;
std::vector<jmp_buf *> return_from_block_jmp_bufs;
RoxorVM(void);
@@ -2184,6 +2185,8 @@ RoxorVM::RoxorVM(void)
previous_block = NULL;
parse_in_eval = false;
+ catch_jmp_bufs = NULL;
+
load_path = rb_ary_new();
rb_objc_retain((void *)load_path);
loaded_features = rb_ary_new();
@@ -6694,6 +6697,68 @@ rb_backref_set(VALUE val)
}
}
+typedef struct {
+ jmp_buf *buf;
+ VALUE throw_value;
+} rb_vm_catch_t;
+
+extern "C"
+VALUE
+rb_vm_catch(VALUE tag)
+{
+ CFMutableDictionaryRef dict = GET_VM()->catch_jmp_bufs;
+ if (dict == NULL) {
+ dict = CFDictionaryCreateMutable(NULL, 0,
+ &kCFTypeDictionaryKeyCallBacks, NULL);
+ GET_VM()->catch_jmp_bufs = dict;
+ }
+
+ void *key = RB2OC(tag);
+ rb_vm_catch_t *s = NULL;
+ if (!CFDictionaryGetValueIfPresent(dict, (void *)key, (const void **)&s)) {
+ s = (rb_vm_catch_t *)malloc(sizeof(rb_vm_catch_t));
+ s->buf = (jmp_buf *)malloc(sizeof(jmp_buf));
+ s->throw_value = Qnil;
+ CFDictionarySetValue(dict, (void *)key, (void *)s);
+ }
+
+ if (setjmp(*s->buf) == 0) {
+ return rb_vm_yield(1, &tag);
+ }
+
+ VALUE retval = s->throw_value;
+ rb_objc_release((void *)retval);
+
+ // FIXME this crashes for a strange reason - to investigate
+ //CFDictionaryRemoveValue(GET_VM()->catch_jmp_bufs, key);
+ //free(s->buf);
+ //free(s);
+
+ return retval;
+}
+
+extern "C"
+VALUE
+rb_vm_throw(VALUE tag, VALUE value)
+{
+ CFMutableDictionaryRef dict = GET_VM()->catch_jmp_bufs;
+ rb_vm_catch_t *s = NULL;
+ void *key = RB2OC(tag);
+ if (dict != NULL) {
+ CFDictionaryGetValueIfPresent(dict, (void *)key, (const void **)&s);
+ }
+ if (s == NULL) {
+ VALUE desc = rb_inspect(tag);
+ rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_PTR(desc));
+ }
+
+ rb_objc_retain((void *)value);
+ s->throw_value = value;
+ longjmp(*s->buf, 1);
+
+ return Qnil; // never reached
+}
+
extern "C"
void
Init_PreVM(void)
View
@@ -78,6 +78,8 @@ bool rb_vm_respond_to(VALUE obj, SEL sel, bool priv);
VALUE rb_vm_method_missing(VALUE obj, int argc, const VALUE *argv);
int rb_vm_find_class_ivar_slot(VALUE klass, ID name);
void rb_vm_set_outer(VALUE klass, VALUE under);
+VALUE rb_vm_catch(VALUE tag);
+VALUE rb_vm_throw(VALUE tag, VALUE value);
static inline void
rb_vm_regrow_robject_slots(struct RObject *obj, unsigned int new_num_slot)
View
@@ -607,8 +607,11 @@ rb_mod_module_exec(VALUE mod, SEL sel, int argc, VALUE *argv)
static VALUE
rb_f_throw(VALUE rcv, SEL sel, int argc, VALUE *argv)
{
- // TODO
- return Qnil;
+ VALUE tag, value;
+
+ rb_scan_args(argc, argv, "11", &tag, &value);
+
+ return rb_vm_throw(tag, value);
}
void
@@ -663,11 +666,9 @@ rb_throw_obj(VALUE tag, VALUE val)
*/
static VALUE
-rb_f_catch(VALUE rcv, SEL sel, int argc, VALUE *argv)
+rb_f_catch(VALUE rcv, SEL sel, VALUE tag)
{
- // TODO
- rb_yield(Qundef);
- return Qnil;
+ return rb_vm_catch(tag);
}
/*
@@ -738,7 +739,7 @@ rb_make_backtrace(void)
void
Init_vm_eval(void)
{
- rb_objc_define_method(rb_mKernel, "catch", rb_f_catch, -1);
+ rb_objc_define_method(rb_mKernel, "catch", rb_f_catch, 1);
rb_objc_define_method(rb_mKernel, "throw", rb_f_throw, -1);
rb_objc_define_method(rb_mKernel, "loop", rb_f_loop, 0);

0 comments on commit 755b464

Please sign in to comment.