Feature #10481 » rescue-conditions.diff
| compile.c | ||
|---|---|---|
| 
     	ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart); 
   | 
||
| 
     	break; 
   | 
||
| 
           } 
   | 
||
| 
           case NODE_RESCOND: 
   | 
||
| 
           case NODE_RESBODY:{ 
   | 
||
| 
     	NODE *resq = node; 
   | 
||
| 
     	NODE *narg; 
   | 
||
| 
     	LABEL *label_miss, *label_hit; 
   | 
||
| 
     	NODE *narg, *cond; 
   | 
||
| 
     	LABEL *label_miss, *label_hit, *label_pass; 
   | 
||
| 
     	while (resq) { 
   | 
||
| 
     	    label_miss = NEW_LABEL(line); 
   | 
||
| 
     	    label_hit = NEW_LABEL(line); 
   | 
||
| 
     	    if (nd_type(resq) == NODE_RESCOND) { 
   | 
||
| 
     	        label_pass = NEW_LABEL(line); 
   | 
||
| 
     	        cond = resq->nd_cond; 
   | 
||
| 
     	        resq = resq->nd_resq; 
   | 
||
| 
     	    } 
   | 
||
| 
     	    else { 
   | 
||
| 
     	        cond = 0; 
   | 
||
| 
     	    } 
   | 
||
| 
     	    narg = resq->nd_args; 
   | 
||
| 
     	    if (narg) { 
   | 
||
| 
     		switch (nd_type(narg)) { 
   | 
||
| ... | ... | |
| 
     	    } 
   | 
||
| 
     	    ADD_INSNL(ret, line, jump, label_miss); 
   | 
||
| 
     	    ADD_LABEL(ret, label_hit); 
   | 
||
| 
     	    if (cond) { 
   | 
||
| 
     	        switch (nd_type(cond)) { 
   | 
||
| 
     	          case NODE_RESCOND_IF: 
   | 
||
| 
     	            compile_branch_condition(iseq, ret, cond->nd_cond, label_pass, label_miss); 
   | 
||
| 
     	            break; 
   | 
||
| 
     	          case NODE_RESCOND_UNLESS: 
   | 
||
| 
     	            compile_branch_condition(iseq, ret, cond->nd_cond, label_miss, label_pass); 
   | 
||
| 
     	            break; 
   | 
||
| 
     	          default: 
   | 
||
| 
     	            rb_bug("NODE_RESCOND: unknown node (%s)", 
   | 
||
| 
     	               ruby_node_name(nd_type(cond))); 
   | 
||
| 
     	        } 
   | 
||
| 
     	        ADD_LABEL(ret, label_pass); 
   | 
||
| 
     	    } 
   | 
||
| 
     	    COMPILE(ret, "resbody body", resq->nd_body); 
   | 
||
| 
     	    if (iseq->compile_data->option->tailcall_optimization) { 
   | 
||
| 
     		ADD_INSN(ret, line, nop); 
   | 
||
| ext/objspace/objspace.c | ||
|---|---|---|
| 
     		COUNT_NODE(NODE_BEGIN); 
   | 
||
| 
     		COUNT_NODE(NODE_RESCUE); 
   | 
||
| 
     		COUNT_NODE(NODE_RESBODY); 
   | 
||
| 
     		COUNT_NODE(NODE_RESCOND); 
   | 
||
| 
     		COUNT_NODE(NODE_RESCOND_IF); 
   | 
||
| 
     		COUNT_NODE(NODE_RESCOND_UNLESS); 
   | 
||
| 
     		COUNT_NODE(NODE_ENSURE); 
   | 
||
| 
     		COUNT_NODE(NODE_AND); 
   | 
||
| 
     		COUNT_NODE(NODE_OR); 
   | 
||
| gc.c | ||
|---|---|---|
| 
     	  case NODE_ALIAS: 
   | 
||
| 
     	  case NODE_VALIAS: 
   | 
||
| 
     	  case NODE_ARGSCAT: 
   | 
||
| 
     	  case NODE_RESCOND: 
   | 
||
| 
     	    gc_mark(objspace, (VALUE)obj->as.node.u1.node); 
   | 
||
| 
     	    /* fall through */ 
   | 
||
| 
     	  case NODE_GASGN:	/* 2 */ 
   | 
||
| ... | ... | |
| 
     	  case NODE_COLON2: 
   | 
||
| 
     	  case NODE_SPLAT: 
   | 
||
| 
     	  case NODE_TO_ARY: 
   | 
||
| 
     	  case NODE_RESCOND_IF: 
   | 
||
| 
     	  case NODE_RESCOND_UNLESS: 
   | 
||
| 
     	    ptr = (VALUE)obj->as.node.u1.node; 
   | 
||
| 
     	    goto again; 
   | 
||
| node.c | ||
|---|---|---|
| 
     	F_NODE(nd_head, "next rescue clause"); 
   | 
||
| 
     	break; 
   | 
||
| 
           case NODE_RESCOND: 
   | 
||
| 
     	ANN("conditional rescue"); 
   | 
||
| 
     	ANN("format: (rescue) [nd_body] (if or unless) [nd_cond]"); 
   | 
||
| 
     	F_NODE(nd_cond, "rescue condition"); 
   | 
||
| 
     	LAST_NODE; 
   | 
||
| 
     	F_NODE(nd_resq, "rescue clause"); 
   | 
||
| 
     	break; 
   | 
||
| 
           case NODE_RESCOND_IF: 
   | 
||
| 
     	ANN("conditional rescue if modifier"); 
   | 
||
| 
     	ANN("format: if [nd_cond]"); 
   | 
||
| 
     	LAST_NODE; 
   | 
||
| 
     	F_NODE(nd_cond, "condition"); 
   | 
||
| 
     	break; 
   | 
||
| 
           case NODE_RESCOND_UNLESS: 
   | 
||
| 
     	ANN("conditional rescue unless modifier"); 
   | 
||
| 
     	ANN("format: unless [nd_cond]"); 
   | 
||
| 
     	LAST_NODE; 
   | 
||
| 
     	F_NODE(nd_cond, "condition"); 
   | 
||
| 
     	break; 
   | 
||
| 
           case NODE_ENSURE: 
   | 
||
| 
     	ANN("ensure clause"); 
   | 
||
| 
     	ANN("format: begin; [nd_head]; ensure; [nd_ensr]; end"); 
   | 
||
| node.h | ||
|---|---|---|
| 
     #define NODE_RESCUE      NODE_RESCUE 
   | 
||
| 
         NODE_RESBODY, 
   | 
||
| 
     #define NODE_RESBODY     NODE_RESBODY 
   | 
||
| 
         NODE_RESCOND, 
   | 
||
| 
     #define NODE_RESCOND     NODE_RESCOND 
   | 
||
| 
         NODE_RESCOND_IF, 
   | 
||
| 
     #define NODE_RESCOND_IF     NODE_RESCOND_IF 
   | 
||
| 
         NODE_RESCOND_UNLESS, 
   | 
||
| 
     #define NODE_RESCOND_UNLESS     NODE_RESCOND_UNLESS 
   | 
||
| 
         NODE_ENSURE, 
   | 
||
| 
     #define NODE_ENSURE      NODE_ENSURE 
   | 
||
| 
         NODE_AND, 
   | 
||
| ... | ... | |
| 
     #define NEW_BEGIN(b) NEW_NODE(NODE_BEGIN,0,b,0) 
   | 
||
| 
     #define NEW_RESCUE(b,res,e) NEW_NODE(NODE_RESCUE,b,res,e) 
   | 
||
| 
     #define NEW_RESBODY(a,ex,n) NEW_NODE(NODE_RESBODY,n,ex,a) 
   | 
||
| 
     #define NEW_RESCOND(c,b) NEW_NODE(NODE_RESCOND,c,b,0) 
   | 
||
| 
     #define NEW_RESCOND_IF(c) NEW_NODE(NODE_RESCOND_IF,c,0,0) 
   | 
||
| 
     #define NEW_RESCOND_UNLESS(c) NEW_NODE(NODE_RESCOND_UNLESS,c,0,0) 
   | 
||
| 
     #define NEW_ENSURE(b,en) NEW_NODE(NODE_ENSURE,b,0,en) 
   | 
||
| 
     #define NEW_RETURN(s) NEW_NODE(NODE_RETURN,s,0,0) 
   | 
||
| 
     #define NEW_YIELD(a) NEW_NODE(NODE_YIELD,a,0,0) 
   | 
||
| parse.y | ||
|---|---|---|
| 
     %type <node> top_compstmt top_stmts top_stmt 
   | 
||
| 
     %type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call 
   | 
||
| 
     %type <node> expr_value arg_value primary_value fcall 
   | 
||
| 
     %type <node> if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure 
   | 
||
| 
     %type <node> if_tail opt_else case_body cases opt_rescue exc_cond exc_list exc_var opt_ensure 
   | 
||
| 
     %type <node> args call_args opt_call_args 
   | 
||
| 
     %type <node> paren_args opt_paren_args args_tail opt_args_tail block_args_tail opt_block_args_tail 
   | 
||
| 
     %type <node> command_args aref_args opt_block_arg block_arg var_ref var_lhs 
   | 
||
| ... | ... | |
| 
     		| case_body 
   | 
||
| 
     		; 
   | 
||
| 
     opt_rescue	: keyword_rescue exc_list exc_var then 
   | 
||
| 
     opt_rescue	: keyword_rescue exc_list exc_var exc_cond then 
   | 
||
| 
     		  compstmt 
   | 
||
| 
     		  opt_rescue 
   | 
||
| 
     		    { 
   | 
||
| 
     		    /*%%%*/ 
   | 
||
| 
     			if ($3) { 
   | 
||
| 
     			    $3 = node_assign($3, NEW_ERRINFO()); 
   | 
||
| 
     			    $5 = block_append($3, $5); 
   | 
||
| 
     			    if ($4) { 
   | 
||
| 
     			      $4->nd_cond = block_append($3, $4->nd_cond); 
   | 
||
| 
     			    } 
   | 
||
| 
     			    else { 
   | 
||
| 
     			      $6 = block_append($3, $6); 
   | 
||
| 
     			    } 
   | 
||
| 
     			} 
   | 
||
| 
     			$$ = NEW_RESBODY($2, $6, $7); 
   | 
||
| 
     			if ($4) { 
   | 
||
| 
     			    $$ = NEW_RESCOND($4, $$); 
   | 
||
| 
     			} 
   | 
||
| 
     			$$ = NEW_RESBODY($2, $5, $6); 
   | 
||
| 
     			fixpos($$, $2?$2:$5); 
   | 
||
| 
     			fixpos($$, $2?$2:$6); 
   | 
||
| 
     		    /*% 
   | 
||
| 
     			$$ = dispatch4(rescue, 
   | 
||
| 
     			$$ = dispatch5(rescue, 
   | 
||
| 
     				       escape_Qundef($2), 
   | 
||
| 
     				       escape_Qundef($3), 
   | 
||
| 
     				       escape_Qundef($5), 
   | 
||
| 
     				       escape_Qundef($6)); 
   | 
||
| 
     				       escape_Qundef($4), 
   | 
||
| 
     				       escape_Qundef($6), 
   | 
||
| 
     				       escape_Qundef($7)); 
   | 
||
| 
     		    %*/ 
   | 
||
| 
     		    } 
   | 
||
| 
     		| none 
   | 
||
| 
     		; 
   | 
||
| 
     exc_cond	: modifier_if expr_value 
   | 
||
| 
     		    { 
   | 
||
| 
     		    /*%%%*/ 
   | 
||
| 
     			$$ = NEW_RESCOND_IF(cond($2)); 
   | 
||
| 
     		    /*% 
   | 
||
| 
     			$$ = dispatch1(rescond_if, $2); 
   | 
||
| 
     		    %*/ 
   | 
||
| 
     		    } 
   | 
||
| 
     		| modifier_unless expr_value 
   | 
||
| 
     		    { 
   | 
||
| 
     		    /*%%%*/ 
   | 
||
| 
     			$$ = NEW_RESCOND_UNLESS(cond($2)); 
   | 
||
| 
     		    /*% 
   | 
||
| 
     			$$ = dispatch1(rescond_unless, $2); 
   | 
||
| 
     		    %*/ 
   | 
||
| 
     		    } 
   | 
||
| 
     		| none 
   | 
||