object $root;
var $root child = 0;
var $root child_index = 0;
var $root inited = 1;
public method .children(): nooverride {
return children();
};
public method .debug(): nooverride {
arg [what];
dblog("DEBUG: " + what.join(" "));
};
public method .del_objname(): nooverride {
arg name;
(> del_objname(name) <);
};
public method .descendants(): nooverride {
var kids, i, c;
kids = children();
while ((| (c = kids[(i = i + 1)]) |))
kids = union(kids, c.children());
return kids;
};
public method .destroy(): nooverride {
if (!child)
throw(~perm, "Attempt to destroy a defining parent.");
(| .uninitialize() |);
destroy();
};
public method .find_method() {
arg method;
return (> find_method(method) <);
};
private method .initialize(): nooverride {
var ancestors, ancestor, pos, len, method;
if (inited)
throw(~perm, "Already initialized.");
ancestors = ancestors();
len = ancestors.length();
for pos in [0 .. len - 1] {
ancestor = ancestors[len - pos];
method = tosym("init_" + tostr(ancestor.objname('symbol)));
catch ~methodnf {
if ((.find_method(method)) != ancestor)
throw(~perm, ((("Initialization method for " + (ancestor.objname())) + " in wrong place(") + (find_method(method).objname())) + ")");
.(method)();
}
}
inited = 1;
child = 1;
};
public method .log(): nooverride {
arg what;
var line;
if (type(what) == 'string) {
dblog(what);
} else if (type(what) == 'list) {
for line in (what)
.log(line);
} else {
throw(~invarg, "Log must be called with a string or a list of strings");
}
};
public method .objname(): nooverride {
arg [args];
var name;
name = (| objname() |);
if (args)
return name || 0;
if (name)
return "$" + tostr(name);
return toliteral(this());
};
public method .parents(): nooverride {
return parents();
};
public method .set_objname(): nooverride {
arg objname;
if (type(objname) != 'symbol)
throw(~perm, "Name is not a symbol.");
// Make sure everything is lowercase.
objname = tosym(lowercase(tostr(objname)));
// Do nothing if objname isn't different.
if (objname == (| objname() |))
return;
(> set_objname(objname) <);
};
public method .spawn(): nooverride {
arg [other_parents];
var base, obj, name;
// if (child)
// throw(~perm, "Attempt to spawn a non-defining object.");
name = .objname('symbol);
base = tostr(name);
while ((| lookup(name) |)) {
child_index = child_index + 1;
name = tosym((base + "_") + tostr(child_index));
}
obj = (> create([this()] + other_parents) <);
catch any {
(> obj.initialize() <);
} with {
.log($parse_lib.traceback(traceback()));
if (!(| obj.destroy() |))
throw(~ack, "Unable to destroy aborted attempt", traceback());
rethrow(error());
}
(> obj.set_objname(name) <);
return obj;
};
private method .uninitialize(): nooverride {
var ancestor, p;
for ancestor in (ancestors()) {
method = tosym("uninit_" + tostr(ancestor.objname('symbol)));
catch ~methodnf {
if ((.find_method(method)) != ancestor)
throw(~perm, ((("UnInitialization method for " + (ancestor.objname())) + " in wrong place (") + ((.find_method(method)).objname())) + ")");
.(method)();
}
}
for p in (.variables())
.del_var('p);
};
public method .add_method() {
arg code, meth;
return (> add_method(code, meth) <);
};
public method .list_method() {
arg method, @args;
args = [(| args[1] |) || 2, (| args[2] |) || 2];
return (> list_method(method, @args) <);
};
public method .del_method() {
arg name;
return (> del_method(name) <);
};
public method .method_info() {
arg @args;
return (> method_info(@args) <);
};