/********************************************************************* * Classes */ name *persistent = (name *)[]; struct object self() { return (object)where(/ParentDictArray); } shared_class class() { root *d = ParentDictArray; return (shared_class)d[length(d)-1]; } root *superclasses() { shared_class c = class; return (plugin_class *)append(c.superclasses,[c]); } root *classes() { root *d = (root *)ParentDictArray; int len = length(d), n; n = collapse ? 2 : (length(d[len-1].superclasses) + 1); return (root *)getinterval(d,len-n,n); } boolean understands(name method) { return where(method); } boolean descendantof(name classnm) { plugin_class c; for (c = class.superclass ; c && (c.classname != classnm) ; c = c.superclass); return c != null; } /********************************************************************* * Naming */ name nm = null; persist(nm); char *namestr() { return sprintf("%(%)",[classname,nm ? nm : cvn("")]); } boolean rename(name n) { char *str; object p; if (n == nm) return true; if ((length(str = cvs(n,string(128))) <= 1) || (str[0] != '@')) return false; if (!(p = @parent)) { nm = n; return true; } if (n && p.understands(n)) return false; if (nm) { undef(p,nm); unpromote(/nm); } if (n) p[nm = n] = self; return true; } void newname0(object p) { name n; if (p) { do { n = cvn(append("@",cvs(cvi(random() * 1000),string(4)))); } while(p.understands(n)); p[nm = n] = self; } } void newname() { object p; if (p = @parent) { if (nm) undef(p,nm); newname0(p); } } object find_name(name address) { if (where(address)) return (object)(EXEC(address)[0]); else return null; } object find_path(name *path) { object obj; if (length(path) <= 1) return self; if (obj = find_name(path[1])) return obj.find_path((name *)tailinterval(path,1)); return null; } object find_object(any address) { name *a; object o; switch (truedicttype(address)) { case /packedarraytype: case /arraytype: if (length(a = (name *)address)) if (o = find_object(a[0])) return o.find_path(a); else return null; else return self; case /hntype: return (object)address; case /nametype: return find_name((name)address); default: return null; } } /********************************************************************* * Hierarchy */ object *members = (object *)[]; persist(members); object *parents() { dicttype *d = ParentDictArray; return (object *)getinterval(d,0,length(d)-length(classes)); } object @parent() { object *p = parents; int n = length(p); return (n > 0) ? p[n-1] : null; } boolean rooted() { return length(ParentDictArray) > length(classes); } void reparent(object *newparents) { object m, *p; ParentDictArray = (root *)append(newparents,classes); if (length(members)) { p = (object *)append(newparents,[soften(self)]); forall (; m ; members) m.reparent(p); } m = @parent; if (nm && (!m.understands(nm))) m[nm] = self; else newname0(m); } void initmember(object m) { m.reparent((object *)append(parents,[soften(self)])); m.oninit(); } void addmember(object m) { members = (object *)append(members,[m]); initmember(m); } object newmember(name classnm) { plugin_class c; shared_class sc; object m; c = class_mgr.find_class(classnm); sc = c.new("",""); m = (object)sc.new(); addmember(m); return m; } void removemember(object m) { int i; if ((i = arrayindex(members,m)) < 0) return; m.reparent((object *)[]); members = (object *)arraydelete(members,i); return; } void delmember(object m) { removemember(m); m.destroy(); } boolean setscript(char *pdb, char *ps) { shared_class c; root *cs; dicttype d; any k; if (!(c = class.superclass.new(pdb,ps))) return false; d = growabledict; forall(; k ;persistent) d[k] = null; d[/ParentDictArray] = null; forall(k;;self) if (!known(d,k)) undef(self,k); cs = classes; cs[length(cs)-1] = c; oninit(); return true; } /********************************************************************* * Initialization */ void OnInit() { } void oninit() { object m; forall(; m ; members) m.oninit(); QSend(OnInit); } /********************************************************************* * Variable management */ void promote(name var, any val) { self[var] = val; } void softpromote(name var, any val) { unpromote(var); if ((!where(var)) || (!cmp(load(var),val))) promote(var,val); } void unpromote(name var) { undef(self,var); } boolean promoted(name var) { return known(self,var); } boolean scoped(name var) { dicttype d; return (!(d = where(var))) || arraycontains(parents,d); } /******************************************************************** * House keeping */ void destroy() { object m; forall(; m ; members) m.destroy(); cleanoutdict(self); } void obsolete() { } /******************************************************************** * Delivering Messages */ persist(logging); void deliver_self(name message) { currentprocess.ErrorDetailLevel = 1; if (logging) stopped(cvx(/log_message)); if (stopped(cvx(message))) { if (ps_error && ps_error.newerror) { stopped(cvx(/handle_error)); ps_error.newerror = false; } } } void deliver_parent(name message) { @parent.deliver(message); } void deliver(name message) { if (where(message)) deliver_self(message); else deliver_parent(message); } void doit(any thing) { exec(cvx(thing)); }