[#1094] Re: [ruby-cvs] ruby, ruby/lib: * eval.c (ev_const_defined, ev_const_get), variable.c — Dave Thomas <dave@...>

> * eval.c (rb_mod_autoload, rb_mod_autoload_p): new method;

12 messages 2003/05/29
[#1095] Re: [ruby-cvs] ruby, ruby/lib: * eval.c (ev_const_defined, ev_const_get), variable.c — nobu.nokada@... 2003/05/29

Hi,

Re: [1.8] terminated object / invalid inspect_tbl

From: ts <decoux@...>
Date: 2003-05-27 09:18:26 UTC
List: ruby-core #1092
>>>>> "Y" == Yukihiro Matsumoto <matz@ruby-lang.org> writes:

Y> Yeah, I'd like to see the code.

 It's a toy actually : it don't work yet with alias and it need some other
 modifications 


Guy Decoux

diff -u ../ruby/env.h ruby/env.h
--- ../ruby/env.h	2003-01-16 08:34:01.000000000 +0100
+++ ruby/env.h	2003-05-25 16:32:33.000000000 +0200
@@ -19,6 +19,8 @@
     VALUE *argv;
     ID last_func;
     ID orig_func;
+    ID orig_id;
+    VALUE orig_class;
     VALUE last_class;
     VALUE cbase;
     struct FRAME *prev;
diff -u ../ruby/eval.c ruby/eval.c
--- ../ruby/eval.c	2003-05-26 17:16:33.000000000 +0200
+++ ruby/eval.c	2003-05-26 18:26:34.000000000 +0200
@@ -106,6 +106,7 @@
 static VALUE rb_cUnboundMethod;
 static VALUE umethod_bind _((VALUE, VALUE));
 static VALUE rb_mod_define_method _((int, VALUE*, VALUE));
+static VALUE rb_mod_define_hook _((int, VALUE*, VALUE));
 
 static int scope_vmode;
 #define SCOPE_PUBLIC    0
@@ -198,6 +199,7 @@
     VALUE origin;		/* where method defined  */
     NODE *method;
     int noex;
+    int hook;
 };
 
 static struct cache_entry cache[CACHE_SIZE];
@@ -344,6 +346,7 @@
 	ent->mid = ent->mid0 = id;
 	ent->noex   = 0;
 	ent->method = 0;
+	ent->hook = 0;
 	
 	return 0;
     }
@@ -432,6 +435,14 @@
     return mod;
 }
 
+static VALUE
+rb_mod_remove_hook(mod, name)
+    VALUE mod, name;
+{
+    remove_method(mod, rb_id_hook(rb_to_id(name)));
+    return mod;
+}
+
 void
 rb_disable_super(klass, name)
     VALUE klass;
@@ -591,16 +602,18 @@
 static struct FRAME *top_frame;
 static struct SCOPE *top_scope;
 
-#define PUSH_FRAME() do {		\
-    struct FRAME _frame;		\
-    _frame.prev = ruby_frame;		\
-    _frame.tmp  = 0;			\
-    _frame.node = ruby_current_node;	\
-    _frame.iter = ruby_iter->iter;	\
-    _frame.cbase = ruby_frame->cbase;	\
-    _frame.argc = 0;			\
-    _frame.argv = 0;			\
-    _frame.flags = FRAME_ALLOCA;	\
+#define PUSH_FRAME() do {			\
+    struct FRAME _frame;			\
+    _frame.prev = ruby_frame;			\
+    _frame.tmp  = 0;				\
+    _frame.node = ruby_current_node;		\
+    _frame.iter = ruby_iter->iter;		\
+    _frame.cbase = ruby_frame->cbase;		\
+    _frame.orig_class = ruby_frame->orig_class;	\
+    _frame.orig_id = ruby_frame->orig_id;	\
+    _frame.argc = 0;				\
+    _frame.argv = 0;				\
+    _frame.flags = FRAME_ALLOCA;		\
     ruby_frame = &_frame
 
 #define POP_FRAME()  			\
@@ -954,6 +967,8 @@
 static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int));
 static VALUE module_setup _((VALUE,NODE*));
 
+static VALUE rb_call_hook _((VALUE,VALUE,ID,ID,int,const VALUE*));
+
 static VALUE massign _((VALUE,NODE*,VALUE,int));
 static void assign _((VALUE,NODE*,VALUE,int));
 
@@ -1810,6 +1825,14 @@
     return mod;
 }
 
+static VALUE
+rb_mod_undef_hook(mod, name)
+    VALUE mod, name;
+{
+    rb_undef(mod, rb_id_hook(rb_to_id(name)));
+    return mod;
+}
+
 void
 rb_alias(klass, name, def)
     VALUE klass;
@@ -3015,9 +3038,23 @@
 
 	    PUSH_ITER(ruby_iter->iter?ITER_PRE:ITER_NOT);
 	    SET_CURRENT_SOURCE();
-	    result = rb_call(RCLASS(ruby_frame->last_class)->super,
-			     ruby_frame->self, ruby_frame->orig_func,
-			     argc, argv, 3);
+	    result = Qundef;
+	    if (rb_is_hook_id(ruby_frame->orig_func)) {
+		result = rb_call_hook(RCLASS(ruby_frame->last_class)->super,
+				      ruby_frame->self, 0,
+				      ruby_frame->orig_func,
+				      argc, argv);
+		if (result == Qundef) {
+		    result = rb_call(ruby_frame->orig_class, 
+				     ruby_frame->self, 
+				     ruby_frame->orig_id, argc, argv, 3);
+		}
+	    }
+	    if (result == Qundef) {
+		result = rb_call(RCLASS(ruby_frame->last_class)->super,
+				 ruby_frame->self, 
+				 ruby_frame->orig_func, argc, argv, 3);
+	    }
 	    POP_ITER();
 	}
 	break;
@@ -4015,6 +4052,8 @@
     struct BLOCK * volatile block;
     struct SCOPE * volatile old_scope;
     struct FRAME frame;
+    VALUE orig_class;
+    ID orig_id;
     NODE *cnode = ruby_current_node;
     int state;
     static unsigned serial = 1;
@@ -4028,7 +4067,11 @@
     block = ruby_block;
     frame = block->frame;
     frame.prev = ruby_frame;
+    orig_class = ruby_frame->orig_class;
+    orig_id = ruby_frame->orig_id;
     ruby_frame = &(frame);
+    ruby_frame->orig_class = orig_class;
+    ruby_frame->orig_id = orig_id;
     old_cref = (VALUE)ruby_cref;
     ruby_cref = (NODE*)ruby_frame->cbase;
     old_wrapper = ruby_wrapper;
@@ -5028,6 +5071,56 @@
 }
 
 static VALUE
+rb_call_hook(klass, recv, oid, mid, argc, argv)
+    VALUE klass, recv;
+    ID    oid, mid;
+    int argc;			/* OK */
+    const VALUE *argv;		/* OK */
+{
+    NODE  *body;		/* OK */
+    int    noex;
+    VALUE  res = Qnil;
+    ID     id = mid;
+    VALUE  oklass = klass;
+    struct cache_entry *ent, *ent_orig;
+
+    ent = cache + EXPR1(klass, mid);
+    if (oid) {
+	ent_orig =  cache + EXPR1(klass, oid);
+    }
+    if (ent->mid == mid && ent->klass == klass) {
+	if (!ent->method) {
+	    if (oid) {
+		ent_orig->hook = 2;
+	    }
+	    return Qundef;
+	}
+	klass = ent->origin;
+	id    = ent->mid0;
+	noex  = ent->noex;
+	body  = ent->method;
+    }
+    else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
+	if (oid) {
+	    ent_orig->hook = 2;
+	}
+	return Qundef;
+    }
+    if (oid) {
+	ruby_frame->orig_class = oklass;
+	ruby_frame->orig_id = oid;
+    }
+    else {
+	ruby_frame->orig_class = ruby_frame->prev->orig_class;
+	ruby_frame->orig_id = ruby_frame->prev->orig_id;
+    }
+    if (oid) {
+	ent_orig->hook = 1;
+    }
+    return rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+}
+
+static VALUE
 rb_call(klass, recv, mid, argc, argv, scope)
     VALUE klass, recv;
     ID    mid;
@@ -5037,6 +5130,7 @@
 {
     NODE  *body;		/* OK */
     int    noex;
+    VALUE  oklass = klass, res;
     ID     id = mid;
     struct cache_entry *ent;
 
@@ -5078,7 +5172,15 @@
 	}
     }
 
-    return rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+    res = Qundef;
+    ent = cache + EXPR1(oklass, mid);
+    if (ent->hook < 2 && scope != 3 && rb_has_hook()) {
+	res = rb_call_hook(oklass, recv, mid, rb_id_hook(id), argc, argv);
+    }
+    if (res == Qundef) {
+	res = rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+    }
+    return res;
 }
 
 VALUE
@@ -6501,6 +6603,9 @@
     rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, 1);
     rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
     rb_define_private_method(rb_cModule, "define_method", rb_mod_define_method, -1);
+    rb_define_private_method(rb_cModule, "remove_hook", rb_mod_remove_hook, 1);
+    rb_define_private_method(rb_cModule, "define_hook", rb_mod_define_hook, -1);
+    rb_define_private_method(rb_cModule, "undef_hook", rb_mod_undef_hook, 2);
 
     rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
     rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0);
@@ -7591,6 +7696,22 @@
     return body;
 }
 
+static VALUE
+rb_mod_define_hook(argc, argv, mod)
+    int argc;
+    VALUE *argv;
+    VALUE mod;
+{
+    ID id;
+
+    if (!argc) {
+	rb_raise(rb_eArgError, "invalid number of arguments");
+    }
+    id = rb_to_id(argv[0]);
+    argv[0] = ID2SYM(rb_id_hook(id));
+    return rb_mod_define_method(argc, argv, mod);
+}
+
 void
 Init_Proc()
 {
diff -u ../ruby/intern.h ruby/intern.h
--- ../ruby/intern.h	2003-05-26 15:47:05.000000000 +0200
+++ ruby/intern.h	2003-05-26 15:49:25.000000000 +0200
@@ -321,6 +321,9 @@
 VALUE rb_lastline_get _((void));
 void rb_lastline_set _((VALUE));
 VALUE rb_sym_all_symbols _((void));
+ID rb_id_hook _((ID));
+int rb_has_hook _((void));
+int rb_is_hook_id _((ID));
 /* process.c */
 int rb_proc_exec _((const char*));
 VALUE rb_f_exec _((int,VALUE*));
diff -u ../ruby/keywords ruby/keywords
--- ../ruby/keywords	2002-09-28 13:08:59.000000000 +0200
+++ ruby/keywords	2003-05-25 14:24:30.000000000 +0200
@@ -19,6 +19,7 @@
 ensure, {kENSURE, kENSURE}, EXPR_BEG
 false, {kFALSE, kFALSE}, EXPR_END
 for, {kFOR, kFOR}, EXPR_BEG
+hook, {kHOOK, kHOOK}, EXPR_END
 if, {kIF, kIF_MOD}, EXPR_BEG
 in, {kIN, kIN}, EXPR_BEG
 module, {kMODULE, kMODULE}, EXPR_BEG
diff -u ../ruby/parse.y ruby/parse.y
--- ../ruby/parse.y	2003-05-26 15:47:07.000000000 +0200
+++ ruby/parse.y	2003-05-26 17:32:31.000000000 +0200
@@ -32,6 +32,7 @@
 
 #define ID_SCOPE_SHIFT 3
 #define ID_SCOPE_MASK 0x07
+#define ID_HOOK     0x00
 #define ID_LOCAL    0x01
 #define ID_INSTANCE 0x02
 #define ID_GLOBAL   0x03
@@ -42,6 +43,7 @@
 #define ID_INTERNAL ID_JUNK
 
 #define is_notop_id(id) ((id)>tLAST_TOKEN)
+#define is_hook_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_HOOK)
 #define is_local_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL)
 #define is_global_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL)
 #define is_instance_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE)
@@ -74,6 +76,7 @@
     EXPR_FNAME,			/* ignore newline, no reserved words. */
     EXPR_DOT,			/* right after `.' or `::', no reserved words. */
     EXPR_CLASS,			/* immediate after `class', no here document. */
+    EXPR_COLON,                 /* right after ':' expect 'hook' */
 } lex_state;
 static NODE *lex_strterm;
 static int lex_strnest;
@@ -233,6 +236,7 @@
 	klEND
 	k__LINE__
 	k__FILE__
+	kHOOK
 
 %token <id>   tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR
 %token <node> tINTEGER tFLOAT tSTRING_CONTENT
@@ -254,7 +258,7 @@
 %type <node> block_var opt_block_var brace_block cmd_brace_block do_block lhs none
 %type <node> mlhs mlhs_head mlhs_basic mlhs_entry mlhs_item mlhs_node
 %type <id>   fitem variable sym symbol operation operation2 operation3
-%type <id>   cname fname op f_rest_arg
+%type <id>   cname fname hname hitem op f_rest_arg
 %type <num>  f_norm_arg f_arg term_push
 %token tUPLUS 		/* unary+ */
 %token tUMINUS 		/* unary- */
@@ -862,6 +866,13 @@
 		    }
 		;
 
+hname		: fname
+		| fname ':' kHOOK
+		    {
+			$$ = rb_id_hook($1);
+		    }
+		;
+
 fname		: tIDENTIFIER
 		| tCONSTANT
 		| tFID
@@ -881,11 +892,15 @@
 		| symbol
 		;
 
-undef_list	: fitem
+hitem		: hname
+		| symbol
+		;
+
+undef_list	: hitem
 		    {
 			$$ = NEW_UNDEF($1);
 		    }
-		| undef_list ',' {lex_state = EXPR_FNAME;} fitem
+		| undef_list ',' {lex_state = EXPR_FNAME;} hitem
 		    {
 			$$ = block_append($1, NEW_UNDEF($4));
 		    }
@@ -1605,7 +1620,7 @@
 		        local_pop();
 			class_nest--;
 		    }
-		| kDEF fname
+		| kDEF hname
 		    {
 			$<id>$ = cur_mid;
 			cur_mid = $2;
@@ -1622,11 +1637,10 @@
 			in_def--;
 			cur_mid = $<id>3;
 		    }
-		| kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} fname
+		| kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} hname
 		    {
 			in_single++;
 			local_push(0);
-		        lex_state = EXPR_END; /* force for args */
 		    }
 		  f_arglist
 		  bodystmt
@@ -3944,6 +3958,10 @@
 	    lex_state = EXPR_BEG;
 	    return ':';
 	}
+	if (lex_state == EXPR_COLON) {
+	    pushback(c);
+	    return ':';
+	}
 	switch (c) {
 	  case '\'':
 	    lex_strterm = NEW_STRTERM(str_ssym, c, 0);
@@ -4324,6 +4342,7 @@
 
     {
 	int result = 0;
+	int found_colon = 0;
 
 	switch (tok()[0]) {
 	  case '$':
@@ -4351,6 +4370,7 @@
 			tokfix();
 		    }
 		    else {
+			found_colon = c == ':';
 			pushback(c);
 		    }
 		}
@@ -4373,6 +4393,10 @@
 		    if (state == EXPR_FNAME) {
 			yylval.id = rb_intern(kw->name);
 		    }
+		    if (state == EXPR_COLON && kw->id[0] == kHOOK) {
+			yylval.id = rb_intern(kw->name);
+			return kw->id[0];
+		    }
 		    if (kw->id[0] == kDO) {
 			if (COND_P()) return kDO_COND;
 			if (CMDARG_P() && state != EXPR_CMDARG)
@@ -4381,12 +4405,14 @@
 			    return kDO_BLOCK;
 			return kDO;
 		    }
-		    if (state == EXPR_BEG)
-			return kw->id[0];
-		    else {
-			if (kw->id[0] != kw->id[1])
-			    lex_state = EXPR_BEG;
-			return kw->id[1];
+		    if (kw->id[0] != kHOOK) {
+			if (state == EXPR_BEG)
+			    return kw->id[0];
+			else {
+			    if (kw->id[0] != kw->id[1])
+				lex_state = EXPR_BEG;
+			    return kw->id[1];
+			}
 		    }
 		}
 	    }
@@ -4408,8 +4434,11 @@
 	    }
 	}
 	yylval.id = rb_intern(tok());
-	if (is_local_id(yylval.id) &&
-	    ((dyna_in_block() && rb_dvar_defined(yylval.id)) || local_id(yylval.id))) {
+	if (found_colon) {
+	    lex_state = EXPR_COLON;
+	}
+	else if (is_local_id(yylval.id) &&
+		 ((dyna_in_block() && rb_dvar_defined(yylval.id)) || local_id(yylval.id))) {
 	    lex_state = EXPR_END;
 	}
 	return result;
@@ -5755,11 +5784,14 @@
 static st_table *sym_tbl;
 static st_table *sym_rev_tbl;
 
+static ID id_allocate;
+
 void
 Init_sym()
 {
     sym_tbl = st_init_strtable_with_size(200);
     sym_rev_tbl = st_init_numtable_with_size(200);
+    id_allocate = rb_intern("allocate");
 }
 
 static ID last_id = tLAST_TOKEN;
@@ -5837,7 +5869,14 @@
     while (*m && is_identchar(*m)) {
 	m++;
     }
-    if (*m) id = ID_JUNK;
+    if (*m) {
+	if (*m == ':') {
+	    id = ID_HOOK;
+	}
+	else {
+	    id = ID_JUNK;
+	}
+    }
     id |= ++last_id << ID_SCOPE_SHIFT;
   id_regist:
     name = strdup(name);
@@ -5861,6 +5900,9 @@
 	}
     }
 
+    if (rb_is_hook_id(id)) {
+	return "hooked method";
+    }
     if (st_lookup(sym_rev_tbl, id, (st_data_t *)&name))
 	return name;
 
@@ -6002,3 +6044,33 @@
 	special_local_set('_', val);
     }
 }
+
+static int has_hook = 0;
+
+ID
+rb_id_hook(id)
+    ID id;
+{
+    has_hook = Qtrue;
+    if (id == ID_ALLOCATOR) {
+	id = id_allocate;
+    }
+    return (id & ~ID_SCOPE_MASK);
+}
+
+int
+rb_has_hook()
+{
+    return has_hook;
+}
+
+int 
+rb_is_hook_id(id)
+    ID id;
+{
+    if (is_hook_id(id)) return Qtrue;
+    return Qfalse;
+}
+
+
+    

In This Thread