···
+
if (node->nd_tbl) {
VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1);
*vars++ = (VALUE)node;
@@ -3570,6 +3597,7 @@
ruby_dyna_vars = block->dyna_vars;
}
ruby_class = klass?klass:block->klass;
+ ruby_frame->curr_class = ruby_class;
if (!klass) self = block->self;
node = block->body;
@@ -3826,7 +3854,11 @@
break;
case NODE_CVASGN:
- rb_cvar_set(ruby_cbase, lhs->nd_vid, val);
+ if (!FL_TEST(ruby_cbase, FL_SINGLETON)) {
+ rb_cvar_set(ruby_cbase, lhs->nd_vid, val);
+ break;
+ }
+ rb_cvar_set(rb_iv_get(ruby_cbase, "__attached__"), lhs->nd_vid, val);
break;
case NODE_MASGN:
@@ -4362,6 +4394,9 @@
ruby_frame->self = recv;
ruby_frame->argc = argc;
ruby_frame->argv = argv;
+ if (nd_type(body) != NODE_CFUNC) {
+ ruby_frame->curr_class = klass;
+ }
switch (nd_type(body)) {
case NODE_CFUNC:
@@ -4902,6 +4937,7 @@
if (TYPE(ruby_class) == T_ICLASS) {
ruby_class = RBASIC(ruby_class)->klass;
}
+ ruby_frame->curr_class = ruby_class;
PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) {
NODE *node;
@@ -5043,6 +5079,7 @@
ruby_frame->last_class = _frame.prev->last_class;
ruby_frame->argc = _frame.prev->argc;
ruby_frame->argv = _frame.prev->argv;
+ ruby_frame->curr_class = ruby_class;
if (ruby_cbase != under) {
ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,ruby_frame->cbase);
}
@@ -5248,6 +5285,7 @@
ruby_frame->last_class = 0;
ruby_frame->self = self;
ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_class,0,0);
+ ruby_frame->curr_class = ruby_class;
PUSH_SCOPE();
/* default visibility is private at loading toplevel */
SCOPE_SET(SCOPE_PRIVATE);
@@ -6005,6 +6043,8 @@
rb_define_method(rb_mKernel, "send", rb_f_send, -1);
rb_define_method(rb_mKernel, "__send__", rb_f_send, -1);
rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1);
+ rb_define_private_method(rb_mKernel, "remove_private_variable",
+ remove_private_variable, 1);
rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
@@ -9091,3 +9131,16 @@
tt = tt->prev;
}
}
+
+static VALUE
+rb_current_class()
+{
+ return ruby_frame->curr_class;
+}
+
+static VALUE
+remove_private_variable(obj, name)
+ VALUE obj, name;
+{
+ return rb_obj_remove_private_variable(obj, rb_current_class(), name);
+}
diff -u ruby-1.6.7/gc.c ruby-1.6.m/gc.c
--- ruby-1.6.7/gc.c 2002-02-13 10:02:15.000000000 +0100
+++ ruby-1.6.m/gc.c 2002-09-07 16:11:11.000000000 +0200
@@ -911,6 +911,7 @@
{
mark_locations_array(frame->argv, frame->argc);
rb_gc_mark(frame->cbase);
+ rb_gc_mark(frame->curr_class);
}
#ifdef __GNUC__
diff -u ruby-1.6.7/intern.h ruby-1.6.m/intern.h
--- ruby-1.6.7/intern.h 2002-02-27 05:50:30.000000000 +0100
+++ ruby-1.6.m/intern.h 2002-09-11 12:12:50.000000000 +0200
@@ -267,6 +267,7 @@
void rb_parser_while_loop _((int, int));
int rb_is_const_id _((ID));
int rb_is_instance_id _((ID));
+int rb_is_private_id _((ID));
int rb_is_class_id _((ID));
VALUE rb_backref_get _((void));
void rb_backref_set _((VALUE));
@@ -370,6 +371,11 @@
void rb_mark_generic_ivar _((VALUE));
void rb_mark_generic_ivar_tbl _((void));
void rb_free_generic_ivar _((VALUE));
+VALUE rb_pvar_get _((VALUE, VALUE, ID));
+VALUE rb_pvar_set _((VALUE, VALUE, ID, VALUE));
+VALUE rb_pvar_defined _((VALUE, VALUE, ID));
+VALUE rb_obj_private_variables _((VALUE, VALUE));
+VALUE rb_obj_remove_private_variable _((VALUE, VALUE, VALUE));
VALUE rb_ivar_get _((VALUE, ID));
VALUE rb_ivar_set _((VALUE, ID, VALUE));
VALUE rb_ivar_defined _((VALUE, ID));
diff -u ruby-1.6.7/marshal.c ruby-1.6.m/marshal.c
--- ruby-1.6.7/marshal.c 2002-02-28 07:52:47.000000000 +0100
+++ ruby-1.6.m/marshal.c 2002-09-08 13:50:33.000000000 +0200
@@ -755,19 +755,41 @@
return v;
}
+struct obj_id {
+ VALUE obj;
+ ID id;
+};
+
+static VALUE
+r_i_pvar(ary, st)
+ VALUE ary;
+ struct obj_id *st;
+{
+ rb_pvar_set(st->obj, RARRAY(ary)->ptr[0], st->id, RARRAY(ary)->ptr[1]);
+ return Qnil;
+}
+
static void
r_ivar(obj, arg)
VALUE obj;
struct load_arg *arg;
{
long len;
+ struct obj_id st;
len = r_long(arg);
if (len > 0) {
while (len--) {
ID id = r_symbol(arg);
VALUE val = r_object(arg);
- rb_ivar_set(obj, id, val);
+ if (rb_is_private_id(id)) {
+ st.obj = obj;
+ st.id = id;
+ rb_iterate(rb_each, val, r_i_pvar, (VALUE)&st);
+ }
+ else {
+ rb_ivar_set(obj, id, val);
+ }
}
}
}
diff -u ruby-1.6.7/object.c ruby-1.6.m/object.c
--- ruby-1.6.7/object.c 2002-02-04 09:09:10.000000000 +0100
+++ ruby-1.6.m/object.c 2002-09-11 12:14:15.000000000 +0200
@@ -1165,7 +1165,7 @@
rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0);
rb_define_private_method(rb_mKernel, "remove_instance_variable",
rb_obj_remove_instance_variable, 1);
-
+ rb_define_method(rb_mKernel, "private_variables", rb_obj_private_variables, 1);
rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1);
rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1);
rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1);
diff -u ruby-1.6.7/parse.y ruby-1.6.m/parse.y
--- ruby-1.6.7/parse.y 2002-02-20 05:28:51.000000000 +0100
+++ ruby-1.6.m/parse.y 2002-09-08 12:25:58.000000000 +0200
@@ -22,12 +22,14 @@
#define ID_SCOPE_SHIFT 3
#define ID_SCOPE_MASK 0x07
+
#define ID_LOCAL 0x01
#define ID_INSTANCE 0x02
#define ID_GLOBAL 0x03
#define ID_ATTRSET 0x04
#define ID_CONST 0x05
#define ID_CLASS 0x06
+#define ID_PRIVATE 0x07
#define is_notop_id(id) ((id)>LAST_TOKEN)
#define is_local_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL)
@@ -36,6 +38,7 @@
#define is_attrset_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET)
#define is_const_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CONST)
#define is_class_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CLASS)
+#define is_private_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_PRIVATE)
NODE *ruby_eval_tree_begin = 0;
NODE *ruby_eval_tree = 0;
@@ -673,7 +676,7 @@
if ($2 == tOROP) {
$<node>3->nd_value = $4;
$$ = NEW_OP_ASGN_OR(gettable($1), $<node>3);
- if (is_instance_id($1)) {
+ if (is_instance_id($1) || is_private_id($1)) {
$$->nd_aid = $1;
}
}
@@ -4182,7 +4185,7 @@
else if (is_global_id(id)) {
return NEW_GVAR(id);
}
- else if (is_instance_id(id)) {
+ else if (is_instance_id(id) || is_private_id(id)) {
return NEW_IVAR(id);
}
else if (is_const_id(id)) {
@@ -4237,7 +4240,7 @@
else if (is_global_id(id)) {
return NEW_GASGN(id, val);
}
- else if (is_instance_id(id)) {
+ else if (is_instance_id(id) || is_private_id(id)) {
return NEW_IASGN(id, val);
}
else if (is_const_id(id)) {
@@ -4955,6 +4958,8 @@
case '@':
if (name[1] == '@')
id |= ID_CLASS;
+ else if (name[1] == '_')
+ id |= ID_PRIVATE;
else
id |= ID_INSTANCE;
break;
@@ -5065,6 +5070,14 @@
return Qfalse;
}
+int
+rb_is_private_id(id)
+ ID id;
+{
+ if (is_private_id(id)) return Qtrue;
+ return Qfalse;
+}
+
static void
special_local_set(c, val)
char c;
diff -u ruby-1.6.7/ruby.h ruby-1.6.m/ruby.h
--- ruby-1.6.7/ruby.h 2002-02-26 14:08:17.000000000 +0100
+++ ruby-1.6.m/ruby.h 2002-09-08 14:00:04.000000000 +0200
@@ -466,6 +466,8 @@
VALUE rb_gv_get _((const char*));
VALUE rb_iv_get _((VALUE, const char*));
VALUE rb_iv_set _((VALUE, const char*, VALUE));
+VALUE rb_pv_get _((VALUE, VALUE, const char*));
+VALUE rb_pv_set _((VALUE, VALUE, const char*, VALUE));
VALUE rb_equal _((VALUE,VALUE));
diff -u ruby-1.6.7/variable.c ruby-1.6.m/variable.c
--- ruby-1.6.7/variable.c 2002-02-19 05:48:04.000000000 +0100
+++ ruby-1.6.m/variable.c 2002-09-11 12:12:17.000000000 +0200
@@ -885,6 +885,7 @@
VALUE clone, obj;
{
st_table *tbl;
+ VALUE val;
if (!generic_iv_tbl) return;
if (st_lookup(generic_iv_tbl, obj, &tbl)) {
@@ -892,6 +893,295 @@
}
}
+static void
+check_valid_class(klass)
+ VALUE klass;
+{
+ switch (TYPE(klass)) {
+ case T_CLASS:
+ case T_ICLASS:
+ case T_MODULE:
+ case T_TRUE:
+ case T_FALSE:
+ case T_NIL:
+ break;
+ default:
+ rb_raise(rb_eArgError, "expected a class object");
+ }
+}
+
+static VALUE
+private_ivar_get(obj, klass, id)
+ VALUE obj, klass;
+ ID id;
+{
+ st_table *tbl;
+ VALUE val;
+
+ if (!generic_iv_tbl) return Qnil;
+ if (!st_lookup(generic_iv_tbl, obj, &tbl)) return Qnil;
+ if (st_lookup(tbl, id, &val) && TYPE(val) == T_HASH &&
+ st_lookup(RHASH(val)->tbl, klass, &val)) {
+ return val;
+ }
+ return Qnil;
+}
+
+VALUE
+rb_pvar_get(obj, klass, id)
+ VALUE klass, obj;
+ ID id;
+{
+ VALUE val;
+
+ check_valid_class(klass);
+ if (!rb_is_private_id(id)) {
+ rb_raise(rb_eNameError, "`%s' is not a private variable",
+ rb_id2name(id));
+ }
+ switch (TYPE(obj)) {
+ case T_OBJECT:
+ case T_CLASS:
+ case T_MODULE:
+ if (ROBJECT(obj)->iv_tbl &&
+ st_lookup(ROBJECT(obj)->iv_tbl, id, &val) &&
+ TYPE(val) == T_HASH && st_lookup(RHASH(val)->tbl, klass, &val)) {
+ return val;
+ }
+ break;
+ default:
+ if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
+ return private_ivar_get(obj, klass, id);
+ }
+ break;
+ }
+ if (ruby_verbose) {
+ rb_warning("private variable %s not initialized", rb_id2name(id));
+ }
+ return Qnil;
+}
+
+static void
+private_ivar_set(obj, klass, id, val)
+ VALUE obj, klass;
+ ID id;
+ VALUE val;
+{
+ st_table *tbl;
+ VALUE stbl;
+
+ if (rb_special_const_p(obj)) {
+ special_generic_ivar = 1;
+ }
+ if (!generic_iv_tbl) {
+ generic_iv_tbl = st_init_numtable();
+ }
+
+ if (!st_lookup(generic_iv_tbl, obj, &tbl)) {
+ FL_SET(obj, FL_EXIVAR);
+ tbl = st_init_numtable();
+ st_add_direct(generic_iv_tbl, obj, tbl);
+ }
+ if (!st_lookup(tbl, id, &stbl)) {
+ stbl = rb_hash_new();
+ st_add_direct(tbl, id, stbl);
+ }
+ if (TYPE(stbl) != T_HASH) {
+ rb_raise(rb_eNameError, "`%s' is not a private variable",
+ rb_id2name(id));
+ }
+ rb_hash_aset(stbl, klass, val);
+}
+
+VALUE
+rb_pvar_set(obj, klass, id, val)
+ VALUE klass, obj;
+ ID id;
+ VALUE val;
+{
+ VALUE stbl;
+
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+ rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
+ if (OBJ_FROZEN(obj)) rb_error_frozen("object");
+
+ check_valid_class(klass);
+ if (!rb_is_private_id(id)) {
+ rb_raise(rb_eNameError, "`%s' is not a private variable",
+ rb_id2name(id));
+ }
+ switch (TYPE(obj)) {
+ case T_OBJECT:
+ case T_CLASS:
+ case T_MODULE:
+ if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable();
+ if (!st_lookup(ROBJECT(obj)->iv_tbl, id, &stbl)) {
+ stbl = rb_hash_new();
+ st_add_direct(ROBJECT(obj)->iv_tbl, id, stbl);
+ }
+ if (TYPE(stbl) != T_HASH) {
+ rb_raise(rb_eNameError, "`%s' is not a private variable",
+ rb_id2name(id));
+ }
+ rb_hash_aset(stbl, klass, val);
+ break;
+ default:
+ private_ivar_set(obj, id, val);
+ break;
+ }
+ return val;
+}
+
+static VALUE
+private_ivar_defined(obj, klass, id)
+ VALUE obj, klass;
+ ID id;
+{
+ st_table *tbl;
+ VALUE val;
+
+ if (!generic_iv_tbl) return Qfalse;
+ if (st_lookup(generic_iv_tbl, obj, &tbl) && st_lookup(tbl, id, &val) &&
+ TYPE(val) == T_HASH && st_lookup(RHASH(val)->tbl, klass, 0)) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+VALUE
+rb_pvar_defined(obj, klass, id)
+ VALUE obj, klass;
+ ID id;
+{
+ VALUE stbl;
+
+ check_valid_class(klass);
+ if (!rb_is_private_id(id)) {
+ rb_raise(rb_eNameError, "`%s' is not a private variable",
+ rb_id2name(id));
+ }
+ switch (TYPE(obj)) {
+ case T_OBJECT:
+ case T_CLASS:
+ case T_MODULE:
+ if (ROBJECT(obj)->iv_tbl &&
+ st_lookup(ROBJECT(obj)->iv_tbl, id, &stbl) &&
+ TYPE(stbl) == T_HASH && st_lookup(RHASH(stbl)->tbl, klass, 0))
+ return Qtrue;
+ break;
+ default:
+ if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
+ return private_ivar_defined(obj, klass, id);
+ }
+ break;
+ }
+ return Qfalse;
+}
+
+struct ary_class {
+ VALUE ary;
+ VALUE klass;
+};
+
+static int
+pvar_i(key, val, st)
+ ID key;
+ VALUE val;
+ struct ary_class *st;
+{
+ if (rb_is_private_id(key) && TYPE(val) == T_HASH &&
+ st_lookup(RHASH(val)->tbl, st->klass, 0)) {
+ rb_ary_push(st->ary, rb_str_new2(rb_id2name(key)));
+ }
+ return ST_CONTINUE;
+}
+
+VALUE
+rb_obj_private_variables(obj, klass)
+ VALUE obj, klass;
+{
+ VALUE ary;
+ struct ary_class st;
+
+ check_valid_class(klass);
+ ary = rb_ary_new();
+ switch (TYPE(obj)) {
+ case T_OBJECT:
+ case T_CLASS:
+ case T_MODULE:
+ if (ROBJECT(obj)->iv_tbl) {
+ st.ary = ary;
+ st.klass = klass;
+ st_foreach(ROBJECT(obj)->iv_tbl, pvar_i, &st);
+ }
+ break;
+ default:
+ if (!generic_iv_tbl) break;
+ if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
+ st_table *tbl;
+
+ if (st_lookup(generic_iv_tbl, obj, &tbl)) {
+ st.ary = ary;
+ st.klass = klass;
+ st_foreach(tbl, pvar_i, &st);
+ }
+ }
+ break;
+ }
+ return ary;
+}
+
+static VALUE
+generic_pvar_remove(obj, klass, id)
+ VALUE obj, klass;
+ ID id;
+{
+ st_table *tbl;
+ VALUE val, stbl;
+
+ if (!generic_iv_tbl) return Qnil;
+ if (!st_lookup(generic_iv_tbl, obj, &tbl)) return Qnil;
+ if (!st_lookup(tbl, id, &stbl)) return Qnil;
+ if (TYPE(stbl) != T_HASH) return Qnil;
+ val = RHASH(stbl)->ifnone;
+ st_delete(RHASH(stbl)->tbl, &klass, &val);
+ return val;
+}
+
+VALUE
+rb_obj_remove_private_variable(obj, klass, name)
+ VALUE obj, klass, name;
+{
+ VALUE val = Qnil;
+ ID id = rb_to_id(name);
+
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+ rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
+ if (OBJ_FROZEN(obj)) rb_error_frozen("object");
+ if (!rb_is_private_id(id)) {
+ rb_raise(rb_eNameError, "`%s' is not a private variable",
+ rb_id2name(id));
+ }
+ check_valid_class(klass);
+
+ switch (TYPE(obj)) {
+ case T_OBJECT:
+ case T_CLASS:
+ case T_MODULE:
+ if (ROBJECT(obj)->iv_tbl &&
+ st_lookup(ROBJECT(obj)->iv_tbl, id, &val) &&
+ TYPE(val) == T_HASH) {
+ st_delete(RHASH(val)->tbl, &klass, &val);
+ }
+ break;
+ default:
+ if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
+ return generic_pvar_remove(obj, klass, id);
+ break;
+ }
+ return val;
+}
+
VALUE
rb_ivar_get(obj, id)
VALUE obj;
@@ -899,6 +1189,9 @@
{
VALUE val;
+ if (rb_is_private_id(id)) {
+ return rb_pvar_get(obj, 1, id);
+ }
switch (TYPE(obj)) {
case T_OBJECT:
case T_CLASS:
@@ -926,6 +1219,9 @@
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
if (OBJ_FROZEN(obj)) rb_error_frozen("object");
+ if (rb_is_private_id(id)) {
+ return rb_pvar_set(obj, 1, id, val);
+ }
switch (TYPE(obj)) {
case T_OBJECT:
case T_CLASS:
@@ -945,6 +1241,9 @@
VALUE obj;
ID id;
{
+ if (rb_is_private_id(id)) {
+ return rb_pvar_defined(obj, 1, id);
+ }
switch (TYPE(obj)) {
case T_OBJECT:
case T_CLASS:
@@ -1549,3 +1848,24 @@
return rb_ivar_set(obj, id, val);
}
+
+VALUE
+rb_pv_get(obj, klass, name)
+ VALUE obj, klass;
+ const char *name;
+{
+ ID id = rb_intern(name);
+
+ return rb_pvar_get(obj, klass, id);
+}
+
+VALUE
+rb_pv_set(obj, klass, name, val)
+ VALUE obj, klass;
+ const char *name;
+ VALUE val;
+{
+ ID id = rb_intern(name);
+
+ return rb_pvar_set(obj, klass, id, val);
+}