* variable.c (rb_alias_variable): should not allow variable

aliasing if $SAFE >= 4.

* parse.y (expr): "break" and "next" to take optional expression,
  which is used as a value for termination. [new, experimental]

* eval.c (rb_eval): "break" can give value to terminating method.

* eval.c (rb_eval): "break" and "next" to take optional expression.

* eval.c (rb_yield_0): "next" can give value to terminating "yield".

* eval.c (rb_iterate): "break" can give value to terminating method.

* eval.c (proc_call): ditto.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1441 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2001-05-22 08:28:11 +00:00
parent ed6a2bd29f
commit 315cd83418
6 changed files with 88 additions and 48 deletions

View File

@ -1,3 +1,23 @@
Tue May 22 17:10:35 2001 K.Kosako <kosako@sofnec.co.jp>
* variable.c (rb_alias_variable): should not allow variable
aliasing if $SAFE >= 4.
Tue May 22 02:37:45 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (expr): "break" and "next" to take optional expression,
which is used as a value for termination. [new, experimental]
* eval.c (rb_eval): "break" can give value to terminating method.
* eval.c (rb_eval): "break" and "next" to take optional expression.
* eval.c (rb_yield_0): "next" can give value to terminating "yield".
* eval.c (rb_iterate): "break" can give value to terminating method.
* eval.c (proc_call): ditto.
Mon May 21 13:15:25 2001 Yukihiro Matsumoto <matz@ruby-lang.org> Mon May 21 13:15:25 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* bignum.c (rb_big2str): t should be protected from GC. * bignum.c (rb_big2str): t should be protected from GC.

33
eval.c
View File

