From: nobu.nakada@... Date: 2000-10-28T14:18:49+09:00 Subject: [ruby-list:25662] Re: ブロックの返り値 なかだです。 At Sat, 28 Oct 2000 11:58:42 +0900, matz@zetabits.com (Yukihiro Matsumoto) wrote: > |途中でブロックを値を返しつつ抜けたい場合は、 > |throw/catchするか、raiseするか、 > |goto(はないんでしたっけ)するか、しかないでしょうか > > いまんとこないですね。 break true みたいなのとか。 ちょっと試しに作ってみたパッチ。 diff -up .#eval.c.1.123 eval.c --- .#eval.c.1.123 Sat Oct 21 09:45:02 2000 +++ eval.c Sat Oct 28 14:15:40 2000 @@ -732,7 +732,6 @@ static struct tag *prot_tag; #define PUSH_TAG(ptag) { \ struct tag _tag; \ - _tag.retval = Qnil; \ _tag.frame = ruby_frame; \ _tag.iter = ruby_iter; \ _tag.prev = prot_tag; \ @@ -2084,6 +2083,7 @@ rb_eval(self, n) case NODE_WHILE: PUSH_TAG(PROT_NONE); + result = Qnil; switch (state = EXEC_TAG()) { case 0: ruby_sourceline = nd_line(node); @@ -2104,6 +2104,7 @@ rb_eval(self, n) state = 0; goto while_next; case TAG_BREAK: + result = prot_tag->retval; state = 0; default: break; @@ -2111,10 +2112,11 @@ rb_eval(self, n) while_out: POP_TAG(); if (state) JUMP_TAG(state); - RETURN(Qnil); + break; case NODE_UNTIL: PUSH_TAG(PROT_NONE); + result = Qnil; switch (state = EXEC_TAG()) { case 0: if (node->nd_state && RTEST(rb_eval(self, node->nd_cond))) @@ -2134,6 +2136,7 @@ rb_eval(self, n) state = 0; goto until_next; case TAG_BREAK: + result = prot_tag->retval; state = 0; default: break; @@ -2141,7 +2144,7 @@ rb_eval(self, n) until_out: POP_TAG(); if (state) JUMP_TAG(state); - RETURN(Qnil); + break; case NODE_BLOCK_PASS: result = block_pass(self, node); @@ -2177,7 +2180,7 @@ rb_eval(self, n) } else if (_block.tag->dst == state) { state &= TAG_MASK; - if (state == TAG_RETURN) { + if (state == TAG_RETURN || state == TAG_BREAK) { result = prot_tag->retval; } } @@ -2191,7 +2194,6 @@ rb_eval(self, n) goto iter_retry; case TAG_BREAK: - result = Qnil; break; case TAG_RETURN: return_value(result); @@ -2203,6 +2205,12 @@ rb_eval(self, n) break; case NODE_BREAK: + if (node->nd_stts) { + return_value(rb_eval(self, node->nd_stts)); + } + else { + return_value(Qnil); + } JUMP_TAG(TAG_BREAK); break; @@ -3242,11 +3250,19 @@ rb_f_abort() } void -rb_iter_break() +rb_break(val) + VALUE val; { + return_value(val); JUMP_TAG(TAG_BREAK); } +void +rb_iter_break() +{ + rb_break(Qnil); +} + static void rb_longjmp _((int, VALUE)) NORETURN; static VALUE make_backtrace _((void)); @@ -3704,7 +3720,6 @@ rb_iterate(it_proc, data1, bl_proc, data goto iter_retry; case TAG_BREAK: - retval = Qnil; break; case TAG_RETURN: @@ -6103,6 +6118,7 @@ proc_call(proc, args) if (state) { switch (state) { case TAG_BREAK: + result = prot_tag->retval; break; case TAG_RETRY: rb_raise(rb_eLocalJumpError, "retry from proc-closure"); diff -up .#gc.c.1.41 gc.c --- .#gc.c.1.41 Tue Oct 24 01:07:47 2000 +++ gc.c Sat Oct 28 13:06:27 2000 @@ -498,6 +498,7 @@ rb_gc_mark(ptr) case NODE_DEFINED: case NODE_MATCH: case NODE_RETURN: + case NODE_BREAK: case NODE_YIELD: case NODE_COLON2: case NODE_ARGS: @@ -525,7 +526,6 @@ rb_gc_mark(ptr) case NODE_BACK_REF: case NODE_ALIAS: case NODE_VALIAS: - case NODE_BREAK: case NODE_NEXT: case NODE_REDO: case NODE_RETRY: diff -up .#node.h.1.16 node.h --- .#node.h.1.16 Fri Sep 8 06:19:08 2000 +++ node.h Sat Oct 28 13:05:44 2000 @@ -244,7 +244,7 @@ typedef struct RNode { #define NEW_UNTIL(c,b,n) rb_node_newnode(NODE_UNTIL,c,b,n) #define NEW_FOR(v,i,b) rb_node_newnode(NODE_FOR,v,b,i) #define NEW_ITER(v,i,b) rb_node_newnode(NODE_ITER,v,b,i) -#define NEW_BREAK() rb_node_newnode(NODE_BREAK,0,0,0) +#define NEW_BREAK(s) rb_node_newnode(NODE_BREAK,s,0,0) #define NEW_NEXT() rb_node_newnode(NODE_NEXT,0,0,0) #define NEW_REDO() rb_node_newnode(NODE_REDO,0,0,0) #define NEW_RETRY() rb_node_newnode(NODE_RETRY,0,0,0) diff -up .#parse.y.1.64 parse.y --- .#parse.y.1.64 Sat Oct 21 06:19:21 2000 +++ parse.y Sat Oct 28 14:13:50 2000 @@ -421,6 +421,10 @@ expr : mlhs '=' mrhs yyerror("return appeared outside of method"); $$ = NEW_RETURN($2); } + | kBREAK ret_args + { + $$ = NEW_BREAK($2); + } | command_call | expr kAND expr { @@ -1292,9 +1296,18 @@ primary : literal local_pop(); in_single--; } + | kBREAK '(' ret_args ')' + { + value_expr($3); + $$ = NEW_BREAK($3); + } + | kBREAK '(' ')' + { + $$ = NEW_BREAK(0); + } | kBREAK { - $$ = NEW_BREAK(); + $$ = NEW_BREAK(0); } | kNEXT { @@ -4185,8 +4198,6 @@ value_expr(node) case NODE_NEXT: case NODE_REDO: case NODE_RETRY: - case NODE_WHILE: - case NODE_UNTIL: case NODE_CLASS: case NODE_MODULE: case NODE_DEFN: diff -up .#ruby.h.1.27 ruby.h --- .#ruby.h.1.27 Mon Oct 16 23:19:17 2000 +++ ruby.h Sat Oct 28 14:04:56 2000 @@ -456,6 +456,7 @@ void rb_raise __((VALUE, const char*, .. void rb_fatal __((const char*, ...)) NORETURN; void rb_bug __((const char*, ...)) NORETURN; void rb_sys_fail _((const char*)) NORETURN; +void rb_break _((VALUE)) NORETURN; void rb_iter_break _((void)) NORETURN; void rb_exit _((int)) NORETURN; void rb_notimplement _((void)) NORETURN; -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