summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-01-23 08:03:28 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-01-23 08:03:28 +0000
commit17b99a2ed9651352c69c7abfcfdb284c1db86ed8 (patch)
tree21966e6d8ef80b64a61c0feecd339a1b60375ae4
parent4bccf2123bb86113c5b4a8164bd1d0981490e1ba (diff)
downloadruby-17b99a2ed9651352c69c7abfcfdb284c1db86ed8.tar.gz
* eval.c (ivar2_prepare): prepare ivar2 ID before processing.
* marshal.c (w_symbol): support class local instance variables. * marshal.c (r_object0): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/matzruby@11561 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog8
-rw-r--r--eval.c27
-rw-r--r--gc.c26
-rw-r--r--intern.h3
-rw-r--r--marshal.c66
-rw-r--r--node.h4
-rw-r--r--parse.y35
-rw-r--r--string.c55
-rw-r--r--variable.c2
9 files changed, 205 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index 6fb70324f3..5bd9597a8d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -372,6 +372,14 @@ Fri Dec 1 16:31:53 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/tcltklib.c: shouldn't run the killed thread at callback.
[ruby-talk: 227408]
+Tue Nov 28 17:31:40 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (ivar2_prepare): prepare ivar2 ID before processing.
+
+ * marshal.c (w_symbol): support class local instance variables.
+
+ * marshal.c (r_object0): ditto.
+
Tue Nov 28 17:25:11 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* array.c (ary_iter_check): should check modification (size
diff --git a/eval.c b/eval.c
index dc2e9e0372..caa7d7b0ee 100644
--- a/eval.c
+++ b/eval.c
@@ -1861,6 +1861,14 @@ cvar_cbase(int warn)
return ruby_cbase;
}
+static void
+ivar2_prepare(NODE *node)
+{
+ if (node->nd_vid == 0) {
+ node->nd_vid = rb_intern_ivar2(node->nd_aid, ruby_cbase);
+ }
+}
+
/*
* call-seq:
* Module.nesting => array
@@ -2326,6 +2334,7 @@ is_defined(VALUE self, NODE *node /* OK */, char *buf, int noeval)
case NODE_DASGN_CURR:
case NODE_GASGN:
case NODE_IASGN:
+ case NODE_IASGN2:
case NODE_CDECL:
case NODE_CVDECL:
case NODE_CVASGN:
@@ -2348,6 +2357,13 @@ is_defined(VALUE self, NODE *node /* OK */, char *buf, int noeval)
}
break;
+ case NODE_IVAR2:
+ ivar2_prepare(node);
+ if (rb_ivar_defined(self, node->nd_vid)) {
+ return "instance-variable";
+ }
+ break;
+
case NODE_CONST:
if (ev_const_defined(node->nd_vid, self)) {
return "constant";
@@ -3480,6 +3496,8 @@ rb_eval(VALUE self, NODE *n)
rb_gvar_set(node->nd_entry, result);
break;
+ case NODE_IASGN2:
+ ivar2_prepare(node);
case NODE_IASGN:
result = rb_eval(self, node->nd_value);
rb_ivar_set(self, node->nd_vid, result);
@@ -3516,6 +3534,9 @@ rb_eval(VALUE self, NODE *n)
result = rb_gvar_get(node->nd_entry);
break;
+ case NODE_IVAR2:
+ ivar2_prepare(node);
+ /* fall through */
case NODE_IVAR:
result = rb_ivar_get(self, node->nd_vid);
break;
@@ -5034,6 +5055,9 @@ assign(VALUE self, NODE *lhs, VALUE val, int pcall)
rb_gvar_set(lhs->nd_entry, val);
break;
+
+ case NODE_IASGN2:
+ ivar2_prepare(lhs);
case NODE_IASGN:
rb_ivar_set(self, lhs->nd_vid, val);
break;
@@ -5758,6 +5782,8 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid,
break;
/* for attr get/set */
+ case NODE_IVAR2:
+ ivar2_prepare(body);
case NODE_IVAR:
if (argc != 0) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
@@ -9288,6 +9314,7 @@ rb_node_arity(NODE *body)
return -1;
case NODE_ATTRSET:
return 1;
+ case NODE_IVAR2:
case NODE_IVAR:
return 0;
case NODE_BMETHOD:
diff --git a/gc.c b/gc.c
index dcad5a10fb..18adf6a374 100644
--- a/gc.c
+++ b/gc.c
@@ -1973,6 +1973,32 @@ id2ref(VALUE obj, VALUE objid)
return (VALUE)ptr;
}
+ID
+rb_dump_ivar2(ID id, VALUE *klassp)
+{
+ VALUE sym = ID2SYM(id);
+ char *ptr = RSTRING_PTR(sym);
+ long len = strlen(ptr);
+ ID oid;
+ VALUE klass;
+
+ if (RSTRING_LEN(sym) == len) return id;
+ oid = rb_intern2(ptr, len);
+
+ memcpy((char*)&klass, ptr+strlen(ptr)+1, sizeof(VALUE));
+ klass = id2ref(0, klass);
+ switch (TYPE(klass)) {
+ case T_CLASS:
+ case T_MODULE:
+ break;
+ default:
+ rb_raise(rb_eTypeError, "corrupted instance variable - %s", ptr);
+ break;
+ }
+ if (klassp) *klassp = klass;
+ return oid;
+}
+
/*
* Document-method: __id__
* Document-method: object_id
diff --git a/intern.h b/intern.h
index bb5370d2d9..5bd861228a 100644
--- a/intern.h
+++ b/intern.h
@@ -313,6 +313,7 @@ void rb_gc_call_finalizer_at_exit(void);
VALUE rb_gc_enable(void);
VALUE rb_gc_disable(void);
VALUE rb_gc_start(void);
+ID rb_dump_ivar2(ID, VALUE*);
/* hash.c */
void st_foreach_safe(struct st_table *, int (*)(ANYARGS), st_data_t);
void rb_hash_foreach(VALUE, int (*)(ANYARGS), VALUE);
@@ -395,6 +396,7 @@ ID rb_id_attrset(ID);
void rb_gc_mark_parser(void);
int rb_is_const_id(ID);
int rb_is_instance_id(ID);
+int rb_is_instance2_id(ID);
int rb_is_class_id(ID);
int rb_is_local_id(ID);
int rb_is_junk_id(ID);
@@ -520,6 +522,7 @@ void rb_str_associate(VALUE, VALUE);
VALUE rb_str_associated(VALUE);
void rb_str_setter(VALUE, ID, VALUE*);
VALUE rb_str_intern(VALUE);
+ID rb_intern_ivar2(ID, VALUE);
/* struct.c */
VALUE rb_struct_new(VALUE, ...);
VALUE rb_struct_define(const char*, ...);
diff --git a/marshal.c b/marshal.c
index 950a1b31d1..74b70c2b4e 100644
--- a/marshal.c
+++ b/marshal.c
@@ -47,7 +47,7 @@ shortlen(long len, BDIGIT *ds)
#endif
#define MARSHAL_MAJOR 4
-#define MARSHAL_MINOR 8
+#define MARSHAL_MINOR 9
#define TYPE_NIL '0'
#define TYPE_TRUE 'T'
@@ -73,6 +73,7 @@ shortlen(long len, BDIGIT *ds)
#define TYPE_MODULE 'm'
#define TYPE_SYMBOL ':'
+#define TYPE_SYMBOL2 ','
#define TYPE_SYMLINK ';'
#define TYPE_IVAR 'I'
@@ -304,7 +305,7 @@ w_float(double d, struct dump_arg *arg)
static void
w_symbol(ID id, struct dump_arg *arg)
{
- const char *sym = rb_id2name(id);
+ const char *sym;
st_data_t num;
if (st_lookup(arg->symbols, id, &num)) {
@@ -312,8 +313,22 @@ w_symbol(ID id, struct dump_arg *arg)
w_long((long)num, arg);
}
else {
- w_byte(TYPE_SYMBOL, arg);
- w_bytes(sym, strlen(sym), arg);
+ if (rb_is_instance2_id(id)) {
+ VALUE klass;
+ volatile VALUE path;
+
+ id = rb_dump_ivar2(id, &klass);
+ path = class2path(klass);
+ w_byte(TYPE_SYMBOL2, arg);
+ sym = rb_id2name(id);
+ w_bytes(sym, strlen(sym), arg);
+ w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
+ }
+ else {
+ sym = rb_id2name(id);
+ w_byte(TYPE_SYMBOL, arg);
+ w_bytes(sym, strlen(sym), arg);
+ }
st_add_direct(arg->symbols, id, arg->symbols->num_entries);
}
}
@@ -360,12 +375,14 @@ w_extended(VALUE klass, struct dump_arg *arg, int check)
static void
w_class(char type, VALUE obj, struct dump_arg *arg, int check)
{
+ volatile VALUE p;
char *path;
VALUE klass = CLASS_OF(obj);
w_extended(klass, arg, check);
w_byte(type, arg);
- path = RSTRING_PTR(class2path(rb_class_real(klass)));
+ p = class2path(rb_class_real(klass));
+ path = RSTRING_PTR(p);
w_unique(path, arg);
}
@@ -490,7 +507,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
}
w_byte(TYPE_CLASS, arg);
{
- VALUE path = class2path(obj);
+ volatile VALUE path = class2path(obj);
w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg);
}
break;
@@ -738,7 +755,9 @@ struct load_arg {
int taint;
};
+static VALUE r_entry(VALUE v, struct load_arg *arg);
static VALUE r_object(struct load_arg *arg);
+static VALUE path2class(const char *path);
static int
r_byte(struct load_arg *arg)
@@ -855,10 +874,24 @@ r_symlink(struct load_arg *arg)
static ID
r_symreal(struct load_arg *arg)
{
- ID id;
volatile VALUE s = r_bytes(arg);
+ ID id = rb_intern(RSTRING_PTR(s));
+
+ st_insert(arg->symbols, arg->symbols->num_entries, id);
+
+ return id;
+}
+
+static ID
+r_symivar2(struct load_arg *arg)
+{
+ volatile VALUE s = r_bytes(arg);
+ ID id = rb_intern(RSTRING_PTR(s));
+ VALUE klass;
- id = rb_intern(RSTRING_PTR(s));
+ s = r_bytes(arg);
+ klass = r_entry(path2class(RSTRING_PTR(s)), arg);
+ id = rb_intern_ivar2(id, klass);
st_insert(arg->symbols, arg->symbols->num_entries, id);
return id;
@@ -867,10 +900,19 @@ r_symreal(struct load_arg *arg)
static ID
r_symbol(struct load_arg *arg)
{
- if (r_byte(arg) == TYPE_SYMLINK) {
+ int type;
+
+ switch ((type = r_byte(arg))) {
+ case TYPE_SYMBOL:
+ return r_symreal(arg);
+ case TYPE_SYMBOL2:
+ return r_symivar2(arg);
+ case TYPE_SYMLINK:
return r_symlink(arg);
+ default:
+ rb_raise(rb_eArgError, "dump format error(0x%x)", type);
+ break;
}
- return r_symreal(arg);
}
static const char*
@@ -1274,6 +1316,10 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
v = ID2SYM(r_symreal(arg));
break;
+ case TYPE_SYMBOL2:
+ v = ID2SYM(r_symivar2(arg));
+ break;
+
case TYPE_SYMLINK:
v = ID2SYM(r_symlink(arg));
break;
diff --git a/node.h b/node.h
index ddca63ab21..dec704c99d 100644
--- a/node.h
+++ b/node.h
@@ -48,6 +48,7 @@ enum node_type {
NODE_DASGN_CURR,
NODE_GASGN,
NODE_IASGN,
+ NODE_IASGN2,
NODE_CDECL,
NODE_CVASGN,
NODE_CVDECL,
@@ -70,6 +71,7 @@ enum node_type {
NODE_DVAR,
NODE_GVAR,
NODE_IVAR,
+ NODE_IVAR2,
NODE_CONST,
NODE_CVAR,
NODE_NTH_REF,
@@ -282,6 +284,7 @@ extern NODE *ruby_top_cref;
#define NEW_DASGN(v,val) NEW_NODE(NODE_DASGN,v,val,0)
#define NEW_DASGN_CURR(v,val) NEW_NODE(NODE_DASGN_CURR,v,val,0)
#define NEW_IASGN(v,val) NEW_NODE(NODE_IASGN,v,val,0)
+#define NEW_IASGN2(v,val) NEW_NODE(NODE_IASGN2,0,val,v)
#define NEW_CDECL(v,val,path) NEW_NODE(NODE_CDECL,v,val,path)
#define NEW_CVASGN(v,val) NEW_NODE(NODE_CVASGN,v,val,0)
#define NEW_CVDECL(v,val) NEW_NODE(NODE_CVDECL,v,val,0)
@@ -294,6 +297,7 @@ extern NODE *ruby_top_cref;
#define NEW_LVAR(v) NEW_NODE(NODE_LVAR,v,0,local_cnt(v))
#define NEW_DVAR(v) NEW_NODE(NODE_DVAR,v,0,0)
#define NEW_IVAR(v) NEW_NODE(NODE_IVAR,v,0,0)
+#define NEW_IVAR2(v) NEW_NODE(NODE_IVAR2,0,0,v)
#define NEW_CONST(v) NEW_NODE(NODE_CONST,v,0,0)
#define NEW_CVAR(v) NEW_NODE(NODE_CVAR,v,0,0)
#define NEW_NTH_REF(n) NEW_NODE(NODE_NTH_REF,0,n,local_cnt('~'))
diff --git a/parse.y b/parse.y
index 52d26e8263..4f9310e004 100644
--- a/parse.y
+++ b/parse.y
@@ -36,19 +36,21 @@
#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_JUNK 0x07
-#define ID_INTERNAL ID_JUNK
+#define ID_LOCAL 0x00
+#define ID_INSTANCE 0x01
+#define ID_INSTANCE2 0x02
+#define ID_GLOBAL 0x03
+#define ID_ATTRSET 0x04
+#define ID_CONST 0x05
+#define ID_CLASS 0x06
+#define ID_JUNK 0x07
+#define ID_INTERNAL ID_JUNK
#define is_notop_id(id) ((id)>tLAST_TOKEN)
#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)
+#define is_instance2_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE2)
#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)
@@ -7174,6 +7176,9 @@ gettable_gen(struct parser_params *parser, ID id)
else if (is_instance_id(id)) {
return NEW_IVAR(id);
}
+ else if (is_instance2_id(id)) {
+ return NEW_IVAR2(id);
+ }
else if (is_const_id(id)) {
return NEW_CONST(id);
}
@@ -7227,6 +7232,9 @@ assignable_gen(struct parser_params *parser, ID id, NODE *val)
else if (is_instance_id(id)) {
return NEW_IASGN(id, val);
}
+ else if (is_instance2_id(id)) {
+ return NEW_IASGN2(id, val);
+ }
else if (is_const_id(id)) {
if (in_def || in_single)
yyerror("dynamic constant assignment");
@@ -7361,6 +7369,7 @@ node_assign_gen(struct parser_params *parser, NODE *lhs, NODE *rhs)
switch (nd_type(lhs)) {
case NODE_GASGN:
case NODE_IASGN:
+ case NODE_IASGN2:
case NODE_LASGN:
case NODE_DASGN:
case NODE_DASGN_CURR:
@@ -8408,6 +8417,9 @@ rb_intern2(const char *name, long len)
m++;
id |= ID_CLASS;
}
+ else if (name[1] == '_') {
+ id |= ID_INSTANCE2;
+ }
else {
id |= ID_INSTANCE;
}
@@ -8590,6 +8602,13 @@ rb_is_instance_id(ID id)
}
int
+rb_is_instance2_id(ID id)
+{
+ if (is_instance2_id(id)) return Qtrue;
+ return Qfalse;
+}
+
+int
rb_is_local_id(ID id)
{
if (is_local_id(id)) return Qtrue;
diff --git a/string.c b/string.c
index bf6eb112eb..87f436bcb9 100644
--- a/string.c
+++ b/string.c
@@ -4227,7 +4227,10 @@ rb_str_intern(VALUE s)
volatile VALUE str = s;
ID id;
- if (OBJ_TAINTED(str) && rb_safe_level() >= 1 && !rb_sym_interned_p(str)) {
+ if (rb_sym_interned_p(str)) {
+ return str;
+ }
+ if (OBJ_TAINTED(str) && rb_safe_level() >= 1) {
rb_raise(rb_eSecurityError, "Insecure: can't intern tainted string");
}
id = rb_intern2(RSTRING_PTR(str), RSTRING_LEN(str));
@@ -4688,8 +4691,13 @@ sym_to_i(VALUE sym)
static VALUE
sym_inspect(VALUE sym)
{
- VALUE str;
+ VALUE str, klass = Qundef;
+ ID id = SYM2ID(sym);
+ if (rb_is_instance2_id(id)) {
+ id = rb_dump_ivar2(id, &klass);
+ sym = ID2SYM(id);
+ }
str = rb_str_new(0, RSTRING_LEN(sym)+1);
RSTRING_PTR(str)[0] = ':';
memcpy(RSTRING_PTR(str)+1, RSTRING_PTR(sym), RSTRING_LEN(sym));
@@ -4698,6 +4706,10 @@ sym_inspect(VALUE sym)
str = rb_str_dump(str);
strncpy(RSTRING_PTR(str), ":\"", 2);
}
+ if (klass != Qundef) {
+ rb_str_cat2(str, "/");
+ rb_str_append(str, rb_inspect(klass));
+ }
return str;
}
@@ -4808,6 +4820,44 @@ rb_to_id(VALUE name)
return id;
}
+ID
+rb_intern_ivar2(ID id, VALUE klass)
+{
+ VALUE sym = ID2SYM(id);
+ long len = RSTRING_LEN(sym);
+ char *buf = ALLOCA_N(char, len+sizeof(VALUE)+1);
+ VALUE oid;
+
+ strcpy(buf, RSTRING_PTR(sym));
+ oid = rb_obj_id(klass);
+ memcpy(buf+len+1, (char*)&oid, sizeof(VALUE));
+ id = rb_intern2(buf, len+sizeof(VALUE)+1);
+ sym = ID2SYM(id);
+// STR_SET_LEN(sym, len);
+ return id;
+}
+
+static VALUE
+sym_div(VALUE sym, VALUE klass)
+{
+ ID id = SYM2ID(sym);
+
+ if (!rb_is_instance2_id(id)) {
+ rb_raise(rb_eArgError, "symbol %s should be local instance variable",
+ rb_id2name(id));
+ }
+ switch (TYPE(klass)) {
+ case T_CLASS:
+ case T_MODULE:
+ break;
+ default:
+ rb_check_type(klass, T_CLASS);
+ break;
+ }
+ id = rb_intern_ivar2(id, klass);
+ return ID2SYM(id);
+}
+
/*
* A <code>String</code> object holds and manipulates an arbitrary sequence of
* bytes, typically representing characters. String objects may be created
@@ -4948,6 +4998,7 @@ Init_String(void)
rb_define_singleton_method(rb_cSymbol, "all_symbols", rb_sym_all_symbols, 0); /* in parse.y */
rb_define_singleton_method(rb_cSymbol, "intern", rb_sym_s_intern, 1);
+ rb_define_method(rb_cSymbol, "/", sym_div, 1);
rb_define_method(rb_cSymbol, "==", sym_equal, 1);
rb_define_method(rb_cSymbol, "to_i", sym_to_i, 0);
rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0);
diff --git a/variable.c b/variable.c
index 63f6ed9474..3786419573 100644
--- a/variable.c
+++ b/variable.c
@@ -987,7 +987,7 @@ rb_ivar_defined(VALUE obj, ID id)
static int
ivar_i(ID key, struct global_entry *entry, VALUE ary)
{
- if (rb_is_instance_id(key)) {
+ if (rb_is_instance_id(key) || rb_is_instance2_id(key)) {
rb_ary_push(ary, ID2SYM(key));
}
return ST_CONTINUE;