mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* eval.c (Init_Proc): Block/Proc separation. [huge change]
* eval.c (block_arity): returns exact arity number for Procs out of methods. also gives 1 for {|a|..}. * string.c (rb_str_match): revert use of String#index for invocation like string =~ string. * eval.c (rb_Array): move Object#to_a exclusion hack from splat_value(). need to be in eval.c for a while. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3867 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
ea325deab0
commit
b4fd4d6018
7 changed files with 341 additions and 170 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
Mon May 26 16:39:10 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* eval.c (Init_Proc): Block/Proc separation. [huge change]
|
||||
|
||||
* eval.c (block_arity): returns exact arity number for Procs out
|
||||
of methods. also gives 1 for {|a|..}.
|
||||
|
||||
* string.c (rb_str_match): revert use of String#index for
|
||||
invocation like string =~ string.
|
||||
|
||||
* eval.c (rb_Array): move Object#to_a exclusion hack from
|
||||
splat_value(). need to be in eval.c for a while.
|
||||
|
||||
Sun May 25 23:48:21 2003 Nobuyoshi Nakada <nobu.nokada@softhome.net>
|
||||
|
||||
* bignum.c (rb_quad_pack): should negate negative bignum.
|
||||
|
|
320
eval.c
320
eval.c
|
@ -93,9 +93,10 @@ char *strrchr _((const char*,const char));
|
|||
|
||||
#include <sys/stat.h>
|
||||
|
||||
VALUE rb_cProc;
|
||||
VALUE rb_cBlock, rb_cProc;
|
||||
static VALUE rb_cBinding;
|
||||
static VALUE proc_invoke _((VALUE,VALUE,int,VALUE));
|
||||
static VALUE block_invoke _((VALUE,VALUE,VALUE));
|
||||
static VALUE block_new _((void));
|
||||
static VALUE rb_f_binding _((VALUE));
|
||||
static void rb_f_END _((void));
|
||||
static VALUE rb_f_block_given_p _((void));
|
||||
|
@ -627,6 +628,7 @@ struct BLOCK {
|
|||
struct RVarmap *dyna_vars;
|
||||
VALUE orig_thread;
|
||||
VALUE wrapper;
|
||||
VALUE block_obj;
|
||||
struct BLOCK *outer;
|
||||
struct BLOCK *prev;
|
||||
};
|
||||
|
@ -634,6 +636,7 @@ struct BLOCK {
|
|||
#define BLOCK_D_SCOPE 1
|
||||
#define BLOCK_DYNAMIC 2
|
||||
#define BLOCK_ORPHAN 4
|
||||
#define BLOCK_PROC 8
|
||||
|
||||
static struct BLOCK *ruby_block;
|
||||
|
||||
|
@ -664,6 +667,7 @@ new_blktag()
|
|||
_block.flags = BLOCK_D_SCOPE; \
|
||||
_block.dyna_vars = ruby_dyna_vars; \
|
||||
_block.wrapper = ruby_wrapper; \
|
||||
_block.block_obj = 0; \
|
||||
ruby_block = &_block
|
||||
|
||||
#define POP_BLOCK() \
|
||||
|
@ -2237,13 +2241,13 @@ call_trace_func(event, node, self, id, klass)
|
|||
PUSH_TAG(PROT_NONE);
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)");
|
||||
proc_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event),
|
||||
block_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event),
|
||||
srcfile,
|
||||
INT2FIX(ruby_sourceline),
|
||||
id?ID2SYM(id):Qnil,
|
||||
self?rb_f_binding(self):Qnil,
|
||||
klass),
|
||||
Qtrue, Qundef);
|
||||
Qundef);
|
||||
}
|
||||
POP_TMPTAG(); /* do not propagate retval */
|
||||
POP_FRAME();
|
||||
|
@ -2333,29 +2337,40 @@ avalue_splat(v)
|
|||
return v;
|
||||
}
|
||||
|
||||
#if 1
|
||||
VALUE
|
||||
rb_Array(val)
|
||||
VALUE val;
|
||||
{
|
||||
VALUE tmp = rb_check_array_type(val);
|
||||
ID to_a;
|
||||
|
||||
if (NIL_P(tmp)) {
|
||||
/* hack to avoid invoke Object#to_a */
|
||||
VALUE origin;
|
||||
ID id = rb_intern("to_a");
|
||||
|
||||
if (search_method(CLASS_OF(val), id, &origin) &&
|
||||
origin != RCLASS(rb_cObject)->super) { /* exclude Object#to_a */
|
||||
val = rb_funcall(val, id, 0);
|
||||
if (TYPE(val) != T_ARRAY) {
|
||||
rb_raise(rb_eTypeError, "`to_a' did not return Array");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
return rb_ary_new3(1, val);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
splat_value(v)
|
||||
VALUE v;
|
||||
{
|
||||
if (NIL_P(v)) return rb_ary_new3(1, Qnil);
|
||||
#if 1
|
||||
/* hack to avoid invoke Object#to_a */
|
||||
if (TYPE(v) != T_ARRAY) {
|
||||
VALUE tmp = rb_check_array_type(v);
|
||||
if (NIL_P(tmp)) {
|
||||
VALUE origin;
|
||||
ID id = rb_intern("to_a");
|
||||
|
||||
if (search_method(CLASS_OF(v), id, &origin) &&
|
||||
origin != RCLASS(rb_cObject)->super) { /* exclude Object#to_a */
|
||||
return rb_funcall(v, id, 0);
|
||||
}
|
||||
else {
|
||||
return rb_ary_new3(1, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rb_Array(v);
|
||||
}
|
||||
|
||||
|
@ -2759,7 +2774,7 @@ rb_eval(self, n)
|
|||
result = Qundef; /* no arg */
|
||||
}
|
||||
SET_CURRENT_SOURCE();
|
||||
result = rb_yield_0(result, 0, 0, 0, 0);
|
||||
result = rb_yield_0(result, 0, 0, Qfalse, Qfalse);
|
||||
break;
|
||||
|
||||
case NODE_RESCUE:
|
||||
|
@ -3204,7 +3219,7 @@ rb_eval(self, n)
|
|||
if (ruby_scope->local_vars == 0)
|
||||
rb_bug("unexpected block argument");
|
||||
if (rb_block_given_p()) {
|
||||
result = rb_f_lambda();
|
||||
result = block_new();
|
||||
ruby_scope->local_vars[node->nd_cnt] = result;
|
||||
}
|
||||
else {
|
||||
|
@ -4158,7 +4173,7 @@ VALUE
|
|||
rb_yield(val)
|
||||
VALUE val;
|
||||
{
|
||||
return rb_yield_0(val, 0, 0, 0, 0);
|
||||
return rb_yield_0(val, 0, 0, Qfalse, Qfalse);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -4171,21 +4186,25 @@ rb_yield_values(int n, va_alist)
|
|||
#endif
|
||||
{
|
||||
va_list args;
|
||||
VALUE ary = rb_ary_new2(n);
|
||||
VALUE ary;
|
||||
|
||||
if (n == 0) {
|
||||
return rb_yield_0(Qundef, 0, 0, Qfalse, Qfalse);
|
||||
}
|
||||
ary = rb_ary_new2(n);
|
||||
va_init_list(args, n);
|
||||
while (n--) {
|
||||
rb_ary_push(ary, va_arg(args, VALUE));
|
||||
}
|
||||
va_end(args);
|
||||
return rb_yield_0(ary, 0, 0, 0, Qtrue);
|
||||
return rb_yield_0(ary, 0, 0, Qfalse, Qtrue);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_f_loop()
|
||||
{
|
||||
for (;;) {
|
||||
rb_yield_0(Qundef, 0, 0, 0, 0);
|
||||
rb_yield_0(Qundef, 0, 0, Qfalse, Qfalse);
|
||||
CHECK_INTS;
|
||||
}
|
||||
return Qnil; /* dummy */
|
||||
|
@ -4866,7 +4885,7 @@ rb_call0(klass, recv, id, oid, argc, argv, body, nosuper)
|
|||
break;
|
||||
|
||||
case NODE_BMETHOD:
|
||||
result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), Qtrue, recv);
|
||||
result = block_invoke(body->nd_cval, rb_ary_new4(argc, argv), recv);
|
||||
break;
|
||||
|
||||
case NODE_SCOPE:
|
||||
|
@ -5550,7 +5569,7 @@ static VALUE
|
|||
yield_under_i(self)
|
||||
VALUE self;
|
||||
{
|
||||
return rb_yield_0(self, self, ruby_class, 0, 0);
|
||||
return rb_yield_0(self, self, ruby_class, Qfalse, Qfalse);
|
||||
}
|
||||
|
||||
/* block eval under the class/module context */
|
||||
|
@ -6345,7 +6364,7 @@ call_end_proc(data)
|
|||
ruby_frame->self = ruby_frame->prev->self;
|
||||
ruby_frame->last_func = 0;
|
||||
ruby_frame->last_class = 0;
|
||||
proc_invoke(data, rb_ary_new2(0), Qfalse, Qundef);
|
||||
block_invoke(data, rb_ary_new2(0), Qundef);
|
||||
POP_FRAME();
|
||||
POP_ITER();
|
||||
}
|
||||
|
@ -6557,6 +6576,7 @@ blk_mark(data)
|
|||
rb_gc_mark((VALUE)data->klass);
|
||||
rb_gc_mark((VALUE)data->tag);
|
||||
rb_gc_mark(data->wrapper);
|
||||
rb_gc_mark(data->block_obj);
|
||||
data = data->prev;
|
||||
}
|
||||
}
|
||||
|
@ -6637,14 +6657,14 @@ frame_dup(frame)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
bind_clone(self)
|
||||
block_clone(self)
|
||||
VALUE self;
|
||||
{
|
||||
struct BLOCK *orig, *data;
|
||||
VALUE bind;
|
||||
|
||||
Data_Get_Struct(self, struct BLOCK, orig);
|
||||
bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data);
|
||||
bind = Data_Make_Struct(rb_obj_class(self),struct BLOCK,blk_mark,blk_free,data);
|
||||
CLONESETUP(bind, self);
|
||||
MEMCPY(data, orig, struct BLOCK, 1);
|
||||
frame_dup(&data->frame);
|
||||
|
@ -6701,26 +6721,26 @@ rb_f_binding(self)
|
|||
return bind;
|
||||
}
|
||||
|
||||
#define PROC_T3 FL_USER1
|
||||
#define PROC_T4 FL_USER2
|
||||
#define PROC_TMAX (FL_USER1|FL_USER2)
|
||||
#define PROC_TMASK (FL_USER1|FL_USER2)
|
||||
#define BLOCK_T3 FL_USER1
|
||||
#define BLOCK_T4 FL_USER2
|
||||
#define BLOCK_TMAX (FL_USER1|FL_USER2)
|
||||
#define BLOCK_TMASK (FL_USER1|FL_USER2)
|
||||
|
||||
static void
|
||||
proc_save_safe_level(data)
|
||||
block_save_safe_level(data)
|
||||
VALUE data;
|
||||
{
|
||||
if (OBJ_TAINTED(data)) {
|
||||
switch (ruby_safe_level) {
|
||||
case 3:
|
||||
FL_SET(data, PROC_T3);
|
||||
FL_SET(data, BLOCK_T3);
|
||||
break;
|
||||
case 4:
|
||||
FL_SET(data, PROC_T4);
|
||||
FL_SET(data, BLOCK_T4);
|
||||
break;
|
||||
default:
|
||||
if (ruby_safe_level > 4) {
|
||||
FL_SET(data, PROC_TMAX);
|
||||
FL_SET(data, BLOCK_TMAX);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -6728,16 +6748,16 @@ proc_save_safe_level(data)
|
|||
}
|
||||
|
||||
static int
|
||||
proc_get_safe_level(data)
|
||||
block_get_safe_level(data)
|
||||
VALUE data;
|
||||
{
|
||||
if (OBJ_TAINTED(data)) {
|
||||
switch (RBASIC(data)->flags & PROC_TMASK) {
|
||||
case PROC_T3:
|
||||
switch (RBASIC(data)->flags & BLOCK_TMASK) {
|
||||
case BLOCK_T3:
|
||||
return 3;
|
||||
case PROC_T4:
|
||||
case BLOCK_T4:
|
||||
return 4;
|
||||
case PROC_TMAX:
|
||||
case BLOCK_TMAX:
|
||||
return 5;
|
||||
}
|
||||
return 3;
|
||||
|
@ -6746,27 +6766,34 @@ proc_get_safe_level(data)
|
|||
}
|
||||
|
||||
static void
|
||||
proc_set_safe_level(data)
|
||||
block_set_safe_level(data)
|
||||
VALUE data;
|
||||
{
|
||||
if (OBJ_TAINTED(data)) {
|
||||
ruby_safe_level = proc_get_safe_level(data);
|
||||
ruby_safe_level = block_get_safe_level(data);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
proc_new(klass)
|
||||
block_alloc(klass, proc)
|
||||
VALUE klass;
|
||||
int proc;
|
||||
{
|
||||
volatile VALUE proc;
|
||||
volatile VALUE block;
|
||||
struct BLOCK *data, *p;
|
||||
struct RVarmap *vars;
|
||||
|
||||
if (!rb_block_given_p() && !rb_f_block_given_p()) {
|
||||
rb_raise(rb_eArgError, "tried to create Proc object without a block");
|
||||
rb_raise(rb_eArgError, "tried to create Block object without a block");
|
||||
}
|
||||
|
||||
proc = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data);
|
||||
if (ruby_block->block_obj) {
|
||||
if ((proc && (ruby_block->flags & BLOCK_PROC)) ||
|
||||
(!proc && !(ruby_block->flags & BLOCK_PROC)))
|
||||
return ruby_block->block_obj;
|
||||
}
|
||||
block = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data);
|
||||
ruby_block->block_obj = block;
|
||||
*data = *ruby_block;
|
||||
|
||||
data->orig_thread = rb_thread_current();
|
||||
|
@ -6789,9 +6816,33 @@ proc_new(klass)
|
|||
}
|
||||
}
|
||||
scope_dup(data->scope);
|
||||
proc_save_safe_level(proc);
|
||||
block_save_safe_level(block);
|
||||
if (proc) data->flags |= BLOCK_PROC;
|
||||
|
||||
return proc;
|
||||
return block;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
block_s_new(argc, argv, klass)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
VALUE klass;
|
||||
{
|
||||
VALUE block = block_alloc(klass, Qfalse);
|
||||
|
||||
rb_obj_call_init(block, argc, argv);
|
||||
return block;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
block_new()
|
||||
{
|
||||
if (ruby_block->flags & BLOCK_PROC) {
|
||||
return block_alloc(rb_cProc, Qtrue);
|
||||
}
|
||||
else {
|
||||
return block_alloc(rb_cBlock, Qfalse);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -6800,20 +6851,20 @@ proc_s_new(argc, argv, klass)
|
|||
VALUE *argv;
|
||||
VALUE klass;
|
||||
{
|
||||
VALUE proc = proc_new(klass);
|
||||
VALUE block = block_alloc(klass, Qtrue);
|
||||
|
||||
rb_obj_call_init(proc, argc, argv);
|
||||
return proc;
|
||||
rb_obj_call_init(block, argc, argv);
|
||||
return block;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_f_lambda()
|
||||
{
|
||||
return proc_new(rb_cProc);
|
||||
return block_alloc(rb_cProc, Qtrue);
|
||||
}
|
||||
|
||||
static int
|
||||
blk_orphan(data)
|
||||
block_orphan(data)
|
||||
struct BLOCK *data;
|
||||
{
|
||||
if ((data->tag->flags & BLOCK_ORPHAN) &&
|
||||
|
@ -6827,9 +6878,8 @@ blk_orphan(data)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
proc_invoke(proc, args, pcall, self)
|
||||
VALUE proc, args; /* OK */
|
||||
int pcall;
|
||||
block_invoke(block, args, self)
|
||||
VALUE block, args; /* OK */
|
||||
VALUE self;
|
||||
{
|
||||
struct BLOCK * volatile old_block;
|
||||
|
@ -6841,15 +6891,17 @@ proc_invoke(proc, args, pcall, self)
|
|||
volatile int safe = ruby_safe_level;
|
||||
volatile VALUE old_wrapper = ruby_wrapper;
|
||||
struct RVarmap * volatile old_dvars = ruby_dyna_vars;
|
||||
int pcall;
|
||||
|
||||
if (rb_block_given_p() && ruby_frame->last_func) {
|
||||
rb_warning("block for %s#%s is useless",
|
||||
rb_obj_classname(proc),
|
||||
rb_obj_classname(block),
|
||||
rb_id2name(ruby_frame->last_func));
|
||||
}
|
||||
|
||||
Data_Get_Struct(proc, struct BLOCK, data);
|
||||
orphan = blk_orphan(data);
|
||||
Data_Get_Struct(block, struct BLOCK, data);
|
||||
orphan = block_orphan(data);
|
||||
pcall = data->flags & BLOCK_PROC;
|
||||
|
||||
ruby_wrapper = data->wrapper;
|
||||
ruby_dyna_vars = data->dyna_vars;
|
||||
|
@ -6864,7 +6916,7 @@ proc_invoke(proc, args, pcall, self)
|
|||
PUSH_TAG(PROT_NONE);
|
||||
state = EXEC_TAG();
|
||||
if (state == 0) {
|
||||
proc_set_safe_level(proc);
|
||||
block_set_safe_level(block);
|
||||
result = rb_yield_0(args, self, self!=Qundef?CLASS_OF(self):0, pcall, Qtrue);
|
||||
}
|
||||
POP_TAG();
|
||||
|
@ -6884,7 +6936,7 @@ proc_invoke(proc, args, pcall, self)
|
|||
break;
|
||||
case TAG_RETRY:
|
||||
if (pcall || orphan) {
|
||||
localjump_error("retry from proc-closure", Qnil, state);
|
||||
localjump_error("retry from block-closure", Qnil, state);
|
||||
}
|
||||
/* fall through */
|
||||
case TAG_BREAK:
|
||||
|
@ -6892,7 +6944,7 @@ proc_invoke(proc, args, pcall, self)
|
|||
result = prot_tag->retval;
|
||||
}
|
||||
else if (orphan) {
|
||||
localjump_error("break from proc-closure", prot_tag->retval, state);
|
||||
localjump_error("break from block-closure", prot_tag->retval, state);
|
||||
}
|
||||
else {
|
||||
ruby_block->tag->dst = incoming_state;
|
||||
|
@ -6900,8 +6952,8 @@ proc_invoke(proc, args, pcall, self)
|
|||
}
|
||||
break;
|
||||
case TAG_RETURN:
|
||||
if (orphan) { /* orphan procedure */
|
||||
localjump_error("return from proc-closure", prot_tag->retval, state);
|
||||
if (orphan) { /* orphan block */
|
||||
localjump_error("return from block-closure", prot_tag->retval, state);
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
|
@ -6911,34 +6963,36 @@ proc_invoke(proc, args, pcall, self)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
proc_call(proc, args)
|
||||
VALUE proc, args; /* OK */
|
||||
block_call(block, args)
|
||||
VALUE block, args; /* OK */
|
||||
{
|
||||
return proc_invoke(proc, args, Qtrue, Qundef);
|
||||
return block_invoke(block, args, Qundef);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
proc_yield(proc, args)
|
||||
VALUE proc, args; /* OK */
|
||||
{
|
||||
return proc_invoke(proc, args, Qfalse, Qundef);
|
||||
}
|
||||
static VALUE bmcall _((VALUE, VALUE));
|
||||
static VALUE method_arity _((VALUE));
|
||||
|
||||
static VALUE
|
||||
proc_arity(proc)
|
||||
VALUE proc;
|
||||
block_arity(block)
|
||||
VALUE block;
|
||||
{
|
||||
struct BLOCK *data;
|
||||
NODE *list;
|
||||
int n;
|
||||
|
||||
Data_Get_Struct(proc, struct BLOCK, data);
|
||||
if (data->var == 0) return INT2FIX(-1);
|
||||
Data_Get_Struct(block, struct BLOCK, data);
|
||||
if (data->var == 0) {
|
||||
if (data->body && nd_type(data->body) == NODE_IFUNC &&
|
||||
data->body->nd_cfnc == bmcall) {
|
||||
return method_arity(data->body->nd_tval);
|
||||
}
|
||||
return INT2FIX(-1);
|
||||
}
|
||||
if (data->var == (NODE*)1) return INT2FIX(0);
|
||||
if (data->var == (NODE*)2) return INT2FIX(0);
|
||||
switch (nd_type(data->var)) {
|
||||
default:
|
||||
return INT2FIX(-1);
|
||||
return INT2FIX(1);
|
||||
case NODE_MASGN:
|
||||
list = data->var->nd_head;
|
||||
n = 0;
|
||||
|
@ -6952,7 +7006,7 @@ proc_arity(proc)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
proc_eq(self, other)
|
||||
block_eq(self, other)
|
||||
VALUE self, other;
|
||||
{
|
||||
struct BLOCK *data, *data2;
|
||||
|
@ -6968,7 +7022,7 @@ proc_eq(self, other)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
proc_to_s(self, other)
|
||||
block_to_s(self, other)
|
||||
VALUE self, other;
|
||||
{
|
||||
struct BLOCK *data;
|
||||
|
@ -6996,20 +7050,20 @@ proc_to_s(self, other)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
proc_to_proc(proc)
|
||||
VALUE proc;
|
||||
block_to_self(self)
|
||||
VALUE self;
|
||||
{
|
||||
return proc;
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
proc_binding(proc)
|
||||
VALUE proc;
|
||||
block_binding(block)
|
||||
VALUE block;
|
||||
{
|
||||
struct BLOCK *orig, *data;
|
||||
VALUE bind;
|
||||
|
||||
Data_Get_Struct(proc, struct BLOCK, orig);
|
||||
Data_Get_Struct(block, struct BLOCK, orig);
|
||||
bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data);
|
||||
MEMCPY(data, orig, struct BLOCK, 1);
|
||||
frame_dup(&data->frame);
|
||||
|
@ -7045,23 +7099,23 @@ block_pass(self, node)
|
|||
POP_ITER();
|
||||
return result;
|
||||
}
|
||||
if (!rb_obj_is_proc(block)) {
|
||||
b = rb_check_convert_type(block, T_DATA, "Proc", "to_proc");
|
||||
if (!rb_obj_is_proc(b)) {
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)",
|
||||
if (!rb_obj_is_block(block)) {
|
||||
b = rb_check_convert_type(block, T_DATA, "Block", "to_block");
|
||||
if (!rb_obj_is_block(b)) {
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected Block)",
|
||||
rb_obj_classname(block));
|
||||
}
|
||||
block = b;
|
||||
}
|
||||
|
||||
if (ruby_safe_level >= 1 && OBJ_TAINTED(block)) {
|
||||
if (ruby_safe_level > proc_get_safe_level(block)) {
|
||||
if (ruby_safe_level > block_get_safe_level(block)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure: tainted block value");
|
||||
}
|
||||
}
|
||||
|
||||
Data_Get_Struct(block, struct BLOCK, data);
|
||||
orphan = blk_orphan(data);
|
||||
orphan = block_orphan(data);
|
||||
|
||||
retry:
|
||||
/* PUSH BLOCK from data */
|
||||
|
@ -7075,7 +7129,7 @@ block_pass(self, node)
|
|||
PUSH_TAG(PROT_NONE);
|
||||
state = EXEC_TAG();
|
||||
if (state == 0) {
|
||||
proc_set_safe_level(block);
|
||||
block_set_safe_level(block);
|
||||
if (safe > ruby_safe_level)
|
||||
ruby_safe_level = safe;
|
||||
result = rb_eval(self, node->nd_iter);
|
||||
|
@ -7104,7 +7158,7 @@ block_pass(self, node)
|
|||
ruby_block = old_block;
|
||||
ruby_safe_level = safe;
|
||||
|
||||
switch (state) {/* escape from orphan procedure */
|
||||
switch (state) {/* escape from orphan block */
|
||||
case 0:
|
||||
break;
|
||||
case TAG_BREAK:
|
||||
|
@ -7114,7 +7168,7 @@ block_pass(self, node)
|
|||
goto retry;
|
||||
case TAG_RETURN:
|
||||
if (orphan) {
|
||||
localjump_error("return from proc-closure", prot_tag->retval, state);
|
||||
localjump_error("return from block-closure", prot_tag->retval, state);
|
||||
}
|
||||
default:
|
||||
JUMP_TAG(state);
|
||||
|
@ -7395,7 +7449,7 @@ method_inspect(method)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
mproc(method)
|
||||
mblock(method)
|
||||
VALUE method;
|
||||
{
|
||||
VALUE proc;
|
||||
|
@ -7435,22 +7489,22 @@ rb_proc_new(func, val)
|
|||
VALUE (*func)(ANYARGS); /* VALUE yieldarg[, VALUE procarg] */
|
||||
VALUE val;
|
||||
{
|
||||
return rb_iterate((VALUE(*)_((VALUE)))mproc, 0, func, val);
|
||||
return rb_iterate((VALUE(*)_((VALUE)))mblock, 0, func, val);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
method_block(method)
|
||||
VALUE method;
|
||||
{
|
||||
return rb_iterate((VALUE(*)_((VALUE)))mblock, method, bmcall, method);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
method_proc(method)
|
||||
VALUE method;
|
||||
{
|
||||
return rb_iterate((VALUE(*)_((VALUE)))mproc, method, bmcall, method);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
umethod_proc(method)
|
||||
VALUE method;
|
||||
{
|
||||
rb_raise(rb_eTypeError, "unbound method cannot be executed; bind first");
|
||||
return Qnil; /* not reached */
|
||||
rb_warn("Method#to_proc is deprecated; use Method#to_block");
|
||||
return method_block(method);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -7481,8 +7535,8 @@ rb_mod_define_method(argc, argv, mod)
|
|||
else if (argc == 2) {
|
||||
id = rb_to_id(argv[0]);
|
||||
body = argv[1];
|
||||
if (!rb_obj_is_method(body) && !rb_obj_is_proc(body)) {
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Method)",
|
||||
if (!rb_obj_is_method(body) && !rb_obj_is_block(body)) {
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected Block/Method)",
|
||||
rb_obj_classname(body));
|
||||
}
|
||||
}
|
||||
|
@ -7495,7 +7549,7 @@ rb_mod_define_method(argc, argv, mod)
|
|||
else if (RDATA(body)->dmark == (RUBY_DATA_FUNC)blk_mark) {
|
||||
struct BLOCK *block;
|
||||
|
||||
body = bind_clone(body);
|
||||
body = block_clone(body);
|
||||
Data_Get_Struct(body, struct BLOCK, block);
|
||||
block->frame.last_func = id;
|
||||
block->frame.orig_func = id;
|
||||
|
@ -7504,7 +7558,7 @@ rb_mod_define_method(argc, argv, mod)
|
|||
}
|
||||
else {
|
||||
/* type error */
|
||||
rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)");
|
||||
rb_raise(rb_eTypeError, "wrong argument type (expected Block/Method)");
|
||||
}
|
||||
|
||||
if (SCOPE_TEST(SCOPE_PRIVATE)) {
|
||||
|
@ -7529,25 +7583,29 @@ Init_Proc()
|
|||
|
||||
rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError);
|
||||
|
||||
rb_cProc = rb_define_class("Proc", rb_cObject);
|
||||
rb_undef_alloc_func(rb_cProc);
|
||||
rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1);
|
||||
rb_cBlock = rb_define_class("Block", rb_cObject);
|
||||
rb_undef_alloc_func(rb_cBlock);
|
||||
rb_define_singleton_method(rb_cBlock, "new", block_s_new, -1);
|
||||
|
||||
rb_define_method(rb_cProc, "call", proc_call, -2);
|
||||
rb_define_method(rb_cProc, "yield", proc_yield, -2);
|
||||
rb_define_method(rb_cProc, "arity", proc_arity, 0);
|
||||
rb_define_method(rb_cProc, "[]", proc_call, -2);
|
||||
rb_define_method(rb_cProc, "==", proc_eq, 1);
|
||||
rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
|
||||
rb_define_method(rb_cProc, "to_proc", proc_to_proc, 0);
|
||||
rb_define_method(rb_cProc, "binding", proc_binding, 0);
|
||||
rb_define_method(rb_cBlock, "clone", block_clone, 0);
|
||||
rb_define_method(rb_cBlock, "call", block_call, -2);
|
||||
rb_define_method(rb_cBlock, "arity", block_arity, 0);
|
||||
rb_define_method(rb_cBlock, "[]", block_call, -2);
|
||||
rb_define_method(rb_cBlock, "==", block_eq, 1);
|
||||
rb_define_method(rb_cBlock, "to_s", block_to_s, 0);
|
||||
rb_define_method(rb_cBlock, "to_block", block_to_self, 0);
|
||||
rb_define_method(rb_cBlock, "binding", block_binding, 0);
|
||||
|
||||
rb_cProc = rb_define_class("Proc", rb_cBlock);
|
||||
rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1);
|
||||
rb_define_global_function("proc", rb_f_lambda, 0);
|
||||
rb_define_global_function("lambda", rb_f_lambda, 0);
|
||||
rb_define_global_function("binding", rb_f_binding, 0);
|
||||
|
||||
rb_cBinding = rb_define_class("Binding", rb_cObject);
|
||||
rb_undef_alloc_func(rb_cBinding);
|
||||
rb_undef_method(CLASS_OF(rb_cBinding), "new");
|
||||
rb_define_method(rb_cBinding, "clone", bind_clone, 0);
|
||||
rb_define_method(rb_cBinding, "clone", block_clone, 0);
|
||||
rb_define_global_function("binding", rb_f_binding, 0);
|
||||
|
||||
rb_cMethod = rb_define_class("Method", rb_cObject);
|
||||
rb_undef_alloc_func(rb_cMethod);
|
||||
|
@ -7559,6 +7617,7 @@ Init_Proc()
|
|||
rb_define_method(rb_cMethod, "arity", method_arity, 0);
|
||||
rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
|
||||
rb_define_method(rb_cMethod, "to_s", method_inspect, 0);
|
||||
rb_define_method(rb_cMethod, "to_block", method_block, 0);
|
||||
rb_define_method(rb_cMethod, "to_proc", method_proc, 0);
|
||||
rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
|
||||
rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
|
||||
|
@ -7571,7 +7630,6 @@ Init_Proc()
|
|||
rb_define_method(rb_cUnboundMethod, "arity", method_arity, 0);
|
||||
rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0);
|
||||
rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0);
|
||||
rb_define_method(rb_cUnboundMethod, "to_proc", umethod_proc, 0);
|
||||
rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
|
||||
rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1);
|
||||
}
|
||||
|
@ -9835,7 +9893,7 @@ rb_f_catch(dmy, tag)
|
|||
t = rb_to_id(tag);
|
||||
PUSH_TAG(t);
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
val = rb_yield_0(tag, 0, 0, 0, Qfalse);
|
||||
val = rb_yield_0(tag, 0, 0, Qfalse, Qfalse);
|
||||
}
|
||||
else if (state == TAG_THROW && t == prot_tag->dst) {
|
||||
val = prot_tag->retval;
|
||||
|
|
|
@ -80,7 +80,13 @@ module TkComm
|
|||
while idx and idx > 0 and str[idx-1] == ?\\
|
||||
idx = str.index('{', idx+1)
|
||||
end
|
||||
return tk_tcl2ruby(str) unless idx
|
||||
unless idx
|
||||
list = tk_tcl2ruby(str)
|
||||
unless Array === list
|
||||
list = [list]
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
list = tk_tcl2ruby(str[0,idx])
|
||||
list = [] if list == ""
|
||||
|
@ -93,6 +99,9 @@ module TkComm
|
|||
brace -= 1 if c == ?}
|
||||
break if brace == 0
|
||||
}
|
||||
if str.size == i + 1
|
||||
return tk_split_list(str[0, i])
|
||||
end
|
||||
if str[0, i] == ' '
|
||||
list.push ' '
|
||||
else
|
||||
|
@ -193,7 +202,7 @@ module TkComm
|
|||
end
|
||||
end
|
||||
def list(val)
|
||||
tk_split_list(val).to_a
|
||||
tk_split_list(val)
|
||||
end
|
||||
def window(val)
|
||||
Tk_WINDOWS[val]
|
||||
|
@ -573,7 +582,7 @@ module TkCore
|
|||
end
|
||||
|
||||
def TkCore.callback(arg)
|
||||
arg = Array(tk_split_list(arg))
|
||||
arg = tk_split_list(arg)
|
||||
_get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg))
|
||||
end
|
||||
|
||||
|
|
8
hash.c
8
hash.c
|
@ -45,7 +45,7 @@ rb_hash_freeze(hash)
|
|||
VALUE rb_cHash;
|
||||
|
||||
static VALUE envtbl;
|
||||
static ID id_hash, id_yield, id_default;
|
||||
static ID id_hash, id_call, id_default;
|
||||
|
||||
VALUE
|
||||
rb_hash(obj)
|
||||
|
@ -329,7 +329,7 @@ rb_hash_default(argc, argv, hash)
|
|||
|
||||
rb_scan_args(argc, argv, "01", &key);
|
||||
if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
|
||||
return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, key);
|
||||
return rb_funcall(RHASH(hash)->ifnone, id_call, 2, hash, key);
|
||||
}
|
||||
return RHASH(hash)->ifnone;
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ rb_hash_shift(hash)
|
|||
return rb_assoc_new(var.key, var.val);
|
||||
}
|
||||
else if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
|
||||
return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, Qnil);
|
||||
return rb_funcall(RHASH(hash)->ifnone, id_call, 2, hash, Qnil);
|
||||
}
|
||||
else {
|
||||
return RHASH(hash)->ifnone;
|
||||
|
@ -1730,7 +1730,7 @@ void
|
|||
Init_Hash()
|
||||
{
|
||||
id_hash = rb_intern("hash");
|
||||
id_yield = rb_intern("yield");
|
||||
id_call = rb_intern("call");
|
||||
id_default = rb_intern("default");
|
||||
|
||||
rb_cHash = rb_define_class("Hash", rb_cObject);
|
||||
|
|
34
object.c
34
object.c
|
@ -1288,34 +1288,30 @@ rb_f_string(obj, arg)
|
|||
return rb_String(arg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
VALUE
|
||||
rb_Array(val)
|
||||
VALUE val;
|
||||
{
|
||||
ID to_ary;
|
||||
VALUE tmp = rb_check_array_type(val);
|
||||
ID to_a;
|
||||
|
||||
if (NIL_P(val)) {
|
||||
rb_raise(rb_eTypeError, "cannot convert nil into Array");
|
||||
}
|
||||
if (TYPE(val) == T_ARRAY) return val;
|
||||
to_ary = rb_intern("to_ary");
|
||||
if (rb_respond_to(val, to_ary)) {
|
||||
val = rb_funcall(val, to_ary, 0);
|
||||
}
|
||||
else {
|
||||
to_ary = rb_intern("to_a");
|
||||
if (rb_respond_to(val, to_ary)) {
|
||||
val = rb_funcall(val, to_ary, 0);
|
||||
}
|
||||
else {
|
||||
val = rb_ary_new3(1, val);
|
||||
}
|
||||
}
|
||||
if (NIL_P(tmp)) {
|
||||
to_a = rb_intern("to_a");
|
||||
if (rb_respond_to(val, to_a)) {
|
||||
val = rb_funcall(val, to_a, 0);
|
||||
if (TYPE(val) != T_ARRAY) {
|
||||
rb_raise(rb_eTypeError, "`%s' did not return Array", rb_id2name(to_ary));
|
||||
rb_raise(rb_eTypeError, "`to_a' did not return Array");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
return rb_ary_new3(1, val);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
static VALUE
|
||||
rb_f_array(obj, arg)
|
||||
|
|
102
sample/test.rb
102
sample/test.rb
|
@ -11,13 +11,13 @@ def test_check(what)
|
|||
$testnum = 0
|
||||
end
|
||||
|
||||
def test_ok(cond)
|
||||
def test_ok(cond,n=1)
|
||||
$testnum+=1
|
||||
$ntest+=1
|
||||
if cond
|
||||
printf "ok %d\n", $testnum
|
||||
else
|
||||
where = caller[0]
|
||||
where = caller(n)[0]
|
||||
printf "not ok %s %d -- %s\n", $what, $testnum, where
|
||||
$failed+=1
|
||||
end
|
||||
|
@ -239,12 +239,9 @@ def r; return *[*[1,2]]; end; a,b,*c = r(); test_ok([a,b,c] == [1,2,[]])
|
|||
|
||||
f = lambda {|r,| test_ok([] == r)}
|
||||
f.call([], *[])
|
||||
f.yield([], *[])
|
||||
|
||||
f = lambda {|r,*l| test_ok([] == r); test_ok([1] == l)}
|
||||
f.call([], *[1])
|
||||
f.yield([], *[1])
|
||||
|
||||
|
||||
f = lambda{|x| x}
|
||||
test_ok(f.call(42) == 42)
|
||||
|
@ -980,6 +977,96 @@ end
|
|||
|
||||
test_ok(C.new.collect{|n| n} == [1,2,3])
|
||||
|
||||
test_ok(Proc < Block)
|
||||
test_ok(Proc == lambda{}.class)
|
||||
test_ok(Proc == proc{}.class)
|
||||
test_ok(Proc == Proc.new{}.class)
|
||||
lambda{|a|test_ok(a==1)}.call(1)
|
||||
def block_test(klass, &block)
|
||||
test_ok(klass === block)
|
||||
end
|
||||
|
||||
block_test(NilClass)
|
||||
block_test(Block){}
|
||||
|
||||
def argument_test(state, proc, *args)
|
||||
x = state
|
||||
begin
|
||||
proc.call(*args)
|
||||
rescue ArgumentError
|
||||
x = !x
|
||||
end
|
||||
test_ok(x,2)
|
||||
end
|
||||
|
||||
argument_test(true, lambda{||})
|
||||
argument_test(false, lambda{||}, 1)
|
||||
argument_test(true, lambda{|a,|}, 1)
|
||||
argument_test(false, lambda{|a,|})
|
||||
argument_test(false, lambda{|a,|}, 1,2)
|
||||
|
||||
def get_block(&block)
|
||||
block
|
||||
end
|
||||
|
||||
test_ok(Block == get_block{}.class)
|
||||
argument_test(true, get_block{||})
|
||||
argument_test(true, get_block{||}, 1)
|
||||
argument_test(true, get_block{|a,|}, 1)
|
||||
argument_test(true, get_block{|a,|})
|
||||
argument_test(true, get_block{|a,|}, 1,2)
|
||||
|
||||
argument_test(true, get_block(&lambda{||}))
|
||||
argument_test(false, get_block(&lambda{||}),1)
|
||||
argument_test(true, get_block(&lambda{|a,|}),1)
|
||||
argument_test(false, get_block(&lambda{|a,|}),1,2)
|
||||
|
||||
block = get_block{11}
|
||||
proc = lambda{44}
|
||||
test_ok(block.class == Block)
|
||||
test_ok(proc.class == Proc)
|
||||
test_ok(block.to_block.class == Block)
|
||||
test_ok(proc.to_block.class == Proc)
|
||||
test_ok(block.clone.call == 11)
|
||||
test_ok(proc.clone.call == 44)
|
||||
|
||||
test_ok(get_block(&block).class == Block)
|
||||
test_ok(get_block(&proc).class == Proc)
|
||||
|
||||
test_ok(Block.new{|a,| a}.call(1,2,3) == 1)
|
||||
argument_test(false, Proc.new{|a,| p a}, 1,2)
|
||||
|
||||
def ljump_test(state, proc, *args)
|
||||
x = state
|
||||
begin
|
||||
proc.call(*args)
|
||||
rescue LocalJumpError
|
||||
x = !x
|
||||
end
|
||||
test_ok(x,2)
|
||||
end
|
||||
|
||||
ljump_test(false, get_block{break})
|
||||
ljump_test(true, lambda{break})
|
||||
|
||||
test_ok(block.arity == -1)
|
||||
test_ok(proc.arity == -1)
|
||||
test_ok(lambda{||}.arity == 0)
|
||||
test_ok(lambda{|a|}.arity == 1)
|
||||
test_ok(lambda{|a,|}.arity == 1)
|
||||
test_ok(lambda{|a,b|}.arity == 2)
|
||||
|
||||
def marity_test(m)
|
||||
method = method(m)
|
||||
test_ok(method.arity == method.to_block.arity)
|
||||
end
|
||||
marity_test(:test_ok)
|
||||
marity_test(:marity_test)
|
||||
marity_test(:p)
|
||||
|
||||
lambda(&method(:test_ok)).call(true)
|
||||
lambda(&get_block{|a,n| test_ok(a,n)}).call(true, 2)
|
||||
|
||||
test_check "float"
|
||||
test_ok(2.6.floor == 2)
|
||||
test_ok((-2.6).floor == -3)
|
||||
|
@ -1111,7 +1198,7 @@ shift_test(-0xfffffffffffffffff)
|
|||
test_check "string & char"
|
||||
|
||||
test_ok("abcd" == "abcd")
|
||||
test_ok("abcd" =~ "abcd")
|
||||
test_ok("abcd" =~ /abcd/)
|
||||
test_ok("abcd" === "abcd")
|
||||
# compile time string concatenation
|
||||
test_ok("ab" "cd" == "abcd")
|
||||
|
@ -1606,6 +1693,9 @@ test_ok(ary.length == ary2.length)
|
|||
test_ok(ary.join(':') == ary2.join(':'))
|
||||
test_ok($x =~ /def/)
|
||||
|
||||
$x = [-1073741825]
|
||||
test_ok($x.pack("q").unpack("q") == $x)
|
||||
|
||||
test_check "math"
|
||||
test_ok(Math.sqrt(4) == 2)
|
||||
|
||||
|
|
11
string.c
11
string.c
|
@ -1020,6 +1020,7 @@ static VALUE
|
|||
rb_str_match(x, y)
|
||||
VALUE x, y;
|
||||
{
|
||||
VALUE reg;
|
||||
long start;
|
||||
|
||||
switch (TYPE(y)) {
|
||||
|
@ -1027,11 +1028,15 @@ rb_str_match(x, y)
|
|||
return rb_reg_match(y, x);
|
||||
|
||||
case T_STRING:
|
||||
start = rb_str_index(x, y, 0);
|
||||
#if RUBY_VERSION_CODE < 181
|
||||
rb_warn("string =~ string will be obsolete; use explicit regexp");
|
||||
#endif
|
||||
reg = rb_reg_regcomp(y);
|
||||
start = rb_reg_search(reg, x, 0, 0);
|
||||
if (start == -1) {
|
||||
return Qnil;
|
||||
}
|
||||
return LONG2NUM(start);
|
||||
return INT2NUM(start);
|
||||
|
||||
default:
|
||||
return rb_funcall(y, rb_intern("=~"), 1, x);
|
||||
|
@ -1459,7 +1464,7 @@ get_pat(pat, quote)
|
|||
|
||||
if (quote) {
|
||||
val = rb_reg_quote(pat);
|
||||
#if RUBY_VERSION_CODE < 180
|
||||
#if RUBY_VERSION_CODE < 181
|
||||
if (val != pat && rb_str_cmp(val, pat) != 0) {
|
||||
rb_warn("string pattern instead of regexp; metacharacters no longer effective");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue