summaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c602
1 files changed, 382 insertions, 220 deletions
diff --git a/eval.c b/eval.c
index 42617c2b27..57aa51171d 100644
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,7 @@
$Date$
created at: Thu Jun 10 14:22:17 JST 1993
- Copyright (C) 1993-1997 Yukihiro Matsumoto
+ Copyright (C) 1993-1998 Yukihiro Matsumoto
************************************************/
@@ -43,6 +43,7 @@ static VALUE f_binding _((VALUE));
static void f_END _((void));
#define SCOPE_PRIVATE FL_USER4
+#define SCOPE_MODFUNC FL_USER5
#define CACHE_SIZE 0x200
#define CACHE_MASK 0x1ff
@@ -51,7 +52,7 @@ static void f_END _((void));
struct cache_entry { /* method hash table. */
ID mid; /* method's id */
ID mid0; /* method's original id */
- VALUE class; /* receiver's class */
+ VALUE klass; /* receiver's class */
VALUE origin; /* where method defined */
NODE *method;
int noex;
@@ -87,80 +88,80 @@ rb_clear_cache_by_id(id)
}
void
-rb_add_method(class, mid, node, noex)
- VALUE class;
+rb_add_method(klass, mid, node, noex)
+ VALUE klass;
ID mid;
NODE *node;
int noex;
{
NODE *body;
- if (NIL_P(class)) class = cObject;
+ if (NIL_P(klass)) klass = cObject;
body = NEW_METHOD(node, noex);
- st_insert(RCLASS(class)->m_tbl, mid, body);
+ st_insert(RCLASS(klass)->m_tbl, mid, body);
}
void
-rb_remove_method(class, mid)
- VALUE class;
+rb_remove_method(klass, mid)
+ VALUE klass;
ID mid;
{
NODE *body;
- if (!st_delete(RCLASS(class)->m_tbl, &mid, &body)) {
+ if (!st_delete(RCLASS(klass)->m_tbl, &mid, &body)) {
NameError("method `%s' not defined in %s",
- rb_id2name(mid), rb_class2name(class));
+ rb_id2name(mid), rb_class2name(klass));
}
rb_clear_cache_by_id(mid);
}
static NODE*
-search_method(class, id, origin)
- VALUE class, *origin;
+search_method(klass, id, origin)
+ VALUE klass, *origin;
ID id;
{
NODE *body;
- while (!st_lookup(RCLASS(class)->m_tbl, id, &body)) {
- class = (VALUE)RCLASS(class)->super;
- if (!class) return 0;
+ while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) {
+ klass = RCLASS(klass)->super;
+ if (!klass) return 0;
}
- if (origin) *origin = class;
+ if (origin) *origin = klass;
return body;
}
static NODE*
-rb_get_method_body(classp, idp, noexp)
- VALUE *classp;
+rb_get_method_body(klassp, idp, noexp)
+ VALUE *klassp;
ID *idp;
int *noexp;
{
ID id = *idp;
- VALUE class = *classp;
+ VALUE klass = *klassp;
VALUE origin;
NODE *body;
struct cache_entry *ent;
- if ((body = search_method(class, id, &origin)) == 0) {
+ if ((body = search_method(klass, id, &origin)) == 0) {
return 0;
}
if (!body->nd_body) return 0;
/* store in cache */
- ent = cache + EXPR1(class, id);
- ent->class = class;
+ ent = cache + EXPR1(klass, id);
+ ent->klass = klass;
ent->noex = body->nd_noex;
body = body->nd_body;
if (nd_type(body) == NODE_FBODY) {
ent->mid = id;
- *classp = body->nd_orig;
+ *klassp = body->nd_orig;
ent->origin = body->nd_orig;
*idp = ent->mid0 = body->nd_mid;
body = ent->method = body->nd_head;
}
else {
- *classp = (VALUE)origin;
+ *klassp = origin;
ent->origin = origin;
ent->mid = ent->mid0 = id;
ent->method = body;
@@ -171,23 +172,23 @@ rb_get_method_body(classp, idp, noexp)
}
void
-rb_alias(class, name, def)
- VALUE class;
+rb_alias(klass, name, def)
+ VALUE klass;
ID name, def;
{
VALUE origin;
NODE *orig, *body;
if (name == def) return;
- orig = search_method(class, def, &origin);
+ orig = search_method(klass, def, &origin);
if (!orig || !orig->nd_body) {
- if (TYPE(class) == T_MODULE) {
+ if (TYPE(klass) == T_MODULE) {
orig = search_method(cObject, def, &origin);
}
}
if (!orig || !orig->nd_body) {
NameError("undefined method `%s' for `%s'",
- rb_id2name(def), rb_class2name((VALUE)class));
+ rb_id2name(def), rb_class2name(klass));
}
body = orig->nd_body;
if (nd_type(body) == NODE_FBODY) { /* was alias */
@@ -196,47 +197,47 @@ rb_alias(class, name, def)
origin = body->nd_orig;
}
- st_insert(RCLASS(class)->m_tbl, name,
+ st_insert(RCLASS(klass)->m_tbl, name,
NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
}
static void
-rb_export_method(class, name, noex)
- VALUE class;
+rb_export_method(klass, name, noex)
+ VALUE klass;
ID name;
int noex;
{
NODE *body;
- struct RClass *origin;
+ VALUE origin;
- body = search_method(class, name, &origin);
- if (!body && TYPE(class) == T_MODULE) {
+ body = search_method(klass, name, &origin);
+ if (!body && TYPE(klass) == T_MODULE) {
body = search_method(cObject, name, &origin);
}
if (!body) {
NameError("undefined method `%s' for `%s'",
- rb_id2name(name), rb_class2name(class));
+ rb_id2name(name), rb_class2name(klass));
}
if (body->nd_noex != noex) {
- if (class == (VALUE)origin) {
+ if (klass == origin) {
body->nd_noex = noex;
}
else {
rb_clear_cache_by_id(name);
- rb_add_method(class, name, NEW_ZSUPER(), noex);
+ rb_add_method(klass, name, NEW_ZSUPER(), noex);
}
}
}
static VALUE
-method_boundp(class, id, ex)
- VALUE class;
+method_boundp(klass, id, ex)
+ VALUE klass;
ID id;
int ex;
{
int noex;
- if (rb_get_method_body(&class, &id, &noex)) {
+ if (rb_get_method_body(&klass, &id, &noex)) {
if (ex && noex == NOEX_PRIVATE)
return FALSE;
return TRUE;
@@ -245,12 +246,12 @@ method_boundp(class, id, ex)
}
int
-rb_method_boundp(class, id, ex)
- VALUE class;
+rb_method_boundp(klass, id, ex)
+ VALUE klass;
ID id;
int ex;
{
- if (method_boundp(class, id, ex))
+ if (method_boundp(klass, id, ex))
return TRUE;
return FALSE;
}
@@ -282,15 +283,15 @@ static struct FRAME *top_frame;
static struct SCOPE *top_scope;
#define PUSH_FRAME() { \
- struct FRAME *_frame = ALLOCA_N(struct FRAME,1);\
- _frame->prev = the_frame; \
- _frame->file = sourcefile; \
- _frame->line = sourceline; \
- _frame->iter = the_iter->iter; \
- _frame->cbase = the_frame->cbase; \
- the_frame = _frame; \
+ struct FRAME _frame; \
+ _frame.prev = the_frame; \
+ _frame.file = sourcefile; \
+ _frame.line = sourceline; \
+ _frame.iter = the_iter->iter; \
+ _frame.cbase = the_frame->cbase; \
+ the_frame = &_frame; \
-#define POP_FRAME() the_frame = _frame->prev; }
+#define POP_FRAME() the_frame = _frame.prev; }
struct BLOCK {
NODE *var;
@@ -298,7 +299,7 @@ struct BLOCK {
VALUE self;
struct FRAME frame;
struct SCOPE *scope;
- VALUE class;
+ VALUE klass;
struct tag *tag;
int iter;
struct RVarmap *d_vars;
@@ -309,29 +310,29 @@ struct BLOCK {
} *the_block;
#define PUSH_BLOCK(v,b) { \
- struct BLOCK *_block = ALLOCA_N(struct BLOCK,1);\
- _block->tag = prot_tag; \
- _block->var = v; \
- _block->body = b; \
- _block->self = self; \
- _block->frame = *the_frame; \
- _block->class = the_class; \
- _block->frame.file = sourcefile; \
- _block->frame.line = sourceline; \
- _block->scope = the_scope; \
- _block->d_vars = the_dyna_vars; \
- _block->prev = the_block; \
- _block->iter = the_iter->iter; \
- the_block = _block;
+ struct BLOCK _block; \
+ _block.tag = prot_tag; \
+ _block.var = v; \
+ _block.body = b; \
+ _block.self = self; \
+ _block.frame = *the_frame; \
+ _block.klass = the_class; \
+ _block.frame.file = sourcefile; \
+ _block.frame.line = sourceline; \
+ _block.scope = the_scope; \
+ _block.d_vars = the_dyna_vars; \
+ _block.prev = the_block; \
+ _block.iter = the_iter->iter; \
+ the_block = &_block;
#define PUSH_BLOCK2(b) { \
- struct BLOCK *_block = ALLOCA_N(struct BLOCK,1);\
- *_block = *b; \
- _block->prev = the_block; \
- the_block = _block;
+ struct BLOCK _block; \
+ _block = *b; \
+ _block.prev = the_block; \
+ the_block = &_block;
#define POP_BLOCK() \
- the_block = the_block->prev; \
+ the_block = _block.prev; \
}
struct RVarmap *the_dyna_vars;
@@ -416,38 +417,26 @@ static struct iter {
the_iter = _iter.prev; \
}
-#ifdef C_ALLOCA
-/* need to protect retval in struct tag from GC. */
-#define tag_retval_dcl VALUE *dd_retval
-#define tag_retval_init VALUE _tag_retval = Qnil;\
- _tag->dd_retval = &_tag_retval;
-#define tag_retval dd_retval[0]
-#else
-#define tag_retval_dcl VALUE retval
-#define tag_retval_init _tag->retval = Qnil
-#define tag_retval retval
-#endif
-
static struct tag {
jmp_buf buf;
struct FRAME *frame;
struct iter *iter;
ID tag;
- tag_retval_dcl;
+ VALUE retval;
ID dst;
struct tag *prev;
} *prot_tag;
#define PUSH_TAG(ptag) { \
- struct tag *_tag = ALLOCA_N(struct tag,1);\
- tag_retval_init; \
- _tag->frame = the_frame; \
- _tag->iter = the_iter; \
- _tag->prev = prot_tag; \
- _tag->tag_retval = Qnil; \
- _tag->tag = ptag; \
- _tag->dst = 0; \
- prot_tag = _tag;
+ struct tag _tag; \
+ _tag.retval = Qnil; \
+ _tag.frame = the_frame; \
+ _tag.iter = the_iter; \
+ _tag.prev = prot_tag; \
+ _tag.retval = Qnil; \
+ _tag.tag = ptag; \
+ _tag.dst = 0; \
+ prot_tag = &_tag;
#define PROT_NONE 0
#define PROT_FUNC -1
@@ -462,7 +451,7 @@ static struct tag {
}
#define POP_TAG() \
- prot_tag = _tag->prev; \
+ prot_tag = _tag.prev; \
}
#define TAG_RETURN 0x1
@@ -717,6 +706,7 @@ ruby_init()
top_scope = the_scope;
/* default visibility is private at toplevel */
FL_SET(top_scope, SCOPE_PRIVATE);
+ FL_UNSET(top_scope, SCOPE_MODFUNC);
PUSH_TAG(PROT_NONE)
if ((state = EXEC_TAG()) == 0) {
@@ -746,11 +736,10 @@ ruby_options(argc, argv)
NODE *save;
ruby_process_options(argc, argv);
+ ext_init = 1; /* Init_ext() called in ruby_process_options */
save = eval_tree;
eval_tree = 0;
- Init_ext();
- ext_init = 1;
- rb_require_modules();
+ ruby_require_modules();
eval_tree = save;
}
POP_TAG();
@@ -1024,10 +1013,10 @@ ev_const_defined(cref, id)
NODE *cbase = cref;
while (cbase && cbase->nd_clss != cObject) {
- struct RClass *class = RCLASS(cbase->nd_clss);
+ struct RClass *klass = RCLASS(cbase->nd_clss);
- if (class->iv_tbl &&
- st_lookup(class->iv_tbl, id, 0)) {
+ if (klass->iv_tbl &&
+ st_lookup(klass->iv_tbl, id, 0)) {
return TRUE;
}
cbase = cbase->nd_next;
@@ -1044,10 +1033,10 @@ ev_const_get(cref, id)
VALUE result;
while (cbase && cbase->nd_clss != cObject) {
- struct RClass *class = RCLASS(cbase->nd_clss);
+ struct RClass *klass = RCLASS(cbase->nd_clss);
- if (class->iv_tbl &&
- st_lookup(class->iv_tbl, id, &result)) {
+ if (klass->iv_tbl &&
+ st_lookup(klass->iv_tbl, id, &result)) {
return result;
}
cbase = cbase->nd_next;
@@ -1103,16 +1092,27 @@ mod_undef_method(mod, name)
}
static VALUE
-mod_alias_method(mod, new, old)
- VALUE mod, new, old;
+mod_alias_method(mod, newname, oldname)
+ VALUE mod, newname, oldname;
{
- ID id = rb_to_id(new);
+ ID id = rb_to_id(newname);
- rb_alias(mod, id, rb_to_id(old));
+ rb_alias(mod, id, rb_to_id(oldname));
rb_clear_cache_by_id(id);
return mod;
}
+#if defined(C_ALLOCA) && defined(THREAD)
+# define TMP_PROTECT NODE *__protect_tmp=0
+# define TMP_ALLOC(type,n) \
+ (__protect_tmp = node_newnode(NODE_ALLOCA, \
+ str_new(0,sizeof(type)*(n)),0,__protect_tmp), \
+ (void*)RSTRING(__protect_tmp->nd_head)->ptr)
+#else
+# define TMP_PROTECT typedef int foobazzz
+# define TMP_ALLOC(type,n) ALLOCA_N(type,n)
+#endif
+
#define SETUP_ARGS(anode) {\
NODE *n = anode;\
if (!n) {\
@@ -1126,7 +1126,7 @@ mod_alias_method(mod, new, old)
int line = sourceline;\
int i;\
n = anode;\
- argv = ALLOCA_N(VALUE,argc);\
+ argv = TMP_ALLOC(VALUE,argc);\
for (i=0;i<argc;i++) {\
argv[i] = rb_eval(self,n->nd_head);\
n=n->nd_next;\
@@ -1371,7 +1371,7 @@ call_trace_func(event, file, line, self, id)
prev = the_frame;
PUSH_FRAME();
- *the_frame = *_frame->prev;
+ *the_frame = *_frame.prev;
the_frame->prev = prev;
the_frame->line = sourceline = line;
@@ -1606,7 +1606,7 @@ rb_eval(self, node)
else if (the_block->tag->dst == state) {
state &= TAG_MASK;
if (state == TAG_RETURN) {
- result = prot_tag->tag_retval;
+ result = prot_tag->retval;
}
}
POP_TAG();
@@ -1767,6 +1767,7 @@ rb_eval(self, node)
{
VALUE recv;
int argc; VALUE *argv; /* used in SETUP_ARGS */
+ TMP_PROTECT;
PUSH_ITER(ITER_NOT);
recv = rb_eval(self, node->nd_recv);
@@ -1779,6 +1780,7 @@ rb_eval(self, node)
case NODE_FCALL:
{
int argc; VALUE *argv; /* used in SETUP_ARGS */
+ TMP_PROTECT;
PUSH_ITER(ITER_NOT);
SETUP_ARGS(node->nd_args);
@@ -1795,6 +1797,7 @@ rb_eval(self, node)
case NODE_ZSUPER:
{
int argc; VALUE *argv; /* used in SETUP_ARGS */
+ TMP_PROTECT;
if (nd_type(node) == NODE_ZSUPER) {
argc = the_frame->argc;
@@ -1819,7 +1822,7 @@ rb_eval(self, node)
PUSH_SCOPE();
PUSH_TAG(PROT_NONE);
- if (node->nd_rval) the_frame->cbase = (VALUE)node->nd_rval;
+ if (node->nd_rval) the_frame->cbase = node->nd_rval;
if (node->nd_tbl) {
VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
*vars++ = (VALUE)node;
@@ -1846,6 +1849,7 @@ rb_eval(self, node)
int argc; VALUE *argv; /* used in SETUP_ARGS */
VALUE recv, val;
NODE *rval;
+ TMP_PROTECT;
recv = rb_eval(self, node->nd_recv);
rval = node->nd_args->nd_head;
@@ -1950,21 +1954,25 @@ rb_eval(self, node)
case NODE_COLON2:
{
- VALUE cls;
+ VALUE klass;
- cls = rb_eval(self, node->nd_head);
- switch (TYPE(cls)) {
+ klass = rb_eval(self, node->nd_head);
+ switch (TYPE(klass)) {
case T_CLASS:
case T_MODULE:
break;
default:
- Check_Type(cls, T_CLASS);
+ Check_Type(klass, T_CLASS);
break;
}
- result = rb_const_get_at(cls, node->nd_mid);
+ result = rb_const_get_at(klass, node->nd_mid);
}
break;
+ case NODE_COLON3:
+ result = rb_const_get_at(cObject, node->nd_mid);
+ break;
+
case NODE_NTH_REF:
result = reg_nth_match(node->nd_nth, MATCH_DATA);
break;
@@ -2106,19 +2114,25 @@ rb_eval(self, node)
body = search_method(the_class, node->nd_mid, &origin);
if (body) {
- if (origin == (VALUE)the_class) {
+ if (origin == the_class) {
Warning("discarding old %s", rb_id2name(node->nd_mid));
}
rb_clear_cache_by_id(node->nd_mid);
}
- if (FL_TEST(the_scope,SCOPE_PRIVATE)) {
+ if (FL_TEST(the_scope,SCOPE_PRIVATE) || node->nd_mid == init) {
noex = NOEX_PRIVATE;
}
else {
noex = NOEX_PUBLIC;
}
rb_add_method(the_class, node->nd_mid, node->nd_defn, noex);
+ if (FL_TEST(the_scope,SCOPE_MODFUNC)) {
+ rb_add_method(rb_singleton_class(the_class),
+ node->nd_mid, node->nd_defn, NOEX_PUBLIC);
+ rb_funcall(the_class, rb_intern("singleton_method_added"),
+ 1, INT2FIX(node->nd_mid));
+ }
if (FL_TEST(the_class, FL_SINGLETON)) {
VALUE recv = rb_iv_get(the_class, "__attached__");
rb_funcall(recv, rb_intern("singleton_method_added"),
@@ -2135,7 +2149,7 @@ rb_eval(self, node)
case NODE_DEFS:
if (node->nd_defn) {
VALUE recv = rb_eval(self, node->nd_recv);
- VALUE class;
+ VALUE klass;
NODE *body;
if (FIXNUM_P(recv)) {
@@ -2151,12 +2165,12 @@ rb_eval(self, node)
rb_id2name(node->nd_mid));
}
- class = rb_singleton_class(recv);
- if (st_lookup(RCLASS(class)->m_tbl, node->nd_mid, &body)) {
+ klass = rb_singleton_class(recv);
+ if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &body)) {
Warning("redefine %s", rb_id2name(node->nd_mid));
}
rb_clear_cache_by_id(node->nd_mid);
- rb_add_method(class, node->nd_mid, node->nd_defn, NOEX_PUBLIC);
+ rb_add_method(klass, node->nd_mid, node->nd_defn, NOEX_PUBLIC);
rb_funcall(recv, rb_intern("singleton_method_added"),
1, INT2FIX(node->nd_mid));
result = Qnil;
@@ -2171,7 +2185,7 @@ rb_eval(self, node)
body = search_method(the_class, node->nd_mid, &origin);
if (!body || !body->nd_body) {
NameError("undefined method `%s' for class `%s'",
- rb_id2name(node->nd_mid), rb_class2name((VALUE)the_class));
+ rb_id2name(node->nd_mid), rb_class2name(the_class));
}
rb_clear_cache_by_id(node->nd_mid);
rb_add_method(the_class, node->nd_mid, 0, NOEX_PUBLIC);
@@ -2193,7 +2207,7 @@ rb_eval(self, node)
case NODE_CLASS:
{
- VALUE super, class, tmp;
+ VALUE super, klass, tmp;
if (node->nd_super) {
super = superclass(self, node->nd_super);
@@ -2203,15 +2217,15 @@ rb_eval(self, node)
}
if (rb_const_defined_at(the_class, node->nd_cname) &&
- ((VALUE)the_class != cObject ||
+ (the_class != cObject ||
!rb_autoload_defined(node->nd_cname))) {
- class = rb_const_get_at(the_class, node->nd_cname);
- if (TYPE(class) != T_CLASS) {
+ klass = rb_const_get_at(the_class, node->nd_cname);
+ if (TYPE(klass) != T_CLASS) {
TypeError("%s is not a class", rb_id2name(node->nd_cname));
}
if (super) {
- tmp = RCLASS(class)->super;
+ tmp = RCLASS(klass)->super;
if (FL_TEST(tmp, FL_SINGLETON)) {
tmp = RCLASS(tmp)->super;
}
@@ -2230,12 +2244,12 @@ rb_eval(self, node)
}
else {
if (!super) super = cObject;
- class = rb_define_class_id(node->nd_cname, super);
- rb_const_set(the_class, node->nd_cname, class);
- rb_set_class_path(class,the_class,rb_id2name(node->nd_cname));
+ klass = rb_define_class_id(node->nd_cname, super);
+ rb_const_set(the_class, node->nd_cname, klass);
+ rb_set_class_path(klass,the_class,rb_id2name(node->nd_cname));
}
- return module_setup(class, node->nd_body);
+ return module_setup(klass, node->nd_body);
}
break;
@@ -2244,7 +2258,7 @@ rb_eval(self, node)
VALUE module;
if (rb_const_defined_at(the_class, node->nd_cname) &&
- ((VALUE)the_class != cObject ||
+ (the_class != cObject ||
!rb_autoload_defined(node->nd_cname))) {
module = rb_const_get_at(the_class, node->nd_cname);
@@ -2267,24 +2281,24 @@ rb_eval(self, node)
case NODE_SCLASS:
{
- VALUE class;
+ VALUE klass;
- class = rb_eval(self, node->nd_recv);
- if (FIXNUM_P(class)) {
+ klass = rb_eval(self, node->nd_recv);
+ if (FIXNUM_P(klass)) {
TypeError("No virtual class for Fixnums");
}
- if (NIL_P(class)) {
+ if (NIL_P(klass)) {
TypeError("No virtual class for nil");
}
- if (rb_special_const_p(class)) {
+ if (rb_special_const_p(klass)) {
TypeError("No virtual class for special constants");
}
- if (FL_TEST(CLASS_OF(class), FL_SINGLETON)) {
+ if (FL_TEST(CLASS_OF(klass), FL_SINGLETON)) {
rb_clear_cache();
- class = rb_singleton_class(class);
}
-
- result = module_setup(class, node->nd_body);
+ klass = rb_singleton_class(klass);
+
+ result = module_setup(klass, node->nd_body);
}
break;
@@ -2326,6 +2340,7 @@ module_setup(module, node)
VALUE result; /* OK */
char *file = sourcefile;
int line = sourceline;
+ TMP_PROTECT;
/* fill c-ref */
node->nd_clss = module;
@@ -2337,7 +2352,7 @@ module_setup(module, node)
if (node->nd_rval) the_frame->cbase = node->nd_rval;
if (node->nd_tbl) {
- VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+ VALUE *vars = TMP_ALLOC(VALUE, node->nd_tbl[0]+1);
*vars++ = (VALUE)node;
the_scope->local_vars = vars;
memclear(the_scope->local_vars, node->nd_tbl[0]);
@@ -2354,7 +2369,7 @@ module_setup(module, node)
call_trace_func("class", file, line,
the_class, the_frame->last_func);
}
- result = rb_eval((VALUE)the_class, node->nd_body);
+ result = rb_eval(the_class, node->nd_body);
}
POP_TAG();
POP_SCOPE();
@@ -2568,7 +2583,7 @@ f_raise(argc, argv)
}
PUSH_FRAME(); /* fake frame */
- *the_frame = *_frame->prev->prev;
+ *the_frame = *_frame.prev->prev;
rb_longjmp(TAG_RAISE, mesg, arg3);
POP_FRAME();
}
@@ -2614,7 +2629,7 @@ rb_yield_0(val, self)
the_scope = block->scope;
the_block = block->prev;
the_dyna_vars = block->d_vars;
- the_class = block->class;
+ the_class = block->klass;
if (!self) self = block->self;
node = block->body;
if (block->var) {
@@ -2795,7 +2810,7 @@ rb_iterate(it_proc, data1, bl_proc, data2)
if (the_block->tag->dst == state) {
state &= TAG_MASK;
if (state == TAG_RETURN) {
- retval = prot_tag->tag_retval;
+ retval = prot_tag->retval;
}
}
POP_TAG();
@@ -2828,6 +2843,7 @@ handle_rescue(self, node)
NODE *node;
{
int argc; VALUE *argv; /* used in SETUP_ARGS */
+ TMP_PROTECT;
if (!node->nd_args) {
return obj_is_kind_of(errinfo, eException);
@@ -2968,7 +2984,7 @@ f_missing(argc, argv, obj)
sourcefile = file;
sourceline = line;
PUSH_FRAME(); /* fake frame */
- *the_frame = *_frame->prev->prev;
+ *the_frame = *_frame.prev->prev;
NameError(format,
rb_id2name(id),
@@ -3022,8 +3038,8 @@ stack_length()
}
static VALUE
-rb_call(class, recv, mid, argc, argv, scope)
- VALUE class, recv;
+rb_call(klass, recv, mid, argc, argv, scope)
+ VALUE klass, recv;
ID mid;
int argc; /* OK */
VALUE *argv; /* OK */
@@ -3037,17 +3053,18 @@ rb_call(class, recv, mid, argc, argv, scope)
int itr;
enum node_type type;
static int tick;
+ TMP_PROTECT;
again:
/* is it in the method cache? */
- ent = cache + EXPR1(class, mid);
- if (ent->mid == mid && ent->class == class) {
- class = ent->origin;
+ 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(&class, &id, &noex)) == 0) {
+ else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
}
@@ -3070,19 +3087,19 @@ rb_call(class, recv, mid, argc, argv, scope)
/* for re-scoped/renamed method */
mid = id;
if (scope == 0) scope = 1;
- if (RCLASS(class)->super == 0) {
+ if (RCLASS(klass)->super == 0) {
/* origin is the Module, so need to scan superclass hierarchy. */
- struct RClass *cl = RCLASS(class);
+ struct RClass *cl = RCLASS(klass);
- class = RBASIC(recv)->class;
- while (class) {
- if (RCLASS(class)->m_tbl == cl->m_tbl)
+ klass = RBASIC(recv)->klass;
+ while (klass) {
+ if (RCLASS(klass)->m_tbl == cl->m_tbl)
break;
- class = RCLASS(class)->super;
+ klass = RCLASS(klass)->super;
}
}
else {
- class = RCLASS(class)->super;
+ klass = RCLASS(klass)->super;
}
goto again;
}
@@ -3093,7 +3110,7 @@ rb_call(class, recv, mid, argc, argv, scope)
PUSH_ITER(itr);
PUSH_FRAME();
the_frame->last_func = id;
- the_frame->last_class = class;
+ the_frame->last_class = klass;
the_frame->argc = argc;
the_frame->argv = argv;
@@ -3200,7 +3217,7 @@ rb_call(class, recv, mid, argc, argv, scope)
default:
if (len < 0) {
Bug("bad argc(%d) specified for `%s(%s)'",
- len, rb_class2name((VALUE)class), rb_id2name(mid));
+ len, rb_class2name(klass), rb_id2name(mid));
}
else {
ArgError("too many arguments(%d)", len);
@@ -3225,7 +3242,7 @@ rb_call(class, recv, mid, argc, argv, scope)
if (body->nd_rval) the_frame->cbase = body->nd_rval;
if (body->nd_tbl) {
- local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]+1);
+ local_vars = TMP_ALLOC(VALUE, body->nd_tbl[0]+1);
*local_vars++ = (VALUE)body;
memclear(local_vars, body->nd_tbl[0]);
the_scope->local_tbl = body->nd_tbl;
@@ -3301,7 +3318,7 @@ rb_call(class, recv, mid, argc, argv, scope)
result = rb_eval(recv, body);
}
else if (state == TAG_RETURN) {
- result = prot_tag->tag_retval;
+ result = prot_tag->retval;
state = 0;
}
POP_VARS();
@@ -3365,19 +3382,34 @@ f_send(argc, argv, recv)
VALUE recv;
{
VALUE vid;
- ID mid;
if (argc == 0) ArgError("no method name given");
- vid = argv[0]; argc--; argv++;
- if (TYPE(vid) == T_STRING) {
- mid = rb_intern(RSTRING(vid)->ptr);
- }
- else {
- mid = NUM2INT(vid);
- }
+ vid = *argv++; argc--;
PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
- vid = rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1);
+ POP_ITER();
+
+ return vid;
+}
+
+static VALUE
+f_pass_block(argc, argv, recv)
+ int argc;
+ VALUE *argv;
+ VALUE recv;
+{
+ VALUE vid;
+
+ if (argc == 0) ArgError("no iterator name given");
+ if (iterator_p())
+ ArgError("iterator block given to pass_block");
+ if (!f_iterator_p())
+ ArgError("pass_block called out of iterator");
+
+ vid = *argv++; argc--;
+ PUSH_ITER(ITER_PRE);
+ vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1);
POP_ITER();
return vid;
@@ -3572,7 +3604,7 @@ eval(self, src, scope)
rb_in_eval++;
if (TYPE(the_class) == T_ICLASS) {
- the_class = RBASIC(the_class)->class;
+ the_class = RBASIC(the_class)->klass;
}
PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) {
@@ -3644,8 +3676,8 @@ eval_under(under, self, src)
PUSH_CLASS();
the_class = under;
PUSH_FRAME();
- the_frame->last_func = _frame->last_func;
- the_frame->last_class = _frame->last_class;
+ the_frame->last_func = _frame.last_func;
+ the_frame->last_class = _frame.last_class;
the_frame->argc = 1;
the_frame->argv = &src;
the_frame->cbase = (VALUE)node_newnode(NODE_CREF,under,0,cbase);
@@ -3722,6 +3754,7 @@ f_load(obj, fname)
int state;
char *file;
volatile ID last_func;
+ TMP_PROTECT;
Check_SafeStr(fname);
if (RSTRING(fname)->ptr[0] == '~') {
@@ -3737,7 +3770,7 @@ f_load(obj, fname)
if (top_scope->local_tbl) {
int len = top_scope->local_tbl[0]+1;
ID *tbl = ALLOC_N(ID, len);
- VALUE *vars = ALLOCA_N(VALUE, len);
+ VALUE *vars = TMP_ALLOC(VALUE, len);
*vars++ = 0;
MEMCPY(tbl, top_scope->local_tbl, ID, len);
MEMCPY(vars, top_scope->local_vars, ID, len-1);
@@ -3746,6 +3779,7 @@ f_load(obj, fname)
}
/* default visibility is private at loading toplevel */
FL_SET(the_scope, SCOPE_PRIVATE);
+ FL_UNSET(top_scope, SCOPE_MODFUNC);
state = EXEC_TAG();
last_func = the_frame->last_func;
@@ -3938,6 +3972,7 @@ mod_public(argc, argv, module)
{
if (argc == 0) {
FL_UNSET(the_scope, SCOPE_PRIVATE);
+ FL_UNSET(top_scope, SCOPE_MODFUNC);
}
else {
set_method_visibility(module, argc, argv, NOEX_PUBLIC);
@@ -3953,6 +3988,7 @@ mod_private(argc, argv, module)
{
if (argc == 0) {
FL_SET(the_scope, SCOPE_PRIVATE);
+ FL_UNSET(top_scope, SCOPE_MODFUNC);
}
else {
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
@@ -4006,7 +4042,12 @@ mod_modfunc(argc, argv, module)
ID id;
NODE *body;
- rb_clear_cache();
+ if (argc == 0) {
+ FL_SET(the_scope, SCOPE_PRIVATE);
+ FL_SET(the_scope, SCOPE_MODFUNC);
+ return module;
+ }
+
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
for (i=0; i<argc; i++) {
id = rb_to_id(argv[i]);
@@ -4015,6 +4056,7 @@ mod_modfunc(argc, argv, module)
NameError("undefined method `%s' for module `%s'",
rb_id2name(id), rb_class2name(module));
}
+ rb_clear_cache_by_id(id);
rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC);
}
return module;
@@ -4053,17 +4095,17 @@ mod_include(argc, argv, module)
}
VALUE
-class_new_instance(argc, argv, class)
+class_new_instance(argc, argv, klass)
int argc;
VALUE *argv;
- VALUE class;
+ VALUE klass;
{
VALUE obj;
- if (FL_TEST(class, FL_SINGLETON)) {
+ if (FL_TEST(klass, FL_SINGLETON)) {
TypeError("can't create instance of virtual class");
}
- obj = obj_alloc(class);
+ obj = obj_alloc(klass);
PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
rb_funcall2(obj, init, argc, argv);
POP_ITER();
@@ -4225,6 +4267,7 @@ Init_eval()
rb_define_global_function("global_variables", f_global_variables, 0);
rb_define_method(mKernel, "send", f_send, -1);
+ rb_define_method(mKernel, "pass_block", f_pass_block, -1);
rb_define_method(mKernel, "instance_eval", obj_instance_eval, 1);
rb_define_private_method(cModule, "append_features", mod_append_features, 1);
@@ -4303,19 +4346,45 @@ static void
blk_mark(data)
struct BLOCK *data;
{
- gc_mark_frame(&data->frame);
- gc_mark(data->scope);
- gc_mark(data->var);
- gc_mark(data->body);
- gc_mark(data->self);
- gc_mark(data->d_vars);
+ while (data) {
+ gc_mark_frame(&data->frame);
+ gc_mark(data->scope);
+ gc_mark(data->var);
+ gc_mark(data->body);
+ gc_mark(data->self);
+ gc_mark(data->d_vars);
+ data = data->prev;
+ }
}
static void
blk_free(data)
struct BLOCK *data;
{
- free(data->frame.argv);
+ struct BLOCK *tmp;
+
+ while (data) {
+ free(data->frame.argv);
+ tmp = data;
+ data = data->prev;
+ free(tmp);
+ }
+}
+
+static void
+blk_copy_prev(block)
+ struct BLOCK *block;
+{
+ struct BLOCK *tmp;
+
+ while (block->prev) {
+ tmp = ALLOC_N(struct BLOCK, 1);
+ MEMCPY(tmp, block->prev, struct BLOCK, 1);
+ tmp->frame.argv = ALLOC_N(VALUE, tmp->frame.argc);
+ MEMCPY(tmp->frame.argv, block->frame.argv, VALUE, tmp->frame.argc);
+ block->prev = tmp;
+ block = tmp;
+ }
}
static VALUE
@@ -4329,11 +4398,21 @@ f_binding(self)
bind = Data_Make_Struct(cData, struct BLOCK, blk_mark, blk_free, data);
MEMCPY(data, the_block, struct BLOCK, 1);
+#ifdef THREAD
+ data->orig_thread = thread_current();
+#endif
data->iter = f_iterator_p();
data->frame.last_func = 0;
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
+ if (data->iter) {
+ blk_copy_prev(data);
+ }
+ else {
+ data->prev = 0;
+ }
+
scope_dup(data->scope);
POP_BLOCK();
@@ -4347,8 +4426,8 @@ f_binding(self)
#define PROC_TMASK (FL_USER1|FL_USER2)
static VALUE
-proc_s_new(class)
- VALUE class;
+proc_s_new(klass)
+ VALUE klass;
{
volatile VALUE proc;
struct BLOCK *data;
@@ -4357,7 +4436,7 @@ proc_s_new(class)
ArgError("tryed to create Procedure-Object out of iterator");
}
- proc = Data_Make_Struct(class, struct BLOCK, blk_mark, blk_free, data);
+ proc = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data);
*data = *the_block;
#ifdef THREAD
@@ -4366,6 +4445,12 @@ proc_s_new(class)
data->iter = f_iterator_p();
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
+ if (data->iter) {
+ blk_copy_prev(data);
+ }
+ else {
+ data->prev = 0;
+ }
scope_dup(data->scope);
if (safe_level >= 3) {
@@ -4392,6 +4477,22 @@ f_lambda()
return proc_s_new(cProc);
}
+static int
+blk_orphan(data)
+ struct BLOCK *data;
+{
+ if (data->scope && data->scope != top_scope &&
+ (data->scope->flag & SCOPE_NOSTACK)) {
+ return 1;
+ }
+#ifdef THREAD
+ if (data->orig_thread != thread_current()) {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
static VALUE
proc_call(proc, args)
VALUE proc, args; /* OK */
@@ -4414,32 +4515,22 @@ proc_call(proc, args)
}
Data_Get_Struct(proc, struct BLOCK, data);
+ orphan = blk_orphan(data);
+
+ /* PUSH BLOCK from data */
+ PUSH_BLOCK2(data);
+ PUSH_ITER(ITER_CUR);
+ the_frame->iter = ITER_CUR;
- if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) {
- orphan = 1;
- }
- else {
-#ifdef THREAD
- if (data->orig_thread != thread_current()) {
- orphan = 1;
- }
- else
-#endif
- orphan = 0;
- }
if (orphan) {/* orphan procedure */
if (iterator_p()) {
- data->frame.iter = ITER_CUR;
+ the_block->frame.iter = ITER_CUR;
}
else {
- data->frame.iter = ITER_NOT;
+ the_block->frame.iter = ITER_NOT;
}
}
- /* PUSH BLOCK from data */
- PUSH_BLOCK2(data);
- PUSH_ITER(ITER_CUR);
- the_frame->iter = ITER_CUR;
if (FL_TEST(proc, PROC_TAINT)) {
switch (RBASIC(proc)->flags & PROC_TMASK) {
case PROC_T3:
@@ -4487,6 +4578,76 @@ proc_call(proc, args)
return result;
}
+static VALUE
+proc_iterate(proc)
+ VALUE proc;
+{
+ VALUE lambda = f_lambda();
+ struct BLOCK *data;
+ volatile VALUE result = Qnil;
+ int state;
+ volatile int orphan;
+ volatile int safe = safe_level;
+
+ Data_Get_Struct(lambda, struct BLOCK, data);
+ data->frame.iter = ITER_PRE;
+ data->iter = ITER_PRE;
+
+ Data_Get_Struct(proc, struct BLOCK, data);
+ orphan = blk_orphan(data);
+
+ /* PUSH BLOCK from data */
+ PUSH_BLOCK2(data);
+ PUSH_ITER(ITER_PRE);
+ the_frame->iter = ITER_PRE;
+ if (FL_TEST(proc, PROC_TAINT)) {
+ switch (RBASIC(proc)->flags & PROC_TMASK) {
+ case PROC_T3:
+ safe_level = 3;
+ break;
+ case PROC_T4:
+ safe_level = 4;
+ break;
+ case PROC_T5:
+ safe_level = 5;
+ break;
+ }
+ }
+
+ PUSH_TAG(PROT_NONE);
+ state = EXEC_TAG();
+ if (state == 0) {
+ result = proc_call(lambda, Qnil);
+ }
+ POP_TAG();
+
+ POP_ITER();
+ if (the_block->tag->dst == state) {
+ state &= TAG_MASK;
+ orphan = 2;
+ }
+ POP_BLOCK();
+ safe_level = safe;
+
+ if (state) {
+ if (orphan == 2) {/* escape from orphan procedure */
+ switch (state) {
+ case TAG_BREAK:
+ Raise(eLocalJumpError, "break from proc-closure");
+ break;
+ case TAG_RETRY:
+ Raise(eLocalJumpError, "retry from proc-closure");
+ break;
+ case TAG_RETURN:
+ Raise(eLocalJumpError, "return from proc-closure");
+ break;
+ }
+ }
+ JUMP_TAG(state);
+ }
+ return result;
+}
+
void
Init_Proc()
{
@@ -4496,6 +4657,7 @@ Init_Proc()
rb_define_singleton_method(cProc, "new", proc_s_new, 0);
rb_define_method(cProc, "call", proc_call, -2);
+ rb_define_method(cProc, "iterate", proc_iterate, 0);
rb_define_global_function("proc", f_lambda, 0);
rb_define_global_function("lambda", f_lambda, 0);
rb_define_global_function("binding", f_binding, 0);
@@ -4562,7 +4724,7 @@ struct thread {
struct BLOCK *block;
struct iter *iter;
struct tag *tag;
- VALUE class;
+ VALUE klass;
VALUE trace;
@@ -4671,6 +4833,7 @@ thread_free(th)
{
if (th->stk_ptr) free(th->stk_ptr);
th->stk_ptr = 0;
+ free(th);
}
static thread_t
@@ -4707,7 +4870,7 @@ thread_save_context(th)
th->frame = the_frame;
th->scope = the_scope;
- th->class = the_class;
+ th->klass = the_class;
th->dyna_vars = the_dyna_vars;
th->block = the_block;
th->iter = the_iter;
@@ -4764,12 +4927,11 @@ thread_restore_context(th, exit)
the_frame = th->frame;
the_scope = th->scope;
- the_class = th->class;
+ the_class = th->klass;
the_dyna_vars = th->dyna_vars;
the_block = th->block;
the_iter = th->iter;
prot_tag = th->tag;
- the_class = th->class;
errat = th->errat;
errinfo = th->errinfo;
last_status = th->last_status;
@@ -5376,7 +5538,7 @@ thread_alloc()
th->frame = 0;
th->scope = 0;
- th->class = 0;
+ th->klass = 0;
th->dyna_vars = 0;
th->block = 0;
th->iter = 0;
@@ -5721,7 +5883,7 @@ f_catch(dmy, tag)
val = rb_yield(tag);
}
else if (state == TAG_THROW && prot_tag->tag == prot_tag->dst) {
- val = prot_tag->tag_retval;
+ val = prot_tag->retval;
state = 0;
}
POP_TAG();
@@ -5745,7 +5907,7 @@ f_throw(argc, argv)
while (tt) {
if (tt->tag == t) {
tt->dst = t;
- tt->tag_retval = value;
+ tt->retval = value;
break;
}
#ifdef THREAD
@@ -5773,7 +5935,7 @@ return_value(val)
while (tt) {
if (tt->tag == PROT_FUNC) {
- tt->tag_retval = val;
+ tt->retval = val;
break;
}
#ifdef THREAD