@ -2288,7 +2288,7 @@ rb_eval(self, n)
} }
else if (_block.tag->dst == state) { else if (_block.tag->dst == state) {
state &= TAG_MASK; state &= TAG_MASK;
if (state == TAG_RETURN) { if (state == TAG_RETURN || state == TAG_BREAK) {
result = prot_tag->retval; result = prot_tag->retval;
} }
} }
@ -2302,8 +2302,8 @@ rb_eval(self, n)
goto iter_retry; goto iter_retry;
case TAG_BREAK: case TAG_BREAK:
result = Qnil;
break; break;
case TAG_RETURN: case TAG_RETURN:
return_value(result); return_value(result);
/* fall through */ /* fall through */
@ -2314,10 +2314,22 @@ rb_eval(self, n)
break; break;
case NODE_BREAK: case NODE_BREAK:
if (node->nd_stts) {
return_value(rb_eval(self, node->nd_stts));
}
else {
return_value(Qnil);
}
JUMP_TAG(TAG_BREAK); JUMP_TAG(TAG_BREAK);
break; break;
case NODE_NEXT: case NODE_NEXT:
if (node->nd_stts) {
return_value(rb_eval(self, node->nd_stts));
}
else {
return_value(Qnil);
}
JUMP_TAG(TAG_NEXT); JUMP_TAG(TAG_NEXT);
break; break;
@ -3574,6 +3586,12 @@ rb_yield_0(val, self, klass, acheck)
RARRAY(val)->len); RARRAY(val)->len);
} }
} }
else if (block->var == (NODE*)2) {
if (val != Qundef && TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) {
rb_raise(rb_eArgError, "wrong # of arguments (%d for 0)",
RARRAY(val)->len);
}
}
else { else {
if (nd_type(block->var) == NODE_MASGN) if (nd_type(block->var) == NODE_MASGN)
massign(self, block->var, val, acheck); massign(self, block->var, val, acheck);
@ -3614,7 +3632,7 @@ rb_yield_0(val, self, klass, acheck)
goto redo; goto redo;
case TAG_NEXT: case TAG_NEXT:
state = 0; state = 0;
result = Qnil; result = prot_tag->retval;
break; break;
case TAG_BREAK: case TAG_BREAK:
case TAG_RETURN: case TAG_RETURN:
@ -3842,7 +3860,7 @@ rb_iterate(it_proc, data1, bl_proc, data2)
} }
if (ruby_block->tag->dst == state) { if (ruby_block->tag->dst == state) {
state &= TAG_MASK; state &= TAG_MASK;
if (state == TAG_RETURN) { if (state == TAG_RETURN || state == TAG_BREAK) {
retval = prot_tag->retval; retval = prot_tag->retval;
} }
} }
@ -3858,7 +3876,6 @@ rb_iterate(it_proc, data1, bl_proc, data2)
goto iter_retry; goto iter_retry;
case TAG_BREAK: case TAG_BREAK:
retval = Qnil;
break; break;
case TAG_RETURN: case TAG_RETURN:
@ -6343,9 +6360,11 @@ proc_call(proc, args)
ruby_block = old_block; ruby_block = old_block;
ruby_safe_level = safe; ruby_safe_level = safe;
if (state) {
switch (state) { switch (state) {
case 0:
break;
case TAG_BREAK: case TAG_BREAK:
result = prot_tag->retval;
break; break;
case TAG_RETRY: case TAG_RETRY:
rb_raise(rb_eLocalJumpError, "retry from proc-closure"); rb_raise(rb_eLocalJumpError, "retry from proc-closure");
@ -6358,7 +6377,6 @@ proc_call(proc, args)
default: default:
JUMP_TAG(state); JUMP_TAG(state);
} }
}
return result; return result;
} }
@ -6373,6 +6391,7 @@ proc_arity(proc)
Data_Get_Struct(proc, struct BLOCK, data); Data_Get_Struct(proc, struct BLOCK, data);
if (data->var == 0) return INT2FIX(-1); if (data->var == 0) return INT2FIX(-1);
if (data->var == (NODE*)1) return INT2FIX(0); if (data->var == (NODE*)1) return INT2FIX(0);
if (data->var == (NODE*)2) return INT2FIX(0);
switch (nd_type(data->var)) { switch (nd_type(data->var)) {
default: default:
return INT2FIX(-1); return INT2FIX(-1);

4
node.h
View File

@ -248,8 +248,8 @@ typedef struct RNode {
#define NEW_UNTIL(c,b,n) rb_node_newnode(NODE_UNTIL,c,b,n) #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_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_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_NEXT(s) rb_node_newnode(NODE_NEXT,s,0,0)
#define NEW_REDO() rb_node_newnode(NODE_REDO,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) #define NEW_RETRY() rb_node_newnode(NODE_RETRY,0,0,0)
#define NEW_BEGIN(b) rb_node_newnode(NODE_BEGIN,0,b,0) #define NEW_BEGIN(b) rb_node_newnode(NODE_BEGIN,0,b,0)

49
parse.y
View File

@ -426,21 +426,13 @@ expr : kRETURN ret_args
yyerror("return appeared outside of method"); yyerror("return appeared outside of method");
$$ = NEW_RETURN($2); $$ = NEW_RETURN($2);
} }
| kBREAK | kBREAK ret_args
{ {
$$ = NEW_BREAK(); $$ = NEW_BREAK($2);
} }
| kNEXT | kNEXT ret_args
{ {
$$ = NEW_NEXT(); $$ = NEW_NEXT($2);
}
| kREDO
{
$$ = NEW_REDO();
}
| kRETRY
{
$$ = NEW_RETRY();
} }
| command_call | command_call
| expr kAND expr | expr kAND expr
@ -1142,19 +1134,6 @@ primary : literal
{ {
$$ = NEW_HASH($2); $$ = NEW_HASH($2);
} }
| kRETURN '(' ret_args ')'
{
if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method");
value_expr($3);
$$ = NEW_RETURN($3);
}
| kRETURN '(' ')'
{
if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method");
$$ = NEW_RETURN(0);
}
| kRETURN | kRETURN
{ {
if (!compile_for_eval && !in_def && !in_single) if (!compile_for_eval && !in_def && !in_single)
@ -1359,6 +1338,22 @@ primary : literal
local_pop(); local_pop();
in_single--; in_single--;
} }
| kBREAK
{
$$ = NEW_BREAK(0);
}
| kNEXT
{
$$ = NEW_NEXT(0);
}
| kREDO
{
$$ = NEW_REDO();
}
| kRETRY
{
$$ = NEW_RETRY();
}
then : term then : term
| kTHEN | kTHEN
@ -1399,6 +1394,10 @@ opt_block_var : none
{ {
$$ = $2; $$ = $2;
} }
| '<' f_args '>'
{
$$ = (NODE*)2;
}
do_block : kDO_BLOCK do_block : kDO_BLOCK

View File

@ -700,6 +700,8 @@ rb_alias_variable(name1, name2)
{ {
struct global_entry *entry1, *entry2; struct global_entry *entry1, *entry2;
if (rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't alias global variable");
entry1 = rb_global_entry(name1); entry1 = rb_global_entry(name1);
entry2 = rb_global_entry(name2); entry2 = rb_global_entry(name2);

View File

@ -1,4 +1,4 @@
#define RUBY_VERSION "1.7.0" #define RUBY_VERSION "1.7.0"
#define RUBY_RELEASE_DATE "2001-05-21" #define RUBY_RELEASE_DATE "2001-05-22"
#define RUBY_VERSION_CODE 170 #define RUBY_VERSION_CODE 170
#define RUBY_RELEASE_CODE 20010521 #define RUBY_RELEASE_CODE 20010522