summaryrefslogtreecommitdiff
path: root/variable.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-05-29 00:11:11 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-05-29 00:11:11 +0000
commit5ddce4f7bccc47a3c73860622f55f40c987ce592 (patch)
tree9847c8a5146f876cb72e94991ceeece3e3b9e92c /variable.c
parent144caca6bbc27ce2d2c681e381ffb912189c73b1 (diff)
* eval.c (ev_const_defined, ev_const_get), variable.c
(rb_const_get_at, rb_const_get, rb_mod_remove_const): use Qundef as autoload marker. [ruby-dev:18103], [ruby-dev:18184] * eval.c (rb_mod_autoload, rb_mod_autoload_p): new method; Module#autoload, Module#autoload?. * variable.c (rb_autoload, rb_autoload_load, rb_autoload_p): manage autoload constants per classes/modules. * variable.c (rb_const_defined_at, rb_const_defined): return false for autoloading constants. * class.c (rb_define_class, rb_define_module), eval.c (rb_eval), variable.c (rb_mod_const_at, rb_const_assign): removed autoload stuff. * intern.h: prototypes; rb_autoload, rb_autoload_load, rb_autoload_p. * lib/optparse.rb (OptionParser::Switch::PlacedArgument::parse): do not treat unmatched argument as an option. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'variable.c')
-rw-r--r--variable.c318
1 files changed, 191 insertions, 127 deletions
diff --git a/variable.c b/variable.c
index 0bb456d0c8..3a38a7ca11 100644
--- a/variable.c
+++ b/variable.c
@@ -20,12 +20,14 @@
static st_table *rb_global_tbl;
st_table *rb_class_tbl;
+static ID autoload;
void
Init_var_tables()
{
rb_global_tbl = st_init_numtable();
rb_class_tbl = st_init_numtable();
+ autoload = rb_intern("__autoload__");
}
struct fc_result {
@@ -104,7 +106,6 @@ fc_i(key, value, res)
default:
break;
-
}
return ST_CONTINUE;
}
@@ -129,7 +130,7 @@ find_class_path(klass)
if (arg.path) {
if (!ROBJECT(klass)->iv_tbl) {
ROBJECT(klass)->iv_tbl = st_init_numtable();
- }
+ }
st_insert(ROBJECT(klass)->iv_tbl,rb_intern("__classpath__"),arg.path);
return arg.path;
}
@@ -278,39 +279,6 @@ rb_name_class(klass, id)
rb_iv_set(klass, "__classid__", ID2SYM(id));
}
-static st_table *autoload_tbl = 0;
-
-static void
-rb_autoload_id(id, filename)
- ID id;
- const char *filename;
-{
- rb_secure(4);
- if (!rb_is_const_id(id)) {
- rb_name_error(id, "autoload must be constant name");
- }
-
- if (!autoload_tbl) {
- autoload_tbl = st_init_numtable();
- }
- st_insert(autoload_tbl, id, (st_data_t)strdup(filename));
-}
-
-void
-rb_autoload(klass, filename)
- const char *klass, *filename;
-{
- rb_autoload_id(rb_intern(klass), filename);
-}
-
-VALUE
-rb_f_autoload(obj, klass, file)
- VALUE obj, klass, file;
-{
- rb_autoload_id(rb_to_id(klass), StringValuePtr(file));
- return Qnil;
-}
-
char *
rb_class2name(klass)
VALUE klass;
@@ -669,7 +637,7 @@ struct trace_data {
struct trace_var *trace;
VALUE val;
};
-
+
static VALUE
trace_ev(data)
struct trace_data *data;
@@ -1133,6 +1101,158 @@ rb_obj_remove_instance_variable(obj, name)
return Qnil; /* not reached */
}
+NORETURN(static void uninitialized_constant _((VALUE, ID)));
+static void
+uninitialized_constant(klass, id)
+ VALUE klass;
+ ID id;
+{
+ if (klass && klass != rb_cObject)
+ rb_name_error(id, "uninitialized constant %s::%s",
+ RSTRING(rb_class_path(klass))->ptr,
+ rb_id2name(id));
+ else {
+ rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
+ }
+}
+
+static struct st_table *
+check_autoload_table(av)
+ VALUE av;
+{
+ struct st_table *tbl;
+
+ Check_Type(av, T_DATA);
+ if (RDATA(av)->dmark != (RUBY_DATA_FUNC)rb_mark_tbl ||
+ RDATA(av)->dfree != (RUBY_DATA_FUNC)st_free_table) {
+ rb_raise(rb_eTypeError, "wrong autoload table: %s", RSTRING(rb_inspect(av))->ptr);
+ }
+ return (struct st_table *)DATA_PTR(av);
+}
+
+void
+rb_autoload(mod, id, file)
+ VALUE mod;
+ ID id;
+ const char *file;
+{
+ VALUE av;
+ struct st_table *tbl;
+
+ if (!rb_is_const_id(id)) {
+ rb_raise(rb_eNameError, "autoload must be constant name",
+ rb_id2name(id));
+ }
+ if (!file || !*file) {
+ rb_raise(rb_eArgError, "empty file name");
+ }
+
+ if ((tbl = RCLASS(mod)->iv_tbl) && st_lookup(tbl, id, &av) && av != Qundef)
+ return;
+
+ rb_const_set(mod, id, Qundef);
+ tbl = RCLASS(mod)->iv_tbl;
+ if (st_lookup(tbl, autoload, &av)) {
+ tbl = check_autoload_table(av);
+ }
+ else {
+ av = Data_Wrap_Struct(rb_cData, rb_mark_tbl, st_free_table, 0);
+ st_add_direct(tbl, autoload, av);
+ DATA_PTR(av) = tbl = st_init_numtable();
+ }
+ st_insert(tbl, id, rb_str_new2(file));
+}
+
+static VALUE
+autoload_delete(mod, id)
+ VALUE mod;
+ ID id;
+{
+ VALUE val, file = Qnil;
+
+ if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) {
+ struct st_table *tbl = check_autoload_table(val);
+
+ if (!st_delete(tbl, &id, &file)) file = Qnil;
+
+ if (!tbl->num_entries) {
+ DATA_PTR(val) = 0;
+ st_free_table(tbl);
+ id = autoload;
+ if (st_delete(RCLASS(mod)->iv_tbl, &id, &val)) {
+ rb_gc_force_recycle(val);
+ }
+ }
+ }
+
+ return file;
+}
+
+void
+rb_autoload_load(klass, id)
+ VALUE klass;
+ ID id;
+{
+ VALUE file, value;
+
+ file = autoload_delete(klass, id);
+ if (NIL_P(file)) {
+ uninitialized_constant(klass, id);
+ }
+ if (rb_provided(RSTRING(file)->ptr)) {
+ uninitialized_constant(klass, id);
+ }
+ FL_UNSET(file, FL_TAINT);
+ rb_f_require(Qnil, file);
+}
+
+static VALUE
+autoload_file(mod, id)
+ VALUE mod;
+ ID id;
+{
+ VALUE val, file;
+ struct st_table *tbl;
+
+ if (!st_lookup(RCLASS(mod)->iv_tbl, autoload, &val) ||
+ !(tbl = check_autoload_table(val)) || !st_lookup(tbl, id, &file)) {
+ return Qnil;
+ }
+ Check_Type(file, T_STRING);
+ if (!RSTRING(file)->ptr) {
+ rb_raise(rb_eArgError, "empty file name");
+ }
+ if (!rb_provided(RSTRING(file)->ptr)) {
+ return file;
+ }
+
+ /* already loaded but not defined */
+ st_delete(tbl, &id, 0);
+ if (!tbl->num_entries) {
+ DATA_PTR(val) = 0;
+ st_free_table(tbl);
+ id = autoload;
+ if (st_delete(RCLASS(mod)->iv_tbl, &id, &val)) {
+ rb_gc_force_recycle(val);
+ }
+ }
+ return Qnil;
+}
+
+VALUE
+rb_autoload_p(mod, id)
+ VALUE mod;
+ ID id;
+{
+ struct st_table *tbl = RCLASS(mod)->iv_tbl;
+ VALUE val;
+
+ if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) {
+ return Qnil;
+ }
+ return autoload_file(mod, id);
+}
+
static int
top_const_get(id, klassp)
ID id;
@@ -1140,13 +1260,6 @@ top_const_get(id, klassp)
{
/* pre-defined class */
if (st_lookup(rb_class_tbl, id, klassp)) return Qtrue;
-
- /* autoload */
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
- rb_autoload_load(id);
- *klassp = rb_const_get(rb_cObject, id);
- return Qtrue;
- }
return Qfalse;
}
@@ -1157,36 +1270,20 @@ rb_const_get_at(klass, id)
{
VALUE value;
- if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+ while (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+ if (value == Qundef) {
+ rb_autoload_load(klass, id);
+ continue;
+ }
return value;
}
if (klass == rb_cObject && top_const_get(id, &value)) {
return value;
}
- rb_name_error(id, "uninitialized constant %s::%s",
- RSTRING(rb_class_path(klass))->ptr,
- rb_id2name(id));
+ uninitialized_constant(klass, id);
return Qnil; /* not reached */
}
-void
-rb_autoload_load(id)
- ID id;
-{
- char *modname;
- VALUE module;
-
- st_delete(autoload_tbl, &id, (st_data_t *)&modname);
- if (rb_provided(modname)) {
- free(modname);
- return;
- }
- module = rb_str_new2(modname);
- free(modname);
- FL_UNSET(module, FL_TAINT);
- rb_f_require(Qnil, module);
-}
-
VALUE
rb_const_get(klass, id)
VALUE klass;
@@ -1198,7 +1295,11 @@ rb_const_get(klass, id)
tmp = klass;
retry:
while (tmp) {
- if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
+ while (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
+ if (value == Qundef) {
+ rb_autoload_load(tmp, id);
+ continue;
+ }
return value;
}
if (tmp == rb_cObject && top_const_get(id, &value)) return value;
@@ -1210,15 +1311,7 @@ rb_const_get(klass, id)
goto retry;
}
- /* Uninitialized constant */
- if (klass && klass != rb_cObject) {
- rb_name_error(id, "uninitialized constant %s at %s",
- rb_id2name(id),
- RSTRING(rb_class_path(klass))->ptr);
- }
- else { /* global_uninitialized */
- rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
- }
+ uninitialized_constant(klass, id);
return Qnil; /* not reached */
}
@@ -1237,13 +1330,14 @@ rb_mod_remove_const(mod, name)
if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, &id, &val)) {
+ if (val == Qundef) autoload_delete(mod, id);
return val;
}
if (rb_const_defined_at(mod, id)) {
- rb_name_error(id, "cannot remove %s::%s",
+ rb_name_error(id, "cannot remove %s::%s",
rb_class2name(mod), rb_id2name(id));
}
- rb_name_error(id, "constant %s::%s not defined",
+ rb_name_error(id, "constant %s::%s not defined",
rb_class2name(mod), rb_id2name(id));
return Qnil; /* not reached */
}
@@ -1262,18 +1356,6 @@ sv_i(key, value, tbl)
return ST_CONTINUE;
}
-static int
-autoload_i(key, name, tbl)
- ID key;
- const char *name;
- st_table *tbl;
-{
- if (!st_lookup(tbl, key, 0)) {
- st_insert(tbl, key, key);
- }
- return ST_CONTINUE;
-}
-
void*
rb_mod_const_at(mod, data)
VALUE mod;
@@ -1288,9 +1370,6 @@ rb_mod_const_at(mod, data)
}
if ((VALUE)mod == rb_cObject) {
st_foreach(rb_class_tbl, sv_i, (st_data_t)tbl);
- if (autoload_tbl) {
- st_foreach(autoload_tbl, autoload_i, (st_data_t)tbl);
- }
}
return tbl;
}
@@ -1344,7 +1423,11 @@ rb_const_defined_at(klass, id)
VALUE klass;
ID id;
{
- if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, 0)) {
+ VALUE value;
+
+ if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+ if (value == Qundef && NIL_P(autoload_file(klass, id)))
+ return Qfalse;
return Qtrue;
}
if (klass == rb_cObject) {
@@ -1354,23 +1437,16 @@ rb_const_defined_at(klass, id)
}
int
-rb_autoload_defined(id)
- ID id;
-{
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0))
- return Qtrue;
- return Qfalse;
-}
-
-int
rb_const_defined(klass, id)
VALUE klass;
ID id;
{
- VALUE tmp = klass;
+ VALUE tmp = klass, value;
while (tmp) {
- if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
+ if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl, id, &value)) {
+ if (value == Qundef && NIL_P(autoload_file(klass, id)))
+ return Qfalse;
return Qtrue;
}
tmp = RCLASS(tmp)->super;
@@ -1380,7 +1456,7 @@ rb_const_defined(klass, id)
}
if (st_lookup(rb_class_tbl, id, 0))
return Qtrue;
- return rb_autoload_defined(id);
+ return Qfalse;
}
static void
@@ -1399,9 +1475,14 @@ mod_av_set(klass, id, val, isconst)
RCLASS(klass)->iv_tbl = st_init_numtable();
}
else if (isconst) {
- if (st_lookup(RCLASS(klass)->iv_tbl, id, 0) ||
+ VALUE value = Qfalse;
+
+ if (st_lookup(RCLASS(klass)->iv_tbl, id, &value) ||
(klass == rb_cObject && st_lookup(rb_class_tbl, id, 0))) {
- rb_warn("already initialized %s %s", dest, rb_id2name(id));
+ if (value == Qundef)
+ autoload_delete(klass, id);
+ else
+ rb_warn("already initialized %s %s", dest, rb_id2name(id));
}
}
@@ -1424,7 +1505,7 @@ rb_const_assign(klass, id, val)
VALUE val;
{
VALUE tmp = klass;
-
+
while (tmp) {
if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
st_insert(RCLASS(tmp)->iv_tbl, id, val);
@@ -1439,24 +1520,7 @@ rb_const_assign(klass, id, val)
return;
}
- /* autoload */
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
- char *modname;
-
- st_delete(autoload_tbl, (st_data_t *)&id, (st_data_t *)&modname);
- free(modname);
- st_insert(RCLASS(rb_cObject)->iv_tbl, id, val);
- return;
- }
-
- /* Uninitialized constant */
- if (klass && klass != rb_cObject)
- rb_name_error(id, "uninitialized constant %s::%s",
- RSTRING(rb_class_path(klass))->ptr,
- rb_id2name(id));
- else {
- rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
- }
+ uninitialized_constant(klass, id);
}
void
@@ -1672,7 +1736,7 @@ rb_mod_remove_cvar(mod, name)
return val;
}
if (rb_cvar_defined(mod, id)) {
- rb_name_error(id, "cannot remove %s for %s",
+ rb_name_error(id, "cannot remove %s for %s",
rb_id2name(id), rb_class2name(mod));
}
rb_name_error(id, "class variable %s not defined for %s",