* vm.c (eval_get_cvar_base): destination for class variable access

is now strictly innermost surrounding class or module.  warned
  if accessed from toplevel.

* variable.c (rb_cvar_get): new class variable look-up scheme:
  1) look up in the class.  2) if the class is singleton attached
  to a class (i.e. metaclass) then start look up in the attached
  class and its ancestors. 3) otherwise, look-up in ancestors of
  the class.

* eval.c (cvar_cbase): destination for class variable access is
  the class/module that holds the method, or cbase outside of
  methods.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11613 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2007-02-02 09:47:55 +00:00
parent e137ee9ac4
commit d99bcbe583
3 changed files with 52 additions and 23 deletions

View file

@ -1570,26 +1570,50 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
mod_av_set(klass, id, val, Qfalse);
}
#define CVAR_LOOKUP(v,r) do {\
if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,id,(v))) {\
return (r);\
}\
if (FL_TEST(klass, FL_SINGLETON) ) {\
VALUE obj = rb_iv_get(klass, "__attached__");\
switch (TYPE(obj)) {\
case T_MODULE:\
case T_CLASS:\
klass = obj;\
break;\
default:\
klass = RCLASS(klass)->super;\
break;\
}\
}\
else {\
klass = RCLASS(klass)->super;\
}\
while (klass) {\
if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,id,(v))) {\
return (r);\
}\
klass = RCLASS(klass)->super;\
}\
} while(0)
VALUE
rb_cvar_get(VALUE klass, ID id)
{
VALUE value;
if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,id,&value)) {
return value;
}
VALUE value, tmp;
tmp = klass;
CVAR_LOOKUP(&value, value);
rb_name_error(id,"uninitialized class variable %s in %s",
rb_id2name(id), rb_class2name(klass));
rb_id2name(id), rb_class2name(tmp));
return Qnil; /* not reached */
}
VALUE
rb_cvar_defined(VALUE klass, ID id)
{
if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl,id,0)) {
return Qtrue;
}
if (!klass) return Qfalse;
CVAR_LOOKUP(0,Qtrue);
return Qfalse;
}