ruby-changes:4586
From: ko1@a...
Date: Sat, 19 Apr 2008 19:30:14 +0900 (JST)
Subject: [ruby-changes:4586] knu - Ruby:r16080 (ruby_1_8): * eval.c (rb_exec_recursive): New internal function to help
knu 2008-04-19 19:29:59 +0900 (Sat, 19 Apr 2008) New Revision: 16080 Modified files: branches/ruby_1_8/ChangeLog branches/ruby_1_8/eval.c branches/ruby_1_8/intern.h Log: * eval.c (rb_exec_recursive): New internal function to help perform recursive operation; backported from 1.9. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/intern.h?r1=16080&r2=16079&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=16080&r2=16079&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/eval.c?r1=16080&r2=16079&diff_format=u Index: ruby_1_8/intern.h =================================================================== --- ruby_1_8/intern.h (revision 16079) +++ ruby_1_8/intern.h (revision 16080) @@ -233,6 +233,7 @@ VALUE rb_thread_local_aref _((VALUE, ID)); VALUE rb_thread_local_aset _((VALUE, ID, VALUE)); void rb_thread_atfork _((void)); +VALUE rb_exec_recursive _((VALUE(*)(VALUE, VALUE, int),VALUE,VALUE)); VALUE rb_funcall_rescue __((VALUE, ID, int, ...)); /* file.c */ VALUE rb_file_s_expand_path _((int, VALUE *)); Index: ruby_1_8/ChangeLog =================================================================== --- ruby_1_8/ChangeLog (revision 16079) +++ ruby_1_8/ChangeLog (revision 16080) @@ -1,3 +1,8 @@ +Sat Apr 19 19:26:09 2008 Akinori MUSHA <knu@i...> + + * intern.h, eval.c (rb_exec_recursive): New internal function to + help perform recursive operation; backported from 1.9. + Sat Apr 19 18:42:04 2008 Akinori MUSHA <knu@i...> * intern.h, hash.c (rb_hash_lookup): New internal function to Index: ruby_1_8/eval.c =================================================================== --- ruby_1_8/eval.c (revision 16079) +++ ruby_1_8/eval.c (revision 16080) @@ -13043,6 +13043,109 @@ } +/* variables for recursive traversals */ +static ID recursive_key; + +static VALUE +recursive_check(hash, obj) + VALUE hash; + VALUE obj; +{ + if (NIL_P(hash) || TYPE(hash) != T_HASH) { + return Qfalse; + } + else { + VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_last_func())); + + if (NIL_P(list) || TYPE(list) != T_HASH) + return Qfalse; + if (NIL_P(rb_hash_lookup(list, obj))) + return Qfalse; + return Qtrue; + } +} + +static VALUE +recursive_push(hash, obj) + VALUE hash; + VALUE obj; +{ + VALUE list, sym; + + sym = ID2SYM(rb_frame_last_func()); + if (NIL_P(hash) || TYPE(hash) != T_HASH) { + hash = rb_hash_new(); + rb_thread_local_aset(rb_thread_current(), recursive_key, hash); + list = Qnil; + } + else { + list = rb_hash_aref(hash, sym); + } + if (NIL_P(list) || TYPE(list) != T_HASH) { + list = rb_hash_new(); + rb_hash_aset(hash, sym, list); + } + rb_hash_aset(list, obj, Qtrue); + return hash; +} + +static void +recursive_pop(hash, obj) + VALUE hash; + VALUE obj; +{ + VALUE list, sym; + + sym = ID2SYM(rb_frame_last_func()); + if (NIL_P(hash) || TYPE(hash) != T_HASH) { + VALUE symname; + VALUE thrname; + symname = rb_inspect(sym); + thrname = rb_inspect(rb_thread_current()); + + rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s", + StringValuePtr(symname), StringValuePtr(thrname)); + } + list = rb_hash_aref(hash, sym); + if (NIL_P(list) || TYPE(list) != T_HASH) { + VALUE symname = rb_inspect(sym); + VALUE thrname = rb_inspect(rb_thread_current()); + rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s", + StringValuePtr(symname), StringValuePtr(thrname)); + } + rb_hash_delete(list, obj); +} + +VALUE +rb_exec_recursive(func, obj, arg) + VALUE (*func) _((VALUE, VALUE, int)); + VALUE obj; + VALUE arg; +{ + VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key); + VALUE objid = rb_obj_id(obj); + + if (recursive_check(hash, objid)) { + return (*func) (obj, arg, Qtrue); + } + else { + VALUE result = Qundef; + int state; + + hash = recursive_push(hash, objid); + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { + result = (*func) (obj, arg, Qfalse); + } + POP_TAG(); + recursive_pop(hash, objid); + if (state) + JUMP_TAG(state); + return result; + } +} + + /* * +Thread+ encapsulates the behavior of a thread of * execution, including the main thread of the Ruby script. -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/