variable.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   variable.c -
00004 
00005   $Author: nagachika $
00006   created at: Tue Apr 19 23:55:15 JST 1994
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00010   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby/ruby.h"
00015 #include "ruby/st.h"
00016 #include "ruby/util.h"
00017 #include "ruby/encoding.h"
00018 #include "node.h"
00019 #include "constant.h"
00020 #include "internal.h"
00021 #include "id.h"
00022 
00023 st_table *rb_global_tbl;
00024 static ID autoload, classpath, tmp_classpath, classid;
00025 
00026 void
00027 Init_var_tables(void)
00028 {
00029     rb_global_tbl = st_init_numtable();
00030     CONST_ID(autoload, "__autoload__");
00031     /* __classpath__: fully qualified class path */
00032     CONST_ID(classpath, "__classpath__");
00033     /* __tmp_classpath__: temporary class path which contains anonymous names */
00034     CONST_ID(tmp_classpath, "__tmp_classpath__");
00035     /* __classid__: name given to class/module under an anonymous namespace */
00036     CONST_ID(classid, "__classid__");
00037 }
00038 
00039 struct fc_result {
00040     ID name, preferred;
00041     VALUE klass;
00042     VALUE path;
00043     VALUE track;
00044     struct fc_result *prev;
00045 };
00046 
00047 static VALUE
00048 fc_path(struct fc_result *fc, ID name)
00049 {
00050     VALUE path, tmp;
00051 
00052     path = rb_id2str(name);
00053     while (fc) {
00054         st_data_t n;
00055         if (fc->track == rb_cObject) break;
00056         if (RCLASS_IV_TBL(fc->track) &&
00057             st_lookup(RCLASS_IV_TBL(fc->track), (st_data_t)classpath, &n)) {
00058             tmp = rb_str_dup((VALUE)n);
00059             rb_str_cat2(tmp, "::");
00060             rb_str_append(tmp, path);
00061             path = tmp;
00062             break;
00063         }
00064         tmp = rb_str_dup(rb_id2str(fc->name));
00065         rb_str_cat2(tmp, "::");
00066         rb_str_append(tmp, path);
00067         path = tmp;
00068         fc = fc->prev;
00069     }
00070     OBJ_FREEZE(path);
00071     return path;
00072 }
00073 
00074 static int
00075 fc_i(st_data_t k, st_data_t v, st_data_t a)
00076 {
00077     ID key = (ID)k;
00078     rb_const_entry_t *ce = (rb_const_entry_t *)v;
00079     struct fc_result *res = (struct fc_result *)a;
00080     VALUE value = ce->value;
00081     if (!rb_is_const_id(key)) return ST_CONTINUE;
00082 
00083     if (value == res->klass && (!res->preferred || key == res->preferred)) {
00084         res->path = fc_path(res, key);
00085         return ST_STOP;
00086     }
00087     if (RB_TYPE_P(value, T_MODULE) || RB_TYPE_P(value, T_CLASS)) {
00088         if (!RCLASS_CONST_TBL(value)) return ST_CONTINUE;
00089         else {
00090             struct fc_result arg;
00091             struct fc_result *list;
00092 
00093             list = res;
00094             while (list) {
00095                 if (list->track == value) return ST_CONTINUE;
00096                 list = list->prev;
00097             }
00098 
00099             arg.name = key;
00100             arg.preferred = res->preferred;
00101             arg.path = 0;
00102             arg.klass = res->klass;
00103             arg.track = value;
00104             arg.prev = res;
00105             st_foreach(RCLASS_CONST_TBL(value), fc_i, (st_data_t)&arg);
00106             if (arg.path) {
00107                 res->path = arg.path;
00108                 return ST_STOP;
00109             }
00110         }
00111     }
00112     return ST_CONTINUE;
00113 }
00114 
00122 static VALUE
00123 find_class_path(VALUE klass, ID preferred)
00124 {
00125     struct fc_result arg;
00126 
00127     arg.preferred = preferred;
00128     arg.name = 0;
00129     arg.path = 0;
00130     arg.klass = klass;
00131     arg.track = rb_cObject;
00132     arg.prev = 0;
00133     if (RCLASS_CONST_TBL(rb_cObject)) {
00134         st_foreach_safe(RCLASS_CONST_TBL(rb_cObject), fc_i, (st_data_t)&arg);
00135     }
00136     if (arg.path) {
00137         st_data_t tmp = tmp_classpath;
00138         if (!RCLASS_IV_TBL(klass)) {
00139             RCLASS_IV_TBL(klass) = st_init_numtable();
00140         }
00141         rb_st_insert_id_and_value(klass, RCLASS_IV_TBL(klass), (st_data_t)classpath, arg.path);
00142 
00143         st_delete(RCLASS_IV_TBL(klass), &tmp, 0);
00144         return arg.path;
00145     }
00146     return Qnil;
00147 }
00148 
00156 static VALUE
00157 classname(VALUE klass, int *permanent)
00158 {
00159     VALUE path = Qnil;
00160     st_data_t n;
00161 
00162     if (!klass) klass = rb_cObject;
00163     *permanent = 1;
00164     if (RCLASS_IV_TBL(klass)) {
00165         if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classpath, &n)) {
00166             ID cid = 0;
00167             if (st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classid, &n)) {
00168                 cid = SYM2ID(n);
00169                 path = find_class_path(klass, cid);
00170             }
00171             if (NIL_P(path)) {
00172                 path = find_class_path(klass, (ID)0);
00173             }
00174             if (NIL_P(path)) {
00175                 if (!cid) {
00176                     return Qnil;
00177                 }
00178                 if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)tmp_classpath, &n)) {
00179                     path = rb_id2str(cid);
00180                     return path;
00181                 }
00182                 *permanent = 0;
00183                 path = (VALUE)n;
00184                 return path;
00185             }
00186         }
00187         else {
00188             path = (VALUE)n;
00189         }
00190         if (!RB_TYPE_P(path, T_STRING)) {
00191             rb_bug("class path is not set properly");
00192         }
00193         return path;
00194     }
00195     return find_class_path(klass, (ID)0);
00196 }
00197 
00198 /*
00199  *  call-seq:
00200  *     mod.name    -> string
00201  *
00202  *  Returns the name of the module <i>mod</i>.  Returns nil for anonymous modules.
00203  */
00204 
00205 VALUE
00206 rb_mod_name(VALUE mod)
00207 {
00208     int permanent;
00209     VALUE path = classname(mod, &permanent);
00210 
00211     if (!NIL_P(path)) return rb_str_dup(path);
00212     return path;
00213 }
00214 
00215 typedef VALUE (*path_cache_func)(VALUE obj, ID id, VALUE val);
00216 
00217 static VALUE
00218 rb_tmp_class_path(VALUE klass, int *permanent, path_cache_func cache_path)
00219 {
00220     VALUE path = classname(klass, permanent);
00221     st_data_t n = (st_data_t)path;
00222 
00223     if (!NIL_P(path)) {
00224         return path;
00225     }
00226     if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),
00227                                           (st_data_t)tmp_classpath, &n)) {
00228         *permanent = 0;
00229         return (VALUE)n;
00230     }
00231     else {
00232         const char *s = "Class";
00233 
00234         if (RB_TYPE_P(klass, T_MODULE)) {
00235             if (rb_obj_class(klass) == rb_cModule) {
00236                 s = "Module";
00237             }
00238             else {
00239                 int perm;
00240                 VALUE path;
00241 
00242                 path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, cache_path);
00243                 s = RSTRING_PTR(path);
00244             }
00245         }
00246         path = rb_sprintf("#<%s:%p>", s, (void*)klass);
00247         OBJ_FREEZE(path);
00248 
00249         cache_path(klass, tmp_classpath, path);
00250         *permanent = 0;
00251 
00252         return path;
00253     }
00254 }
00255 
00256 VALUE
00257 rb_class_path(VALUE klass)
00258 {
00259     int permanent;
00260     VALUE path = rb_tmp_class_path(klass, &permanent, rb_ivar_set);
00261     if (!NIL_P(path)) path = rb_str_dup(path);
00262     return path;
00263 }
00264 
00265 static VALUE
00266 null_cache(VALUE obj, ID id, VALUE val)
00267 {
00268     return Qnil;
00269 }
00270 
00271 VALUE
00272 rb_class_path_no_cache(VALUE klass)
00273 {
00274     int permanent;
00275     VALUE path = rb_tmp_class_path(klass, &permanent, null_cache);
00276     if (!NIL_P(path)) path = rb_str_dup(path);
00277     return path;
00278 }
00279 
00280 VALUE
00281 rb_class_path_cached(VALUE klass)
00282 {
00283     st_table *ivtbl = RCLASS_IV_TBL(klass);
00284     st_data_t n;
00285 
00286     if (!ivtbl) return Qnil;
00287     if (st_lookup(ivtbl, (st_data_t)classpath, &n)) return (VALUE)n;
00288     if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
00289     return Qnil;
00290 }
00291 
00292 void
00293 rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
00294 {
00295     VALUE str;
00296     ID pathid = classpath;
00297 
00298     if (under == rb_cObject) {
00299         str = rb_str_new_frozen(name);
00300     }
00301     else {
00302         int permanent;
00303         str = rb_str_dup(rb_tmp_class_path(under, &permanent, rb_ivar_set));
00304         rb_str_cat2(str, "::");
00305         rb_str_append(str, name);
00306         OBJ_FREEZE(str);
00307         if (!permanent) {
00308             pathid = tmp_classpath;
00309             rb_ivar_set(klass, classid, ID2SYM(rb_intern_str(name)));
00310         }
00311     }
00312     rb_ivar_set(klass, pathid, str);
00313 }
00314 
00315 void
00316 rb_set_class_path(VALUE klass, VALUE under, const char *name)
00317 {
00318     VALUE str;
00319     ID pathid = classpath;
00320 
00321     if (under == rb_cObject) {
00322         str = rb_str_new2(name);
00323     }
00324     else {
00325         int permanent;
00326         str = rb_str_dup(rb_tmp_class_path(under, &permanent, rb_ivar_set));
00327         rb_str_cat2(str, "::");
00328         rb_str_cat2(str, name);
00329         if (!permanent) {
00330             pathid = tmp_classpath;
00331             rb_ivar_set(klass, classid, ID2SYM(rb_intern(name)));
00332         }
00333     }
00334     OBJ_FREEZE(str);
00335     rb_ivar_set(klass, pathid, str);
00336 }
00337 
00338 VALUE
00339 rb_path_to_class(VALUE pathname)
00340 {
00341     rb_encoding *enc = rb_enc_get(pathname);
00342     const char *pbeg, *p, *path = RSTRING_PTR(pathname);
00343     ID id;
00344     VALUE c = rb_cObject;
00345 
00346     if (!rb_enc_asciicompat(enc)) {
00347         rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
00348     }
00349     pbeg = p = path;
00350     if (path[0] == '#') {
00351         rb_raise(rb_eArgError, "can't retrieve anonymous class %"PRIsVALUE,
00352                  QUOTE(pathname));
00353     }
00354     while (*p) {
00355         while (*p && *p != ':') p++;
00356         id = rb_check_id_cstr(pbeg, p-pbeg, enc);
00357         if (p[0] == ':') {
00358             if (p[1] != ':') goto undefined_class;
00359             p += 2;
00360             pbeg = p;
00361         }
00362         if (!id || !rb_const_defined_at(c, id)) {
00363           undefined_class:
00364             rb_raise(rb_eArgError, "undefined class/module %.*"PRIsVALUE,
00365                      (int)(p-path), pathname);
00366         }
00367         c = rb_const_get_at(c, id);
00368         if (!RB_TYPE_P(c, T_MODULE) && !RB_TYPE_P(c, T_CLASS)) {
00369             rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
00370                      pathname);
00371         }
00372     }
00373     RB_GC_GUARD(pathname);
00374 
00375     return c;
00376 }
00377 
00378 VALUE
00379 rb_path2class(const char *path)
00380 {
00381     return rb_path_to_class(rb_str_new_cstr(path));
00382 }
00383 
00384 void
00385 rb_name_class(VALUE klass, ID id)
00386 {
00387     rb_ivar_set(klass, classid, ID2SYM(id));
00388 }
00389 
00390 VALUE
00391 rb_class_name(VALUE klass)
00392 {
00393     return rb_class_path(rb_class_real(klass));
00394 }
00395 
00396 const char *
00397 rb_class2name(VALUE klass)
00398 {
00399     int permanent;
00400     VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, rb_ivar_set);
00401     if (NIL_P(path)) return NULL;
00402     return RSTRING_PTR(path);
00403 }
00404 
00405 const char *
00406 rb_obj_classname(VALUE obj)
00407 {
00408     return rb_class2name(CLASS_OF(obj));
00409 }
00410 
00411 #define global_variable rb_global_variable
00412 #define global_entry rb_global_entry
00413 
00414 #define gvar_getter_t rb_gvar_getter_t
00415 #define gvar_setter_t rb_gvar_setter_t
00416 #define gvar_marker_t rb_gvar_marker_t
00417 
00418 struct trace_var {
00419     int removed;
00420     void (*func)(VALUE arg, VALUE val);
00421     VALUE data;
00422     struct trace_var *next;
00423 };
00424 
00425 struct global_variable {
00426     int   counter;
00427     void *data;
00428     gvar_getter_t *getter;
00429     gvar_setter_t *setter;
00430     gvar_marker_t *marker;
00431     int block_trace;
00432     struct trace_var *trace;
00433 };
00434 
00435 #define undef_getter    rb_gvar_undef_getter
00436 #define undef_setter    rb_gvar_undef_setter
00437 #define undef_marker    rb_gvar_undef_marker
00438 
00439 #define val_getter      rb_gvar_val_getter
00440 #define val_setter      rb_gvar_val_setter
00441 #define val_marker      rb_gvar_val_marker
00442 
00443 #define var_getter      rb_gvar_var_getter
00444 #define var_setter      rb_gvar_var_setter
00445 #define var_marker      rb_gvar_var_marker
00446 
00447 #define readonly_setter rb_gvar_readonly_setter
00448 
00449 struct global_entry*
00450 rb_global_entry(ID id)
00451 {
00452     struct global_entry *entry;
00453     st_data_t data;
00454 
00455     if (!st_lookup(rb_global_tbl, (st_data_t)id, &data)) {
00456         struct global_variable *var;
00457         entry = ALLOC(struct global_entry);
00458         var = ALLOC(struct global_variable);
00459         entry->id = id;
00460         entry->var = var;
00461         var->counter = 1;
00462         var->data = 0;
00463         var->getter = undef_getter;
00464         var->setter = undef_setter;
00465         var->marker = undef_marker;
00466 
00467         var->block_trace = 0;
00468         var->trace = 0;
00469         st_add_direct(rb_global_tbl, id, (st_data_t)entry);
00470     }
00471     else {
00472         entry = (struct global_entry *)data;
00473     }
00474     return entry;
00475 }
00476 
00477 VALUE
00478 undef_getter(ID id, void *data, struct global_variable *var)
00479 {
00480     rb_warning("global variable `%"PRIsVALUE"' not initialized", QUOTE_ID(id));
00481 
00482     return Qnil;
00483 }
00484 
00485 void
00486 undef_setter(VALUE val, ID id, void *data, struct global_variable *var)
00487 {
00488     var->getter = val_getter;
00489     var->setter = val_setter;
00490     var->marker = val_marker;
00491 
00492     var->data = (void*)val;
00493 }
00494 
00495 void
00496 undef_marker(VALUE *var)
00497 {
00498 }
00499 
00500 VALUE
00501 val_getter(ID id, void *data, struct global_variable *var)
00502 {
00503     return (VALUE)data;
00504 }
00505 
00506 void
00507 val_setter(VALUE val, ID id, void *data, struct global_variable *var)
00508 {
00509     var->data = (void*)val;
00510 }
00511 
00512 void
00513 val_marker(VALUE *var)
00514 {
00515     VALUE data = (VALUE)var;
00516     if (data) rb_gc_mark_maybe(data);
00517 }
00518 
00519 VALUE
00520 var_getter(ID id, void *data, struct global_variable *gvar)
00521 {
00522     VALUE *var = data;
00523     if (!var) return Qnil;
00524     return *var;
00525 }
00526 
00527 void
00528 var_setter(VALUE val, ID id, void *data, struct global_variable *gvar)
00529 {
00530     *(VALUE *)data = val;
00531 }
00532 
00533 void
00534 var_marker(VALUE *var)
00535 {
00536     if (var) rb_gc_mark_maybe(*var);
00537 }
00538 
00539 void
00540 readonly_setter(VALUE val, ID id, void *data, struct global_variable *gvar)
00541 {
00542     rb_name_error(id, "%"PRIsVALUE" is a read-only variable", QUOTE_ID(id));
00543 }
00544 
00545 static int
00546 mark_global_entry(st_data_t k, st_data_t v, st_data_t a)
00547 {
00548     struct global_entry *entry = (struct global_entry *)v;
00549     struct trace_var *trace;
00550     struct global_variable *var = entry->var;
00551 
00552     (*var->marker)(var->data);
00553     trace = var->trace;
00554     while (trace) {
00555         if (trace->data) rb_gc_mark_maybe(trace->data);
00556         trace = trace->next;
00557     }
00558     return ST_CONTINUE;
00559 }
00560 
00561 void
00562 rb_gc_mark_global_tbl(void)
00563 {
00564     if (rb_global_tbl)
00565         st_foreach_safe(rb_global_tbl, mark_global_entry, 0);
00566 }
00567 
00568 static ID
00569 global_id(const char *name)
00570 {
00571     ID id;
00572 
00573     if (name[0] == '$') id = rb_intern(name);
00574     else {
00575         size_t len = strlen(name);
00576         char *buf = ALLOCA_N(char, len+1);
00577         buf[0] = '$';
00578         memcpy(buf+1, name, len);
00579         id = rb_intern2(buf, len+1);
00580     }
00581     return id;
00582 }
00583 
00584 void
00585 rb_define_hooked_variable(
00586     const char *name,
00587     VALUE *var,
00588     VALUE (*getter)(ANYARGS),
00589     void  (*setter)(ANYARGS))
00590 {
00591     volatile VALUE tmp = var ? *var : Qnil;
00592     ID id = global_id(name);
00593     struct global_variable *gvar = rb_global_entry(id)->var;
00594 
00595     gvar->data = (void*)var;
00596     gvar->getter = getter?(gvar_getter_t *)getter:var_getter;
00597     gvar->setter = setter?(gvar_setter_t *)setter:var_setter;
00598     gvar->marker = var_marker;
00599 
00600     RB_GC_GUARD(tmp);
00601 }
00602 
00603 void
00604 rb_define_variable(const char *name, VALUE *var)
00605 {
00606     rb_define_hooked_variable(name, var, 0, 0);
00607 }
00608 
00609 void
00610 rb_define_readonly_variable(const char *name, VALUE *var)
00611 {
00612     rb_define_hooked_variable(name, var, 0, readonly_setter);
00613 }
00614 
00615 void
00616 rb_define_virtual_variable(
00617     const char *name,
00618     VALUE (*getter)(ANYARGS),
00619     void  (*setter)(ANYARGS))
00620 {
00621     if (!getter) getter = val_getter;
00622     if (!setter) setter = readonly_setter;
00623     rb_define_hooked_variable(name, 0, getter, setter);
00624 }
00625 
00626 static void
00627 rb_trace_eval(VALUE cmd, VALUE val)
00628 {
00629     rb_eval_cmd(cmd, rb_ary_new3(1, val), 0);
00630 }
00631 
00632 /*
00633  *  call-seq:
00634  *     trace_var(symbol, cmd )             -> nil
00635  *     trace_var(symbol) {|val| block }    -> nil
00636  *
00637  *  Controls tracing of assignments to global variables. The parameter
00638  *  +symbol_ identifies the variable (as either a string name or a
00639  *  symbol identifier). _cmd_ (which may be a string or a
00640  *  +Proc+ object) or block is executed whenever the variable
00641  *  is assigned. The block or +Proc+ object receives the
00642  *  variable's new value as a parameter. Also see
00643  *  <code>Kernel::untrace_var</code>.
00644  *
00645  *     trace_var :$_, proc {|v| puts "$_ is now '#{v}'" }
00646  *     $_ = "hello"
00647  *     $_ = ' there'
00648  *
00649  *  <em>produces:</em>
00650  *
00651  *     $_ is now 'hello'
00652  *     $_ is now ' there'
00653  */
00654 
00655 VALUE
00656 rb_f_trace_var(int argc, VALUE *argv)
00657 {
00658     VALUE var, cmd;
00659     struct global_entry *entry;
00660     struct trace_var *trace;
00661 
00662     if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) {
00663         cmd = rb_block_proc();
00664     }
00665     if (NIL_P(cmd)) {
00666         return rb_f_untrace_var(argc, argv);
00667     }
00668     entry = rb_global_entry(rb_to_id(var));
00669     if (OBJ_TAINTED(cmd)) {
00670         rb_raise(rb_eSecurityError, "Insecure: tainted variable trace");
00671     }
00672     trace = ALLOC(struct trace_var);
00673     trace->next = entry->var->trace;
00674     trace->func = rb_trace_eval;
00675     trace->data = cmd;
00676     trace->removed = 0;
00677     entry->var->trace = trace;
00678 
00679     return Qnil;
00680 }
00681 
00682 static void
00683 remove_trace(struct global_variable *var)
00684 {
00685     struct trace_var *trace = var->trace;
00686     struct trace_var t;
00687     struct trace_var *next;
00688 
00689     t.next = trace;
00690     trace = &t;
00691     while (trace->next) {
00692         next = trace->next;
00693         if (next->removed) {
00694             trace->next = next->next;
00695             xfree(next);
00696         }
00697         else {
00698             trace = next;
00699         }
00700     }
00701     var->trace = t.next;
00702 }
00703 
00704 /*
00705  *  call-seq:
00706  *     untrace_var(symbol [, cmd] )   -> array or nil
00707  *
00708  *  Removes tracing for the specified command on the given global
00709  *  variable and returns +nil+. If no command is specified,
00710  *  removes all tracing for that variable and returns an array
00711  *  containing the commands actually removed.
00712  */
00713 
00714 VALUE
00715 rb_f_untrace_var(int argc, VALUE *argv)
00716 {
00717     VALUE var, cmd;
00718     ID id;
00719     struct global_entry *entry;
00720     struct trace_var *trace;
00721     st_data_t data;
00722 
00723     rb_scan_args(argc, argv, "11", &var, &cmd);
00724     id = rb_check_id(&var);
00725     if (!id) {
00726         rb_name_error_str(var, "undefined global variable %"PRIsVALUE"", QUOTE(var));
00727     }
00728     if (!st_lookup(rb_global_tbl, (st_data_t)id, &data)) {
00729         rb_name_error(id, "undefined global variable %"PRIsVALUE"", QUOTE_ID(id));
00730     }
00731 
00732     trace = (entry = (struct global_entry *)data)->var->trace;
00733     if (NIL_P(cmd)) {
00734         VALUE ary = rb_ary_new();
00735 
00736         while (trace) {
00737             struct trace_var *next = trace->next;
00738             rb_ary_push(ary, (VALUE)trace->data);
00739             trace->removed = 1;
00740             trace = next;
00741         }
00742 
00743         if (!entry->var->block_trace) remove_trace(entry->var);
00744         return ary;
00745     }
00746     else {
00747         while (trace) {
00748             if (trace->data == cmd) {
00749                 trace->removed = 1;
00750                 if (!entry->var->block_trace) remove_trace(entry->var);
00751                 return rb_ary_new3(1, cmd);
00752             }
00753             trace = trace->next;
00754         }
00755     }
00756     return Qnil;
00757 }
00758 
00759 VALUE
00760 rb_gvar_get(struct global_entry *entry)
00761 {
00762     struct global_variable *var = entry->var;
00763     return (*var->getter)(entry->id, var->data, var);
00764 }
00765 
00766 struct trace_data {
00767     struct trace_var *trace;
00768     VALUE val;
00769 };
00770 
00771 static VALUE
00772 trace_ev(struct trace_data *data)
00773 {
00774     struct trace_var *trace = data->trace;
00775 
00776     while (trace) {
00777         (*trace->func)(trace->data, data->val);
00778         trace = trace->next;
00779     }
00780 
00781     return Qnil;
00782 }
00783 
00784 static VALUE
00785 trace_en(struct global_variable *var)
00786 {
00787     var->block_trace = 0;
00788     remove_trace(var);
00789     return Qnil;                /* not reached */
00790 }
00791 
00792 VALUE
00793 rb_gvar_set(struct global_entry *entry, VALUE val)
00794 {
00795     struct trace_data trace;
00796     struct global_variable *var = entry->var;
00797 
00798     (*var->setter)(val, entry->id, var->data, var);
00799 
00800     if (var->trace && !var->block_trace) {
00801         var->block_trace = 1;
00802         trace.trace = var->trace;
00803         trace.val = val;
00804         rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
00805     }
00806     return val;
00807 }
00808 
00809 VALUE
00810 rb_gv_set(const char *name, VALUE val)
00811 {
00812     struct global_entry *entry;
00813 
00814     entry = rb_global_entry(global_id(name));
00815     return rb_gvar_set(entry, val);
00816 }
00817 
00818 VALUE
00819 rb_gv_get(const char *name)
00820 {
00821     struct global_entry *entry;
00822 
00823     entry = rb_global_entry(global_id(name));
00824     return rb_gvar_get(entry);
00825 }
00826 
00827 VALUE
00828 rb_gvar_defined(struct global_entry *entry)
00829 {
00830     if (entry->var->getter == undef_getter) return Qfalse;
00831     return Qtrue;
00832 }
00833 
00834 static int
00835 gvar_i(st_data_t k, st_data_t v, st_data_t a)
00836 {
00837     ID key = (ID)k;
00838     VALUE ary = (VALUE)a;
00839     rb_ary_push(ary, ID2SYM(key));
00840     return ST_CONTINUE;
00841 }
00842 
00843 /*
00844  *  call-seq:
00845  *     global_variables    -> array
00846  *
00847  *  Returns an array of the names of global variables.
00848  *
00849  *     global_variables.grep /std/   #=> [:$stdin, :$stdout, :$stderr]
00850  */
00851 
00852 VALUE
00853 rb_f_global_variables(void)
00854 {
00855     VALUE ary = rb_ary_new();
00856     char buf[2];
00857     int i;
00858 
00859     st_foreach_safe(rb_global_tbl, gvar_i, ary);
00860     buf[0] = '$';
00861     for (i = 1; i <= 9; ++i) {
00862         buf[1] = (char)(i + '0');
00863         rb_ary_push(ary, ID2SYM(rb_intern2(buf, 2)));
00864     }
00865     return ary;
00866 }
00867 
00868 void
00869 rb_alias_variable(ID name1, ID name2)
00870 {
00871     struct global_entry *entry1, *entry2;
00872     st_data_t data1;
00873 
00874     entry2 = rb_global_entry(name2);
00875     if (!st_lookup(rb_global_tbl, (st_data_t)name1, &data1)) {
00876         entry1 = ALLOC(struct global_entry);
00877         entry1->id = name1;
00878         st_add_direct(rb_global_tbl, name1, (st_data_t)entry1);
00879     }
00880     else if ((entry1 = (struct global_entry *)data1)->var != entry2->var) {
00881         struct global_variable *var = entry1->var;
00882         if (var->block_trace) {
00883             rb_raise(rb_eRuntimeError, "can't alias in tracer");
00884         }
00885         var->counter--;
00886         if (var->counter == 0) {
00887             struct trace_var *trace = var->trace;
00888             while (trace) {
00889                 struct trace_var *next = trace->next;
00890                 xfree(trace);
00891                 trace = next;
00892             }
00893             xfree(var);
00894         }
00895     }
00896     else {
00897         return;
00898     }
00899     entry2->var->counter++;
00900     entry1->var = entry2->var;
00901 }
00902 
00903 static int special_generic_ivar = 0;
00904 static st_table *generic_iv_tbl;
00905 
00906 st_table*
00907 rb_generic_ivar_table(VALUE obj)
00908 {
00909     st_data_t tbl;
00910 
00911     if (!FL_TEST(obj, FL_EXIVAR)) return 0;
00912     if (!generic_iv_tbl) return 0;
00913     if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) return 0;
00914     return (st_table *)tbl;
00915 }
00916 
00917 static VALUE
00918 generic_ivar_get(VALUE obj, ID id, VALUE undef)
00919 {
00920     st_data_t tbl, val;
00921 
00922     if (generic_iv_tbl) {
00923         if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
00924             if (st_lookup((st_table *)tbl, (st_data_t)id, &val)) {
00925                 return (VALUE)val;
00926             }
00927         }
00928     }
00929     return undef;
00930 }
00931 
00932 static void
00933 generic_ivar_set(VALUE obj, ID id, VALUE val)
00934 {
00935     st_table *tbl;
00936     st_data_t data;
00937 
00938     if (rb_special_const_p(obj)) {
00939         if (rb_obj_frozen_p(obj)) rb_error_frozen("object");
00940         special_generic_ivar = 1;
00941     }
00942     if (!generic_iv_tbl) {
00943         generic_iv_tbl = st_init_numtable();
00944     }
00945     if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
00946         FL_SET(obj, FL_EXIVAR);
00947         tbl = st_init_numtable();
00948         st_add_direct(generic_iv_tbl, (st_data_t)obj, (st_data_t)tbl);
00949         st_add_direct(tbl, (st_data_t)id, (st_data_t)val);
00950         if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
00951         return;
00952     }
00953     st_insert((st_table *)data, (st_data_t)id, (st_data_t)val);
00954     if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, data, val);
00955 }
00956 
00957 static VALUE
00958 generic_ivar_defined(VALUE obj, ID id)
00959 {
00960     st_table *tbl;
00961     st_data_t data;
00962 
00963     if (!generic_iv_tbl) return Qfalse;
00964     if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return Qfalse;
00965     tbl = (st_table *)data;
00966     if (st_lookup(tbl, (st_data_t)id, &data)) {
00967         return Qtrue;
00968     }
00969     return Qfalse;
00970 }
00971 
00972 static int
00973 generic_ivar_remove(VALUE obj, ID id, st_data_t *valp)
00974 {
00975     st_table *tbl;
00976     st_data_t data, key = (st_data_t)id;
00977     int status;
00978 
00979     if (!generic_iv_tbl) return 0;
00980     if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return 0;
00981     tbl = (st_table *)data;
00982     status = st_delete(tbl, &key, valp);
00983     if (tbl->num_entries == 0) {
00984         key = (st_data_t)obj;
00985         st_delete(generic_iv_tbl, &key, &data);
00986         st_free_table((st_table *)data);
00987     }
00988     return status;
00989 }
00990 
00991 void
00992 rb_mark_generic_ivar(VALUE obj)
00993 {
00994     st_data_t tbl;
00995 
00996     if (!generic_iv_tbl) return;
00997     if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
00998         rb_mark_tbl((st_table *)tbl);
00999     }
01000 }
01001 
01002 static int
01003 givar_mark_i(st_data_t k, st_data_t v, st_data_t a)
01004 {
01005     VALUE value = (VALUE)v;
01006     rb_gc_mark(value);
01007     return ST_CONTINUE;
01008 }
01009 
01010 static int
01011 givar_i(st_data_t k, st_data_t v, st_data_t a)
01012 {
01013     VALUE obj = (VALUE)k;
01014     st_table *tbl = (st_table *)v;
01015     if (rb_special_const_p(obj)) {
01016         st_foreach_safe(tbl, givar_mark_i, 0);
01017     }
01018     return ST_CONTINUE;
01019 }
01020 
01021 void
01022 rb_mark_generic_ivar_tbl(void)
01023 {
01024     if (!generic_iv_tbl) return;
01025     if (special_generic_ivar == 0) return;
01026     st_foreach_safe(generic_iv_tbl, givar_i, 0);
01027 }
01028 
01029 void
01030 rb_free_generic_ivar(VALUE obj)
01031 {
01032     st_data_t key = (st_data_t)obj, tbl;
01033 
01034     if (!generic_iv_tbl) return;
01035     if (st_delete(generic_iv_tbl, &key, &tbl))
01036         st_free_table((st_table *)tbl);
01037 }
01038 
01039 RUBY_FUNC_EXPORTED size_t
01040 rb_generic_ivar_memsize(VALUE obj)
01041 {
01042     st_data_t tbl;
01043     if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl))
01044         return st_memsize((st_table *)tbl);
01045     return 0;
01046 }
01047 
01048 void
01049 rb_copy_generic_ivar(VALUE clone, VALUE obj)
01050 {
01051     st_data_t data;
01052 
01053     if (!generic_iv_tbl) return;
01054     if (!FL_TEST(obj, FL_EXIVAR)) {
01055       clear:
01056         if (FL_TEST(clone, FL_EXIVAR)) {
01057             rb_free_generic_ivar(clone);
01058             FL_UNSET(clone, FL_EXIVAR);
01059         }
01060         return;
01061     }
01062     if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
01063         st_table *tbl = (st_table *)data;
01064 
01065         if (tbl->num_entries == 0)
01066             goto clear;
01067 
01068         if (st_lookup(generic_iv_tbl, (st_data_t)clone, &data)) {
01069             st_free_table((st_table *)data);
01070             st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
01071         }
01072         else {
01073             st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
01074             FL_SET(clone, FL_EXIVAR);
01075         }
01076     }
01077 }
01078 
01079 static VALUE
01080 rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
01081 {
01082     VALUE val, *ptr;
01083     struct st_table *iv_index_tbl;
01084     long len;
01085     st_data_t index;
01086 
01087     if (SPECIAL_CONST_P(obj)) goto generic;
01088     switch (BUILTIN_TYPE(obj)) {
01089       case T_OBJECT:
01090         len = ROBJECT_NUMIV(obj);
01091         ptr = ROBJECT_IVPTR(obj);
01092         iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01093         if (!iv_index_tbl) break;
01094         if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01095         if (len <= (long)index) break;
01096         val = ptr[index];
01097         if (val != Qundef)
01098             return val;
01099         break;
01100       case T_CLASS:
01101       case T_MODULE:
01102         if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, &index))
01103             return (VALUE)index;
01104         break;
01105       default:
01106       generic:
01107         if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01108             return generic_ivar_get(obj, id, undef);
01109         break;
01110     }
01111     return undef;
01112 }
01113 
01114 VALUE
01115 rb_ivar_get(VALUE obj, ID id)
01116 {
01117     VALUE iv = rb_ivar_lookup(obj, id, Qundef);
01118 
01119     if (iv == Qundef) {
01120         rb_warning("instance variable %"PRIsVALUE" not initialized", QUOTE_ID(id));
01121         iv = Qnil;
01122     }
01123     return iv;
01124 }
01125 
01126 VALUE
01127 rb_attr_get(VALUE obj, ID id)
01128 {
01129     return rb_ivar_lookup(obj, id, Qnil);
01130 }
01131 
01132 VALUE
01133 rb_ivar_set(VALUE obj, ID id, VALUE val)
01134 {
01135     struct st_table *iv_index_tbl;
01136     st_data_t index;
01137     long i, len;
01138     int ivar_extended;
01139 
01140     rb_check_frozen(obj);
01141     if (SPECIAL_CONST_P(obj)) goto generic;
01142     switch (BUILTIN_TYPE(obj)) {
01143       case T_OBJECT:
01144         iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01145         if (!iv_index_tbl) {
01146             VALUE klass = rb_obj_class(obj);
01147             iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
01148             if (!iv_index_tbl) {
01149                 iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
01150             }
01151         }
01152         ivar_extended = 0;
01153         if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
01154             index = iv_index_tbl->num_entries;
01155             st_add_direct(iv_index_tbl, (st_data_t)id, index);
01156             ivar_extended = 1;
01157         }
01158         len = ROBJECT_NUMIV(obj);
01159         if (len <= (long)index) {
01160             VALUE *ptr = ROBJECT_IVPTR(obj);
01161             if (index < ROBJECT_EMBED_LEN_MAX) {
01162                 RBASIC(obj)->flags |= ROBJECT_EMBED;
01163                 ptr = ROBJECT(obj)->as.ary;
01164                 for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
01165                     ptr[i] = Qundef;
01166                 }
01167             }
01168             else {
01169                 VALUE *newptr;
01170                 long newsize = (index+1) + (index+1)/4; /* (index+1)*1.25 */
01171                 if (!ivar_extended &&
01172                     iv_index_tbl->num_entries < (st_index_t)newsize) {
01173                     newsize = iv_index_tbl->num_entries;
01174                 }
01175                 if (RBASIC(obj)->flags & ROBJECT_EMBED) {
01176                     newptr = ALLOC_N(VALUE, newsize);
01177                     MEMCPY(newptr, ptr, VALUE, len);
01178                     RBASIC(obj)->flags &= ~ROBJECT_EMBED;
01179                     ROBJECT(obj)->as.heap.ivptr = newptr;
01180                 }
01181                 else {
01182                     REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
01183                     newptr = ROBJECT(obj)->as.heap.ivptr;
01184                 }
01185                 for (; len < newsize; len++)
01186                     newptr[len] = Qundef;
01187                 ROBJECT(obj)->as.heap.numiv = newsize;
01188                 ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
01189             }
01190         }
01191         RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], val);
01192         break;
01193       case T_CLASS:
01194       case T_MODULE:
01195         if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
01196         rb_st_insert_id_and_value(obj, RCLASS_IV_TBL(obj), (st_data_t)id, val);
01197         break;
01198       default:
01199       generic:
01200         generic_ivar_set(obj, id, val);
01201         break;
01202     }
01203     return val;
01204 }
01205 
01206 VALUE
01207 rb_ivar_defined(VALUE obj, ID id)
01208 {
01209     VALUE val;
01210     struct st_table *iv_index_tbl;
01211     st_data_t index;
01212     if (SPECIAL_CONST_P(obj)) goto generic;
01213     switch (BUILTIN_TYPE(obj)) {
01214       case T_OBJECT:
01215         iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01216         if (!iv_index_tbl) break;
01217         if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01218         if (ROBJECT_NUMIV(obj) <= (long)index) break;
01219         val = ROBJECT_IVPTR(obj)[index];
01220         if (val != Qundef)
01221             return Qtrue;
01222         break;
01223       case T_CLASS:
01224       case T_MODULE:
01225         if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, 0))
01226             return Qtrue;
01227         break;
01228       default:
01229       generic:
01230         if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
01231             return generic_ivar_defined(obj, id);
01232         break;
01233     }
01234     return Qfalse;
01235 }
01236 
01237 struct obj_ivar_tag {
01238     VALUE obj;
01239     int (*func)(ID key, VALUE val, st_data_t arg);
01240     st_data_t arg;
01241 };
01242 
01243 static int
01244 obj_ivar_i(st_data_t key, st_data_t index, st_data_t arg)
01245 {
01246     struct obj_ivar_tag *data = (struct obj_ivar_tag *)arg;
01247     if ((long)index < ROBJECT_NUMIV(data->obj)) {
01248         VALUE val = ROBJECT_IVPTR(data->obj)[(long)index];
01249         if (val != Qundef) {
01250             return (data->func)((ID)key, val, data->arg);
01251         }
01252     }
01253     return ST_CONTINUE;
01254 }
01255 
01256 static void
01257 obj_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01258 {
01259     st_table *tbl;
01260     struct obj_ivar_tag data;
01261 
01262     tbl = ROBJECT_IV_INDEX_TBL(obj);
01263     if (!tbl)
01264         return;
01265 
01266     data.obj = obj;
01267     data.func = (int (*)(ID key, VALUE val, st_data_t arg))func;
01268     data.arg = arg;
01269 
01270     st_foreach_safe(tbl, obj_ivar_i, (st_data_t)&data);
01271 }
01272 
01273 void
01274 rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
01275 {
01276     if (SPECIAL_CONST_P(obj)) goto generic;
01277     switch (BUILTIN_TYPE(obj)) {
01278       case T_OBJECT:
01279         obj_ivar_each(obj, func, arg);
01280         break;
01281       case T_CLASS:
01282       case T_MODULE:
01283         if (RCLASS_IV_TBL(obj)) {
01284             st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
01285         }
01286         break;
01287       default:
01288       generic:
01289         if (!generic_iv_tbl) break;
01290         if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01291             st_data_t tbl;
01292 
01293             if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
01294                 st_foreach_safe((st_table *)tbl, func, arg);
01295             }
01296         }
01297         break;
01298     }
01299 }
01300 
01301 st_index_t
01302 rb_ivar_count(VALUE obj)
01303 {
01304     st_table *tbl;
01305     if (SPECIAL_CONST_P(obj)) goto generic;
01306     switch (BUILTIN_TYPE(obj)) {
01307       case T_OBJECT:
01308         if ((tbl = ROBJECT_IV_INDEX_TBL(obj)) != 0) {
01309             st_index_t i, count, num = tbl->num_entries;
01310             const VALUE *const ivptr = ROBJECT_IVPTR(obj);
01311             for (i = count = 0; i < num; ++i) {
01312                 if (ivptr[i] != Qundef) {
01313                     count++;
01314                 }
01315             }
01316             return count;
01317         }
01318         break;
01319       case T_CLASS:
01320       case T_MODULE:
01321         if ((tbl = RCLASS_IV_TBL(obj)) != 0) {
01322             return tbl->num_entries;
01323         }
01324         break;
01325       default:
01326       generic:
01327         if (!generic_iv_tbl) break;
01328         if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01329             st_data_t data;
01330 
01331             if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data) &&
01332                 (tbl = (st_table *)data) != 0) {
01333                 return tbl->num_entries;
01334             }
01335         }
01336         break;
01337     }
01338     return 0;
01339 }
01340 
01341 static int
01342 ivar_i(st_data_t k, st_data_t v, st_data_t a)
01343 {
01344     ID key = (ID)k;
01345     VALUE ary = (VALUE)a;
01346 
01347     if (rb_is_instance_id(key)) {
01348         rb_ary_push(ary, ID2SYM(key));
01349     }
01350     return ST_CONTINUE;
01351 }
01352 
01353 /*
01354  *  call-seq:
01355  *     obj.instance_variables    -> array
01356  *
01357  *  Returns an array of instance variable names for the receiver. Note
01358  *  that simply defining an accessor does not create the corresponding
01359  *  instance variable.
01360  *
01361  *     class Fred
01362  *       attr_accessor :a1
01363  *       def initialize
01364  *         @iv = 3
01365  *       end
01366  *     end
01367  *     Fred.new.instance_variables   #=> [:@iv]
01368  */
01369 
01370 VALUE
01371 rb_obj_instance_variables(VALUE obj)
01372 {
01373     VALUE ary;
01374 
01375     ary = rb_ary_new();
01376     rb_ivar_foreach(obj, ivar_i, ary);
01377     return ary;
01378 }
01379 
01380 /*
01381  *  call-seq:
01382  *     obj.remove_instance_variable(symbol)    -> obj
01383  *
01384  *  Removes the named instance variable from <i>obj</i>, returning that
01385  *  variable's value.
01386  *
01387  *     class Dummy
01388  *       attr_reader :var
01389  *       def initialize
01390  *         @var = 99
01391  *       end
01392  *       def remove
01393  *         remove_instance_variable(:@var)
01394  *       end
01395  *     end
01396  *     d = Dummy.new
01397  *     d.var      #=> 99
01398  *     d.remove   #=> 99
01399  *     d.var      #=> nil
01400  */
01401 
01402 VALUE
01403 rb_obj_remove_instance_variable(VALUE obj, VALUE name)
01404 {
01405     VALUE val = Qnil;
01406     const ID id = rb_check_id(&name);
01407     st_data_t n, v;
01408     struct st_table *iv_index_tbl;
01409     st_data_t index;
01410 
01411     rb_check_frozen(obj);
01412     if (!id) {
01413         if (rb_is_instance_name(name)) {
01414             rb_name_error_str(name, "instance variable %"PRIsVALUE" not defined",
01415                               name);
01416         }
01417         else {
01418             rb_name_error_str(name, "`%"PRIsVALUE"' is not allowed as an instance variable name",
01419                               QUOTE(name));
01420         }
01421     }
01422     if (!rb_is_instance_id(id)) {
01423         rb_name_error(id, "`%"PRIsVALUE"' is not allowed as an instance variable name",
01424                       QUOTE_ID(id));
01425     }
01426 
01427     if (SPECIAL_CONST_P(obj)) goto generic;
01428     switch (BUILTIN_TYPE(obj)) {
01429       case T_OBJECT:
01430         iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
01431         if (!iv_index_tbl) break;
01432         if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
01433         if (ROBJECT_NUMIV(obj) <= (long)index) break;
01434         val = ROBJECT_IVPTR(obj)[index];
01435         if (val != Qundef) {
01436             ROBJECT_IVPTR(obj)[index] = Qundef;
01437             return val;
01438         }
01439         break;
01440       case T_CLASS:
01441       case T_MODULE:
01442         n = id;
01443         if (RCLASS_IV_TBL(obj) && st_delete(RCLASS_IV_TBL(obj), &n, &v)) {
01444             return (VALUE)v;
01445         }
01446         break;
01447       default:
01448       generic:
01449         if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
01450             v = val;
01451             if (generic_ivar_remove(obj, (st_data_t)id, &v)) {
01452                 return (VALUE)v;
01453             }
01454         }
01455         break;
01456     }
01457     rb_name_error(id, "instance variable %"PRIsVALUE" not defined", QUOTE_ID(id));
01458 
01459     UNREACHABLE;
01460 }
01461 
01462 NORETURN(static void uninitialized_constant(VALUE, ID));
01463 static void
01464 uninitialized_constant(VALUE klass, ID id)
01465 {
01466     if (klass && rb_class_real(klass) != rb_cObject)
01467         rb_name_error(id, "uninitialized constant %"PRIsVALUE"::%"PRIsVALUE"",
01468                       rb_class_name(klass),
01469                       QUOTE_ID(id));
01470     else {
01471         rb_name_error(id, "uninitialized constant %"PRIsVALUE"", QUOTE_ID(id));
01472     }
01473 }
01474 
01475 static VALUE
01476 const_missing(VALUE klass, ID id)
01477 {
01478     return rb_funcall(klass, rb_intern("const_missing"), 1, ID2SYM(id));
01479 }
01480 
01481 
01482 /*
01483  * call-seq:
01484  *    mod.const_missing(sym)    -> obj
01485  *
01486  * Invoked when a reference is made to an undefined constant in
01487  * <i>mod</i>. It is passed a symbol for the undefined constant, and
01488  * returns a value to be used for that constant. The
01489  * following code is an example of the same:
01490  *
01491  *   def Foo.const_missing(name)
01492  *     name # return the constant name as Symbol
01493  *   end
01494  *
01495  *   Foo::UNDEFINED_CONST    #=> :UNDEFINED_CONST: symbol returned
01496  *
01497  * In the next example when a reference is made to an undefined constant,
01498  * it attempts to load a file whose name is the lowercase version of the
01499  * constant (thus class <code>Fred</code> is assumed to be in file
01500  * <code>fred.rb</code>).  If found, it returns the loaded class. It
01501  * therefore implements an autoload feature similar to Kernel#autoload and
01502  * Module#autoload.
01503  *
01504  *   def Object.const_missing(name)
01505  *     @looked_for ||= {}
01506  *     str_name = name.to_s
01507  *     raise "Class not found: #{name}" if @looked_for[str_name]
01508  *     @looked_for[str_name] = 1
01509  *     file = str_name.downcase
01510  *     require file
01511  *     klass = const_get(name)
01512  *     return klass if klass
01513  *     raise "Class not found: #{name}"
01514  *   end
01515  *
01516  */
01517 
01518 VALUE
01519 rb_mod_const_missing(VALUE klass, VALUE name)
01520 {
01521     rb_vm_pop_cfunc_frame();
01522     uninitialized_constant(klass, rb_to_id(name));
01523 
01524     UNREACHABLE;
01525 }
01526 
01527 static void
01528 autoload_mark(void *ptr)
01529 {
01530     rb_mark_tbl((st_table *)ptr);
01531 }
01532 
01533 static void
01534 autoload_free(void *ptr)
01535 {
01536     st_free_table((st_table *)ptr);
01537 }
01538 
01539 static size_t
01540 autoload_memsize(const void *ptr)
01541 {
01542     const st_table *tbl = ptr;
01543     return tbl ? st_memsize(tbl) : 0;
01544 }
01545 
01546 static const rb_data_type_t autoload_data_type = {
01547     "autoload",
01548     {autoload_mark, autoload_free, autoload_memsize,},
01549     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01550 };
01551 
01552 #define check_autoload_table(av) \
01553     (struct st_table *)rb_check_typeddata((av), &autoload_data_type)
01554 
01555 static VALUE
01556 autoload_data(VALUE mod, ID id)
01557 {
01558     struct st_table *tbl;
01559     st_data_t val;
01560 
01561     if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) ||
01562             !(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, (st_data_t)id, &val)) {
01563         return 0;
01564     }
01565     return (VALUE)val;
01566 }
01567 
01568 struct autoload_data_i {
01569     VALUE feature;
01570     int safe_level;
01571     VALUE thread;
01572     VALUE value;
01573 };
01574 
01575 static void
01576 autoload_i_mark(void *ptr)
01577 {
01578     struct autoload_data_i *p = ptr;
01579     rb_gc_mark(p->feature);
01580     rb_gc_mark(p->thread);
01581     rb_gc_mark(p->value);
01582 }
01583 
01584 static void
01585 autoload_i_free(void *ptr)
01586 {
01587     struct autoload_data_i *p = ptr;
01588     xfree(p);
01589 }
01590 
01591 static size_t
01592 autoload_i_memsize(const void *ptr)
01593 {
01594     return sizeof(struct autoload_data_i);
01595 }
01596 
01597 static const rb_data_type_t autoload_data_i_type = {
01598     "autoload_i",
01599     {autoload_i_mark, autoload_i_free, autoload_i_memsize,},
01600     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01601 };
01602 
01603 #define check_autoload_data(av) \
01604     (struct autoload_data_i *)rb_check_typeddata((av), &autoload_data_i_type)
01605 
01606 void
01607 rb_autoload(VALUE mod, ID id, const char *file)
01608 {
01609     st_data_t av;
01610     VALUE ad, fn;
01611     struct st_table *tbl;
01612     struct autoload_data_i *ele;
01613 
01614     if (!rb_is_const_id(id)) {
01615         rb_raise(rb_eNameError, "autoload must be constant name: %"PRIsVALUE"",
01616                  QUOTE_ID(id));
01617     }
01618     if (!file || !*file) {
01619         rb_raise(rb_eArgError, "empty file name");
01620     }
01621 
01622     if ((tbl = RCLASS_CONST_TBL(mod)) && st_lookup(tbl, (st_data_t)id, &av) && ((rb_const_entry_t*)av)->value != Qundef)
01623         return;
01624 
01625     rb_const_set(mod, id, Qundef);
01626     tbl = RCLASS_IV_TBL(mod);
01627     if (tbl && st_lookup(tbl, (st_data_t)autoload, &av)) {
01628         tbl = check_autoload_table((VALUE)av);
01629     }
01630     else {
01631         if (!tbl) tbl = RCLASS_IV_TBL(mod) = st_init_numtable();
01632         av = (st_data_t)TypedData_Wrap_Struct(0, &autoload_data_type, 0);
01633         st_add_direct(tbl, (st_data_t)autoload, av);
01634         RB_OBJ_WRITTEN(mod, Qnil, av);
01635         DATA_PTR(av) = tbl = st_init_numtable();
01636     }
01637     fn = rb_str_new2(file);
01638     FL_UNSET(fn, FL_TAINT);
01639     OBJ_FREEZE(fn);
01640 
01641     ele = ALLOC(struct autoload_data_i);
01642     ele->feature = fn;
01643     ele->safe_level = rb_safe_level();
01644     ele->thread = Qnil;
01645     ele->value = Qundef;
01646     ad = TypedData_Wrap_Struct(0, &autoload_data_i_type, ele);
01647     st_insert(tbl, (st_data_t)id, (st_data_t)ad);
01648 }
01649 
01650 static void
01651 autoload_delete(VALUE mod, ID id)
01652 {
01653     st_data_t val, load = 0, n = id;
01654     rb_const_entry_t *ce;
01655 
01656     st_delete(RCLASS_CONST_TBL(mod), &n, &val);
01657     ce = (rb_const_entry_t*)val;
01658     if (ce) xfree(ce);
01659     if (st_lookup(RCLASS_IV_TBL(mod), (st_data_t)autoload, &val)) {
01660         struct st_table *tbl = check_autoload_table((VALUE)val);
01661 
01662         st_delete(tbl, &n, &load);
01663 
01664         if (tbl->num_entries == 0) {
01665             n = autoload;
01666             st_delete(RCLASS_IV_TBL(mod), &n, &val);
01667         }
01668     }
01669 }
01670 
01671 static VALUE
01672 autoload_provided(VALUE arg)
01673 {
01674     const char **p = (const char **)arg;
01675     return rb_feature_provided(*p, p);
01676 }
01677 
01678 static VALUE
01679 reset_safe(VALUE safe)
01680 {
01681     rb_set_safe_level_force((int)safe);
01682     return safe;
01683 }
01684 
01685 static VALUE
01686 check_autoload_required(VALUE mod, ID id, const char **loadingpath)
01687 {
01688     VALUE file, load;
01689     struct autoload_data_i *ele;
01690     const char *loading;
01691     int safe;
01692 
01693     if (!(load = autoload_data(mod, id)) || !(ele = check_autoload_data(load))) {
01694         return 0;
01695     }
01696     file = ele->feature;
01697     Check_Type(file, T_STRING);
01698     if (!RSTRING_PTR(file) || !*RSTRING_PTR(file)) {
01699         rb_raise(rb_eArgError, "empty file name");
01700     }
01701     loading = RSTRING_PTR(file);
01702     safe = rb_safe_level();
01703     rb_set_safe_level_force(0);
01704     if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
01705         return load;
01706     }
01707     if (loadingpath && loading) {
01708         *loadingpath = loading;
01709         return load;
01710     }
01711     return 0;
01712 }
01713 
01714 int
01715 rb_autoloading_value(VALUE mod, ID id, VALUE* value)
01716 {
01717     VALUE load;
01718     struct autoload_data_i *ele;
01719 
01720     if (!(load = autoload_data(mod, id)) || !(ele = check_autoload_data(load))) {
01721         return 0;
01722     }
01723     if (ele->thread == rb_thread_current()) {
01724         if (ele->value != Qundef) {
01725             if (value) {
01726                 *value = ele->value;
01727             }
01728             return 1;
01729         }
01730     }
01731     return 0;
01732 }
01733 
01734 static int
01735 autoload_defined_p(VALUE mod, ID id)
01736 {
01737     struct st_table *tbl = RCLASS_CONST_TBL(mod);
01738     st_data_t val;
01739 
01740     if (!tbl || !st_lookup(tbl, (st_data_t)id, &val) || ((rb_const_entry_t*)val)->value != Qundef) {
01741         return 0;
01742     }
01743     return !rb_autoloading_value(mod, id, NULL);
01744 }
01745 
01746 struct autoload_const_set_args {
01747     VALUE mod;
01748     ID id;
01749     VALUE value;
01750 };
01751 
01752 static VALUE
01753 autoload_const_set(VALUE arg)
01754 {
01755     struct autoload_const_set_args* args = (struct autoload_const_set_args *)arg;
01756     autoload_delete(args->mod, args->id);
01757     rb_const_set(args->mod, args->id, args->value);
01758     return 0;                   /* ignored */
01759 }
01760 
01761 static VALUE
01762 autoload_require(VALUE arg)
01763 {
01764     struct autoload_data_i *ele = (struct autoload_data_i *)arg;
01765     return rb_require_safe(ele->feature, ele->safe_level);
01766 }
01767 
01768 VALUE
01769 rb_autoload_load(VALUE mod, ID id)
01770 {
01771     VALUE load, result;
01772     const char *loading = 0, *src;
01773     struct autoload_data_i *ele;
01774     int state = 0;
01775 
01776     if (!autoload_defined_p(mod, id)) return Qfalse;
01777     load = check_autoload_required(mod, id, &loading);
01778     if (!load) return Qfalse;
01779     src = rb_sourcefile();
01780     if (src && loading && strcmp(src, loading) == 0) return Qfalse;
01781 
01782     /* set ele->thread for a marker of autoloading thread */
01783     if (!(ele = check_autoload_data(load))) {
01784         return Qfalse;
01785     }
01786     if (ele->thread == Qnil) {
01787         ele->thread = rb_thread_current();
01788     }
01789     /* autoload_data_i can be deleted by another thread while require */
01790     result = rb_protect(autoload_require, (VALUE)ele, &state);
01791     if (ele->thread == rb_thread_current()) {
01792         ele->thread = Qnil;
01793     }
01794     if (state) rb_jump_tag(state);
01795 
01796     if (RTEST(result)) {
01797         /* At the last, move a value defined in autoload to constant table */
01798         if (ele->value != Qundef) {
01799             int safe_backup;
01800             struct autoload_const_set_args args;
01801             args.mod = mod;
01802             args.id = id;
01803             args.value = ele->value;
01804             safe_backup = rb_safe_level();
01805             rb_set_safe_level_force(ele->safe_level);
01806             rb_ensure(autoload_const_set, (VALUE)&args, reset_safe, (VALUE)safe_backup);
01807         }
01808     }
01809     RB_GC_GUARD(load);
01810     return result;
01811 }
01812 
01813 VALUE
01814 rb_autoload_p(VALUE mod, ID id)
01815 {
01816     VALUE load;
01817     struct autoload_data_i *ele;
01818 
01819     while (!autoload_defined_p(mod, id)) {
01820         mod = RCLASS_SUPER(mod);
01821         if (!mod) return Qnil;
01822     }
01823     load = check_autoload_required(mod, id, 0);
01824     if (!load) return Qnil;
01825     return (ele = check_autoload_data(load)) ? ele->feature : Qnil;
01826 }
01827 
01828 static VALUE
01829 rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
01830 {
01831     VALUE value, tmp, av;
01832     int mod_retry = 0;
01833 
01834     tmp = klass;
01835   retry:
01836     while (RTEST(tmp)) {
01837         VALUE am = 0;
01838         st_data_t data;
01839         while (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &data)) {
01840             rb_const_entry_t *ce = (rb_const_entry_t *)data;
01841             if (visibility && ce->flag == CONST_PRIVATE) {
01842                 rb_name_error(id, "private constant %"PRIsVALUE"::%"PRIsVALUE" referenced",
01843                               rb_class_name(klass), QUOTE_ID(id));
01844             }
01845             value = ce->value;
01846             if (value == Qundef) {
01847                 if (am == tmp) break;
01848                 am = tmp;
01849                 if (rb_autoloading_value(tmp, id, &av)) return av;
01850                 rb_autoload_load(tmp, id);
01851                 continue;
01852             }
01853             if (exclude && tmp == rb_cObject && klass != rb_cObject) {
01854                 rb_warn("toplevel constant %"PRIsVALUE" referenced by %"PRIsVALUE"::%"PRIsVALUE"",
01855                         QUOTE_ID(id), rb_class_name(klass), QUOTE_ID(id));
01856             }
01857             return value;
01858         }
01859         if (!recurse) break;
01860         tmp = RCLASS_SUPER(tmp);
01861     }
01862     if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
01863         mod_retry = 1;
01864         tmp = rb_cObject;
01865         goto retry;
01866     }
01867 
01868     value = const_missing(klass, id);
01869     rb_vm_inc_const_missing_count();
01870     return value;
01871 }
01872 
01873 VALUE
01874 rb_const_get_from(VALUE klass, ID id)
01875 {
01876     return rb_const_get_0(klass, id, TRUE, TRUE, FALSE);
01877 }
01878 
01879 VALUE
01880 rb_const_get(VALUE klass, ID id)
01881 {
01882     return rb_const_get_0(klass, id, FALSE, TRUE, FALSE);
01883 }
01884 
01885 VALUE
01886 rb_const_get_at(VALUE klass, ID id)
01887 {
01888     return rb_const_get_0(klass, id, TRUE, FALSE, FALSE);
01889 }
01890 
01891 VALUE
01892 rb_public_const_get_from(VALUE klass, ID id)
01893 {
01894     return rb_const_get_0(klass, id, TRUE, TRUE, TRUE);
01895 }
01896 
01897 VALUE
01898 rb_public_const_get(VALUE klass, ID id)
01899 {
01900     return rb_const_get_0(klass, id, FALSE, TRUE, TRUE);
01901 }
01902 
01903 VALUE
01904 rb_public_const_get_at(VALUE klass, ID id)
01905 {
01906     return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
01907 }
01908 
01909 /*
01910  *  call-seq:
01911  *     remove_const(sym)   -> obj
01912  *
01913  *  Removes the definition of the given constant, returning that
01914  *  constant's previous value.  If that constant referred to
01915  *  a module, this will not change that module's name and can lead
01916  *  to confusion.
01917  */
01918 
01919 VALUE
01920 rb_mod_remove_const(VALUE mod, VALUE name)
01921 {
01922     const ID id = rb_check_id(&name);
01923 
01924     if (!id) {
01925         if (rb_is_const_name(name)) {
01926             rb_name_error_str(name, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
01927                               rb_class_name(mod), name);
01928         }
01929         else {
01930             rb_name_error_str(name, "`%"PRIsVALUE"' is not allowed as a constant name",
01931                               QUOTE(name));
01932         }
01933     }
01934     if (!rb_is_const_id(id)) {
01935         rb_name_error(id, "`%"PRIsVALUE"' is not allowed as a constant name",
01936                       QUOTE_ID(id));
01937     }
01938     return rb_const_remove(mod, id);
01939 }
01940 
01941 VALUE
01942 rb_const_remove(VALUE mod, ID id)
01943 {
01944     VALUE val;
01945     st_data_t v, n = id;
01946 
01947     rb_check_frozen(mod);
01948     if (!RCLASS_CONST_TBL(mod) || !st_delete(RCLASS_CONST_TBL(mod), &n, &v)) {
01949         if (rb_const_defined_at(mod, id)) {
01950             rb_name_error(id, "cannot remove %"PRIsVALUE"::%"PRIsVALUE"",
01951                           rb_class_name(mod), QUOTE_ID(id));
01952         }
01953         rb_name_error(id, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
01954                       rb_class_name(mod), QUOTE_ID(id));
01955     }
01956 
01957     rb_clear_constant_cache();
01958 
01959     val = ((rb_const_entry_t*)v)->value;
01960     if (val == Qundef) {
01961         autoload_delete(mod, id);
01962         val = Qnil;
01963     }
01964     xfree((rb_const_entry_t*)v);
01965     return val;
01966 }
01967 
01968 static int
01969 sv_i(st_data_t k, st_data_t v, st_data_t a)
01970 {
01971     ID key = (ID)k;
01972     rb_const_entry_t *ce = (rb_const_entry_t *)v;
01973     st_table *tbl = (st_table *)a;
01974 
01975     if (rb_is_const_id(key)) {
01976         if (!st_lookup(tbl, (st_data_t)key, 0)) {
01977             st_insert(tbl, (st_data_t)key, (st_data_t)ce);
01978         }
01979     }
01980     return ST_CONTINUE;
01981 }
01982 
01983 static int
01984 rb_local_constants_i(st_data_t const_name, st_data_t const_value, st_data_t ary)
01985 {
01986     rb_ary_push((VALUE)ary, ID2SYM((ID)const_name));
01987     return ST_CONTINUE;
01988 }
01989 
01990 static VALUE
01991 rb_local_constants(VALUE mod)
01992 {
01993     st_table *tbl = RCLASS_CONST_TBL(mod);
01994     VALUE ary;
01995 
01996     if (!tbl) return rb_ary_new2(0);
01997 
01998     ary = rb_ary_new2(tbl->num_entries);
01999     st_foreach(tbl, rb_local_constants_i, ary);
02000     return ary;
02001 }
02002 
02003 void*
02004 rb_mod_const_at(VALUE mod, void *data)
02005 {
02006     st_table *tbl = data;
02007     if (!tbl) {
02008         tbl = st_init_numtable();
02009     }
02010     if (RCLASS_CONST_TBL(mod)) {
02011         st_foreach_safe(RCLASS_CONST_TBL(mod), sv_i, (st_data_t)tbl);
02012     }
02013     return tbl;
02014 }
02015 
02016 void*
02017 rb_mod_const_of(VALUE mod, void *data)
02018 {
02019     VALUE tmp = mod;
02020     for (;;) {
02021         data = rb_mod_const_at(tmp, data);
02022         tmp = RCLASS_SUPER(tmp);
02023         if (!tmp) break;
02024         if (tmp == rb_cObject && mod != rb_cObject) break;
02025     }
02026     return data;
02027 }
02028 
02029 static int
02030 list_i(st_data_t key, st_data_t value, VALUE ary)
02031 {
02032     ID sym = (ID)key;
02033     rb_const_entry_t *ce = (rb_const_entry_t *)value;
02034     if (ce->flag != CONST_PRIVATE) rb_ary_push(ary, ID2SYM(sym));
02035     return ST_CONTINUE;
02036 }
02037 
02038 VALUE
02039 rb_const_list(void *data)
02040 {
02041     st_table *tbl = data;
02042     VALUE ary;
02043 
02044     if (!tbl) return rb_ary_new2(0);
02045     ary = rb_ary_new2(tbl->num_entries);
02046     st_foreach_safe(tbl, list_i, ary);
02047     st_free_table(tbl);
02048 
02049     return ary;
02050 }
02051 
02052 /*
02053  *  call-seq:
02054  *     mod.constants(inherit=true)    -> array
02055  *
02056  *  Returns an array of the names of the constants accessible in
02057  *  <i>mod</i>. This includes the names of constants in any included
02058  *  modules (example at start of section), unless the <i>inherit</i>
02059  *  parameter is set to <code>false</code>.
02060  *
02061  *    IO.constants.include?(:SYNC)        #=> true
02062  *    IO.constants(false).include?(:SYNC) #=> false
02063  *
02064  *  Also see <code>Module::const_defined?</code>.
02065  */
02066 
02067 VALUE
02068 rb_mod_constants(int argc, VALUE *argv, VALUE mod)
02069 {
02070     VALUE inherit;
02071 
02072     if (argc == 0) {
02073         inherit = Qtrue;
02074     }
02075     else {
02076         rb_scan_args(argc, argv, "01", &inherit);
02077     }
02078 
02079     if (RTEST(inherit)) {
02080         return rb_const_list(rb_mod_const_of(mod, 0));
02081     }
02082     else {
02083         return rb_local_constants(mod);
02084     }
02085 }
02086 
02087 static int
02088 rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
02089 {
02090     st_data_t value;
02091     VALUE tmp;
02092     int mod_retry = 0;
02093 
02094     tmp = klass;
02095   retry:
02096     while (tmp) {
02097         if (RCLASS_CONST_TBL(tmp) && st_lookup(RCLASS_CONST_TBL(tmp), (st_data_t)id, &value)) {
02098             rb_const_entry_t *ce = (rb_const_entry_t *)value;
02099             if (visibility && ce->flag == CONST_PRIVATE) {
02100                 return (int)Qfalse;
02101             }
02102             if (ce->value == Qundef && !check_autoload_required(tmp, id, 0) && !rb_autoloading_value(tmp, id, 0))
02103                 return (int)Qfalse;
02104             return (int)Qtrue;
02105         }
02106         if (!recurse) break;
02107         tmp = RCLASS_SUPER(tmp);
02108     }
02109     if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
02110         mod_retry = 1;
02111         tmp = rb_cObject;
02112         goto retry;
02113     }
02114     return (int)Qfalse;
02115 }
02116 
02117 int
02118 rb_const_defined_from(VALUE klass, ID id)
02119 {
02120     return rb_const_defined_0(klass, id, TRUE, TRUE, FALSE);
02121 }
02122 
02123 int
02124 rb_const_defined(VALUE klass, ID id)
02125 {
02126     return rb_const_defined_0(klass, id, FALSE, TRUE, FALSE);
02127 }
02128 
02129 int
02130 rb_const_defined_at(VALUE klass, ID id)
02131 {
02132     return rb_const_defined_0(klass, id, TRUE, FALSE, FALSE);
02133 }
02134 
02135 int
02136 rb_public_const_defined_from(VALUE klass, ID id)
02137 {
02138     return rb_const_defined_0(klass, id, TRUE, TRUE, TRUE);
02139 }
02140 
02141 int
02142 rb_public_const_defined(VALUE klass, ID id)
02143 {
02144     return rb_const_defined_0(klass, id, FALSE, TRUE, TRUE);
02145 }
02146 
02147 int
02148 rb_public_const_defined_at(VALUE klass, ID id)
02149 {
02150     return rb_const_defined_0(klass, id, TRUE, FALSE, TRUE);
02151 }
02152 
02153 static void
02154 check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
02155 {
02156     rb_check_frozen(klass);
02157 }
02158 
02159 void
02160 rb_const_set(VALUE klass, ID id, VALUE val)
02161 {
02162     rb_const_entry_t *ce;
02163     rb_const_flag_t visibility = CONST_PUBLIC;
02164 
02165     if (NIL_P(klass)) {
02166         rb_raise(rb_eTypeError, "no class/module to define constant %"PRIsVALUE"",
02167                  QUOTE_ID(id));
02168     }
02169 
02170     check_before_mod_set(klass, id, val, "constant");
02171     if (!RCLASS_CONST_TBL(klass)) {
02172         RCLASS_CONST_TBL(klass) = st_init_numtable();
02173     }
02174     else {
02175         st_data_t value;
02176 
02177         if (st_lookup(RCLASS_CONST_TBL(klass), (st_data_t)id, &value)) {
02178             rb_const_entry_t *ce = (rb_const_entry_t*)value;
02179             if (ce->value == Qundef) {
02180                 VALUE load;
02181                 struct autoload_data_i *ele;
02182 
02183                 load = autoload_data(klass, id);
02184                 /* for autoloading thread, keep the defined value to autoloading storage */
02185                 if (load && (ele = check_autoload_data(load)) && (ele->thread == rb_thread_current())) {
02186                     rb_clear_constant_cache();
02187 
02188                     ele->value = val; /* autoload_i is non-WB-protected */
02189                     return;
02190                 }
02191                 /* otherwise, allow to override */
02192                 autoload_delete(klass, id);
02193             }
02194             else {
02195                 VALUE name = QUOTE_ID(id);
02196                 visibility = ce->flag;
02197                 if (klass == rb_cObject)
02198                     rb_warn("already initialized constant %"PRIsVALUE"", name);
02199                 else
02200                     rb_warn("already initialized constant %"PRIsVALUE"::%"PRIsVALUE"",
02201                             rb_class_name(klass), name);
02202                 if (!NIL_P(ce->file) && ce->line) {
02203                     rb_compile_warn(RSTRING_PTR(ce->file), ce->line,
02204                                     "previous definition of %"PRIsVALUE" was here", name);
02205                 }
02206                 st_delete(RCLASS_CONST_TBL(klass), &id, 0);
02207                 xfree(ce);
02208             }
02209         }
02210     }
02211 
02212     rb_clear_constant_cache();
02213 
02214 
02215     ce = ALLOC(rb_const_entry_t);
02216     MEMZERO(ce, rb_const_entry_t, 1);
02217     ce->flag = visibility;
02218     ce->line = rb_sourceline();
02219     st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
02220     RB_OBJ_WRITE(klass, &ce->value, val);
02221     RB_OBJ_WRITE(klass, &ce->file, rb_sourcefilename());
02222 }
02223 
02224 void
02225 rb_define_const(VALUE klass, const char *name, VALUE val)
02226 {
02227     ID id = rb_intern(name);
02228 
02229     if (!rb_is_const_id(id)) {
02230         rb_warn("rb_define_const: invalid name `%s' for constant", name);
02231     }
02232     rb_const_set(klass, id, val);
02233 }
02234 
02235 void
02236 rb_define_global_const(const char *name, VALUE val)
02237 {
02238     rb_define_const(rb_cObject, name, val);
02239 }
02240 
02241 static void
02242 set_const_visibility(VALUE mod, int argc, VALUE *argv, rb_const_flag_t flag)
02243 {
02244     int i;
02245     st_data_t v;
02246     ID id;
02247 
02248     if (argc == 0) {
02249         rb_warning("%"PRIsVALUE" with no argument is just ignored",
02250                    QUOTE_ID(rb_frame_callee()));
02251         return;
02252     }
02253 
02254     for (i = 0; i < argc; i++) {
02255         VALUE val = argv[i];
02256         id = rb_check_id(&val);
02257         if (!id) {
02258             if (i > 0) {
02259                 rb_clear_constant_cache();
02260             }
02261 
02262             rb_name_error_str(val, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
02263                               rb_class_name(mod), QUOTE(val));
02264         }
02265         if (RCLASS_CONST_TBL(mod) &&
02266             st_lookup(RCLASS_CONST_TBL(mod), (st_data_t)id, &v)) {
02267             ((rb_const_entry_t*)v)->flag = flag;
02268         }
02269         else {
02270             if (i > 0) {
02271                 rb_clear_constant_cache();
02272             }
02273             rb_name_error(id, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined",
02274                           rb_class_name(mod), QUOTE_ID(id));
02275         }
02276     }
02277     rb_clear_constant_cache();
02278 }
02279 
02280 /*
02281  *  call-seq:
02282  *     mod.private_constant(symbol, ...)    => mod
02283  *
02284  *  Makes a list of existing constants private.
02285  */
02286 
02287 VALUE
02288 rb_mod_private_constant(int argc, VALUE *argv, VALUE obj)
02289 {
02290     set_const_visibility(obj, argc, argv, CONST_PRIVATE);
02291     return obj;
02292 }
02293 
02294 /*
02295  *  call-seq:
02296  *     mod.public_constant(symbol, ...)    => mod
02297  *
02298  *  Makes a list of existing constants public.
02299  */
02300 
02301 VALUE
02302 rb_mod_public_constant(int argc, VALUE *argv, VALUE obj)
02303 {
02304     set_const_visibility(obj, argc, argv, CONST_PUBLIC);
02305     return obj;
02306 }
02307 
02308 static VALUE
02309 original_module(VALUE c)
02310 {
02311     if (RB_TYPE_P(c, T_ICLASS))
02312         return RBASIC(c)->klass;
02313     return c;
02314 }
02315 
02316 static int
02317 cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
02318 {
02319     if (!RCLASS_IV_TBL(klass)) return 0;
02320     return st_lookup(RCLASS_IV_TBL(klass), (st_data_t)id, v);
02321 }
02322 
02323 static VALUE
02324 cvar_front_klass(VALUE klass)
02325 {
02326     if (FL_TEST(klass, FL_SINGLETON)) {
02327         VALUE obj = rb_ivar_get(klass, id__attached__);
02328         if (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS)) {
02329             return obj;
02330         }
02331     }
02332     return RCLASS_SUPER(klass);
02333 }
02334 
02335 #define CVAR_FOREACH_ANCESTORS(klass, v, r) \
02336     for (klass = cvar_front_klass(klass); klass; klass = RCLASS_SUPER(klass)) { \
02337         if (cvar_lookup_at(klass, id, (v))) { \
02338             r; \
02339         } \
02340     }
02341 
02342 #define CVAR_LOOKUP(v,r) do {\
02343     if (cvar_lookup_at(klass, id, (v))) {r;}\
02344     CVAR_FOREACH_ANCESTORS(klass, v, r);\
02345 } while(0)
02346 
02347 void
02348 rb_cvar_set(VALUE klass, ID id, VALUE val)
02349 {
02350     VALUE tmp, front = 0, target = 0;
02351 
02352     tmp = klass;
02353     CVAR_LOOKUP(0, {if (!front) front = klass; target = klass;});
02354     if (target) {
02355         if (front && target != front) {
02356             st_data_t did = id;
02357 
02358             if (RTEST(ruby_verbose)) {
02359                 rb_warning("class variable %"PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
02360                            QUOTE_ID(id), rb_class_name(original_module(front)),
02361                            rb_class_name(original_module(target)));
02362             }
02363             if (BUILTIN_TYPE(front) == T_CLASS) {
02364                 st_delete(RCLASS_IV_TBL(front),&did,0);
02365             }
02366         }
02367     }
02368     else {
02369         target = tmp;
02370     }
02371 
02372     check_before_mod_set(target, id, val, "class variable");
02373     if (!RCLASS_IV_TBL(target)) {
02374         RCLASS_IV_TBL(target) = st_init_numtable();
02375     }
02376 
02377     rb_st_insert_id_and_value(target, RCLASS_IV_TBL(target), (st_data_t)id, (st_data_t)val);
02378 }
02379 
02380 VALUE
02381 rb_cvar_get(VALUE klass, ID id)
02382 {
02383     VALUE tmp, front = 0, target = 0;
02384     st_data_t value;
02385 
02386     tmp = klass;
02387     CVAR_LOOKUP(&value, {if (!front) front = klass; target = klass;});
02388     if (!target) {
02389         rb_name_error(id, "uninitialized class variable %"PRIsVALUE" in %"PRIsVALUE"",
02390                       QUOTE_ID(id), rb_class_name(tmp));
02391     }
02392     if (front && target != front) {
02393         st_data_t did = id;
02394 
02395         if (RTEST(ruby_verbose)) {
02396             rb_warning("class variable %"PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
02397                        QUOTE_ID(id), rb_class_name(original_module(front)),
02398                        rb_class_name(original_module(target)));
02399         }
02400         if (BUILTIN_TYPE(front) == T_CLASS) {
02401             st_delete(RCLASS_IV_TBL(front),&did,0);
02402         }
02403     }
02404     return (VALUE)value;
02405 }
02406 
02407 VALUE
02408 rb_cvar_defined(VALUE klass, ID id)
02409 {
02410     if (!klass) return Qfalse;
02411     CVAR_LOOKUP(0,return Qtrue);
02412     return Qfalse;
02413 }
02414 
02415 void
02416 rb_cv_set(VALUE klass, const char *name, VALUE val)
02417 {
02418     ID id = rb_intern(name);
02419     if (!rb_is_class_id(id)) {
02420         rb_name_error(id, "wrong class variable name %s", name);
02421     }
02422     rb_cvar_set(klass, id, val);
02423 }
02424 
02425 VALUE
02426 rb_cv_get(VALUE klass, const char *name)
02427 {
02428     ID id = rb_intern(name);
02429     if (!rb_is_class_id(id)) {
02430         rb_name_error(id, "wrong class variable name %s", name);
02431     }
02432     return rb_cvar_get(klass, id);
02433 }
02434 
02435 void
02436 rb_define_class_variable(VALUE klass, const char *name, VALUE val)
02437 {
02438     ID id = rb_intern(name);
02439 
02440     if (!rb_is_class_id(id)) {
02441         rb_name_error(id, "wrong class variable name %s", name);
02442     }
02443     rb_cvar_set(klass, id, val);
02444 }
02445 
02446 static int
02447 cv_i(st_data_t k, st_data_t v, st_data_t a)
02448 {
02449     ID key = (ID)k;
02450     st_table *tbl = (st_table *)a;
02451 
02452     if (rb_is_class_id(key)) {
02453         if (!st_lookup(tbl, (st_data_t)key, 0)) {
02454             st_insert(tbl, (st_data_t)key, 0);
02455         }
02456     }
02457     return ST_CONTINUE;
02458 }
02459 
02460 static void*
02461 mod_cvar_at(VALUE mod, void *data)
02462 {
02463     st_table *tbl = data;
02464     if (!tbl) {
02465         tbl = st_init_numtable();
02466     }
02467     if (RCLASS_IV_TBL(mod)) {
02468         st_foreach_safe(RCLASS_IV_TBL(mod), cv_i, (st_data_t)tbl);
02469     }
02470     return tbl;
02471 }
02472 
02473 static void*
02474 mod_cvar_of(VALUE mod, void *data)
02475 {
02476     VALUE tmp = mod;
02477     for (;;) {
02478         data = mod_cvar_at(tmp, data);
02479         tmp = RCLASS_SUPER(tmp);
02480         if (!tmp) break;
02481     }
02482     return data;
02483 }
02484 
02485 static int
02486 cv_list_i(st_data_t key, st_data_t value, VALUE ary)
02487 {
02488     ID sym = (ID)key;
02489     rb_ary_push(ary, ID2SYM(sym));
02490     return ST_CONTINUE;
02491 }
02492 
02493 static VALUE
02494 cvar_list(void *data)
02495 {
02496     st_table *tbl = data;
02497     VALUE ary;
02498 
02499     if (!tbl) return rb_ary_new2(0);
02500     ary = rb_ary_new2(tbl->num_entries);
02501     st_foreach_safe(tbl, cv_list_i, ary);
02502     st_free_table(tbl);
02503 
02504     return ary;
02505 }
02506 
02507 /*
02508  *  call-seq:
02509  *     mod.class_variables(inherit=true)    -> array
02510  *
02511  *  Returns an array of the names of class variables in <i>mod</i>.
02512  *  This includes the names of class variables in any included
02513  *  modules, unless the <i>inherit</i> parameter is set to
02514  *  <code>false</code>.
02515  *
02516  *     class One
02517  *       @@var1 = 1
02518  *     end
02519  *     class Two < One
02520  *       @@var2 = 2
02521  *     end
02522  *     One.class_variables          #=> [:@@var1]
02523  *     Two.class_variables          #=> [:@@var2, :@@var1]
02524  *     Two.class_variables(false)   #=> [:@@var2]
02525  */
02526 
02527 VALUE
02528 rb_mod_class_variables(int argc, VALUE *argv, VALUE mod)
02529 {
02530     VALUE inherit;
02531     st_table *tbl;
02532 
02533     if (argc == 0) {
02534         inherit = Qtrue;
02535     }
02536     else {
02537         rb_scan_args(argc, argv, "01", &inherit);
02538     }
02539     if (RTEST(inherit)) {
02540         tbl = mod_cvar_of(mod, 0);
02541     }
02542     else {
02543         tbl = mod_cvar_at(mod, 0);
02544     }
02545     return cvar_list(tbl);
02546 }
02547 
02548 /*
02549  *  call-seq:
02550  *     remove_class_variable(sym)    -> obj
02551  *
02552  *  Removes the definition of the <i>sym</i>, returning that
02553  *  constant's value.
02554  *
02555  *     class Dummy
02556  *       @@var = 99
02557  *       puts @@var
02558  *       remove_class_variable(:@@var)
02559  *       p(defined? @@var)
02560  *     end
02561  *
02562  *  <em>produces:</em>
02563  *
02564  *     99
02565  *     nil
02566  */
02567 
02568 VALUE
02569 rb_mod_remove_cvar(VALUE mod, VALUE name)
02570 {
02571     const ID id = rb_check_id(&name);
02572     st_data_t val, n = id;
02573 
02574     if (!id) {
02575         if (rb_is_class_name(name)) {
02576             rb_name_error_str(name, "class variable %"PRIsVALUE" not defined for %"PRIsVALUE"",
02577                               name, rb_class_name(mod));
02578         }
02579         else {
02580             rb_name_error_str(name, "wrong class variable name %"PRIsVALUE"", QUOTE(name));
02581         }
02582     }
02583     if (!rb_is_class_id(id)) {
02584         rb_name_error(id, "wrong class variable name %"PRIsVALUE"", QUOTE_ID(id));
02585     }
02586     rb_check_frozen(mod);
02587     if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), &n, &val)) {
02588         return (VALUE)val;
02589     }
02590     if (rb_cvar_defined(mod, id)) {
02591         rb_name_error(id, "cannot remove %"PRIsVALUE" for %"PRIsVALUE"",
02592                  QUOTE_ID(id), rb_class_name(mod));
02593     }
02594     rb_name_error(id, "class variable %"PRIsVALUE" not defined for %"PRIsVALUE"",
02595                   QUOTE_ID(id), rb_class_name(mod));
02596 
02597     UNREACHABLE;
02598 }
02599 
02600 VALUE
02601 rb_iv_get(VALUE obj, const char *name)
02602 {
02603     ID id = rb_intern(name);
02604 
02605     return rb_ivar_get(obj, id);
02606 }
02607 
02608 VALUE
02609 rb_iv_set(VALUE obj, const char *name, VALUE val)
02610 {
02611     ID id = rb_intern(name);
02612 
02613     return rb_ivar_set(obj, id, val);
02614 }
02615 
02616 /* tbl = xx(obj); tbl[key] = value; */
02617 int
02618 rb_st_insert_id_and_value(VALUE obj, st_table *tbl, ID key, VALUE value)
02619 {
02620     int result = st_insert(tbl, (st_data_t)key, (st_data_t)value);
02621     RB_OBJ_WRITTEN(obj, Qundef, value);
02622     return result;
02623 }
02624 
02625 static int
02626 tbl_copy_i(st_data_t key, st_data_t value, st_data_t data)
02627 {
02628     RB_OBJ_WRITTEN((VALUE)data, Qundef, (VALUE)value);
02629     return ST_CONTINUE;
02630 }
02631 
02632 st_table *
02633 rb_st_copy(VALUE obj, struct st_table *orig_tbl)
02634 {
02635     st_table *new_tbl = st_copy(orig_tbl);
02636     st_foreach(new_tbl, tbl_copy_i, (st_data_t)obj);
02637     return new_tbl;
02638 }
02639 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7