1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

shugo's method etc.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/v1_1r@106 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 1998-03-03 10:16:14 +00:00
parent 0861165bdc
commit 369124b0ec
8 changed files with 271 additions and 78 deletions

239
eval.c
View file

@ -3051,39 +3051,19 @@ stack_length()
}
static VALUE
rb_call(klass, recv, mid, argc, argv, scope)
rb_call0(klass, recv, mid, id, argc, argv, scope, body, type)
VALUE klass, recv;
ID mid;
ID mid, id;
int argc; /* OK */
VALUE *argv; /* OK */
int scope;
NODE *body;
enum node_type type;
{
NODE *body, *b2; /* OK */
int noex;
ID id = mid;
struct cache_entry *ent;
NODE *b2; /* OK */
volatile VALUE result = Qnil;
int itr;
enum node_type type;
static int tick;
TMP_PROTECT;
again:
/* is it in the method cache? */
ent = cache + EXPR1(klass, mid);
if (ent->mid == mid && ent->klass == klass) {
klass = ent->origin;
id = ent->mid0;
noex = ent->noex;
body = ent->method;
}
else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
}
/* receiver specified form for private method */
if (noex == NOEX_PRIVATE && scope == 0)
return rb_undefined(recv, mid, argc, argv, CSTAT_NOEX);
switch (the_iter->iter) {
case ITER_PRE:
@ -3095,28 +3075,6 @@ rb_call(klass, recv, mid, argc, argv, scope)
break;
}
type = nd_type(body);
if (type == NODE_ZSUPER) {
/* for re-scoped/renamed method */
mid = id;
if (scope == 0) scope = 1;
if (RCLASS(klass)->super == 0) {
/* origin is the Module, so need to scan superclass hierarchy. */
struct RClass *cl = RCLASS(klass);
klass = RBASIC(recv)->klass;
while (klass) {
if (RCLASS(klass)->m_tbl == cl->m_tbl)
break;
klass = RCLASS(klass)->super;
}
}
else {
klass = RCLASS(klass)->super;
}
goto again;
}
if ((++tick & 0xfff) == 0 && stack_length() > STACK_LEVEL_MAX)
Fatal("stack level too deep");
@ -3271,15 +3229,22 @@ rb_call(klass, recv, mid, argc, argv, scope)
PUSH_VARS();
if ((state = EXEC_TAG()) == 0) {
if (nd_type(body) == NODE_BLOCK) {
NODE *node = body->nd_head;
int i;
NODE *node = 0;
int i;
if (nd_type(body) == NODE_ARGS) {
node = body;
body = 0;
}
else if (nd_type(body) == NODE_BLOCK) {
node = body->nd_head;
body = body->nd_next;
}
if (node) {
if (nd_type(node) != NODE_ARGS) {
Bug("no argument-node");
}
body = body->nd_next;
i = node->nd_cnt;
if (i > argc) {
ArgError("Wrong # of arguments(%d for %d)", argc, i);
@ -3321,9 +3286,7 @@ rb_call(klass, recv, mid, argc, argv, scope)
}
}
}
else if (nd_type(body) == NODE_ARGS) {
body = 0;
}
if (trace_func) {
call_trace_func("call", b2->nd_file, nd_line(b2),
recv, the_frame->last_func);
@ -3373,6 +3336,61 @@ rb_call(klass, recv, mid, argc, argv, scope)
return result;
}
static VALUE
rb_call(klass, recv, mid, argc, argv, scope)
VALUE klass, recv;
ID mid;
int argc; /* OK */
VALUE *argv; /* OK */
int scope;
{
NODE *body; /* OK */
int noex;
ID id = mid;
struct cache_entry *ent;
enum node_type type;
TMP_PROTECT;
again:
/* is it in the method cache? */
ent = cache + EXPR1(klass, mid);
if (ent->mid == mid && ent->klass == klass) {
klass = ent->origin;
id = ent->mid0;
noex = ent->noex;
body = ent->method;
}
else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
}
/* receiver specified form for private method */
if (noex == NOEX_PRIVATE && scope == 0)
return rb_undefined(recv, mid, argc, argv, CSTAT_NOEX);
type = nd_type(body);
if (type == NODE_ZSUPER) {
/* for re-scoped/renamed method */
mid = id;
if (scope == 0) scope = 1;
if (BUILTIN_TYPE(klass) == T_MODULE) {
/* origin is the Module, so need to scan superclass hierarchy. */
struct RClass *cl = RCLASS(klass);
klass = RBASIC(recv)->klass;
while (klass) {
if (RCLASS(klass)->m_tbl == cl->m_tbl)
break;
klass = RCLASS(klass)->super;
}
}
klass = RCLASS(klass)->super;
goto again;
}
return rb_call0(klass, recv, mid, id, argc, argv, scope, body, type);
}
VALUE
rb_apply(recv, mid, args)
VALUE recv;
@ -4682,6 +4700,113 @@ proc_iterate(proc)
return result;
}
static VALUE cMethod;
struct METHOD {
VALUE klass;
VALUE recv;
ID id;
NODE *body;
};
static void
bm_mark(struct METHOD *data)
{
gc_mark(data->klass);
gc_mark(data->recv);
gc_mark(data->body);
}
static VALUE
obj_method(obj, vid)
VALUE obj;
VALUE vid;
{
VALUE method;
VALUE klass = CLASS_OF(obj);
ID mid, id;
NODE *body;
int noex;
enum node_type type;
struct METHOD *data;
mid = id = rb_to_id(vid);
again:
if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
return rb_undefined(obj, mid, 0, 0, 0);
}
type = nd_type(body);
if (type == NODE_ZSUPER) {
/* for re-scoped/renamed method */
mid = id;
if (BUILTIN_TYPE(klass) == T_MODULE) {
/* origin is the Module, so need to scan superclass hierarchy. */
struct RClass *cl = RCLASS(klass);
klass = RBASIC(obj)->klass;
while (klass) {
if (RCLASS(klass)->m_tbl == cl->m_tbl)
break;
klass = RCLASS(klass)->super;
}
}
klass = RCLASS(klass)->super;
goto again;
}
if (BUILTIN_TYPE(klass) == T_ICLASS) {
klass = RBASIC(klass)->klass;
}
method = Data_Make_Struct(cMethod, struct METHOD, bm_mark, free, data);
data->klass = klass;
data->recv = obj;
data->id = id;
data->body = body;
return method;
}
static VALUE
method_call(argc, argv, method)
int argc;
VALUE *argv;
VALUE method;
{
VALUE result;
struct METHOD *data;
Data_Get_Struct(method, struct METHOD, data);
PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
result = rb_call0(data->klass, data->recv, data->id, data->id,
argc, argv, 1, data->body, nd_type(data->body));
POP_ITER();
return result;
}
static VALUE
method_inspect(method)
VALUE method;
{
struct METHOD *data;
VALUE str;
char *s;
Data_Get_Struct(method, struct METHOD, data);
str = str_new2("#<");
s = rb_class2name(CLASS_OF(method));
str_cat(str, s, strlen(s));
str_cat(str, ": ", 2);
s = rb_class2name(data->klass);
str_cat(str, s, strlen(s));
str_cat(str, "#", 1);
s = rb_id2name(data->id);
str_cat(str, s, strlen(s));
str_cat(str, ">", 1);
return str;
}
void
Init_Proc()
{
@ -4695,6 +4820,12 @@ Init_Proc()
rb_define_global_function("proc", f_lambda, 0);
rb_define_global_function("lambda", f_lambda, 0);
rb_define_global_function("binding", f_binding, 0);
cMethod = rb_define_class("Method", cObject);
rb_undef_method(CLASS_OF(cMethod), "new");
rb_define_method(cMethod, "call", method_call, -1);
rb_define_method(cMethod, "inspect", method_inspect, 0);
rb_define_method(mKernel, "method", obj_method, 1);
}
#ifdef THREAD