<> <> <> <> DIRECTORY CD, CDBottomUp, CDDirectory, CDOps, CDProperties; CDBottomUpImpl: CEDAR MONITOR IMPORTS CDDirectory, CDOps, CDProperties EXPORTS CDBottomUp = BEGIN OPEN CDBottomUp; PrivateRec: TYPE = RECORD [ lastInvocation: REF_NIL, lastVal: REF_NIL, originalInvocation: REF_NIL ]; <<--passed through invocations are never NIL: a NIL invocation means value not yet computed>> MakeHandle: PUBLIC PROC [class: Class, design: CD.Design, data: REF_NIL, invocation: REF_NIL] RETURNS [handle: Handle] = { handle _ NEW[HandleRec_[ class: class, design: design, data: data, invocation: IF invocation#NIL THEN invocation ELSE NEW[INT] ]]; }; Register: PUBLIC PROC[do: DoProc, reUse: ReUseProc, key: REF, reRegistrationKey: REF, classData: REF] RETURNS [class: Class] = { IF key=NIL THEN key _ NEW[INT]; class _ NEW[ClassRec _ [do, reUse, key, classData]]; [] _ CDProperties.RegisterProperty[key, reRegistrationKey]; CDProperties.InstallProcs[key, [autoRem: TRUE]]; }; Peek: PUBLIC PROC [key: REF, ob: CD.Object] RETURNS [val: REF_NIL] = { WITH CDProperties.GetObjectProp[ob, key] SELECT FROM p: REF PrivateRec => val _ p.lastVal; ENDCASE => NULL; }; StartRecurse: PUBLIC PROC [class: Class, design: CD.Design, ob: CD.Object, data: REF_NIL] RETURNS [val: REF, new: BOOL, handle: Handle] = { handle _ MakeHandle[class, design, data]; [val, new] _ DoRecurse[handle, ob]; }; DoRecurse: PUBLIC PROC [handle: Handle, ob: CD.Object] RETURNS [val: REF_NIL, new: BOOL_FALSE] = { GetPrivate: PROC [key: REF, ob: CD.Object] RETURNS [h: REF PrivateRec] = INLINE { WITH CDProperties.GetObjectProp[ob, key] SELECT FROM p: REF PrivateRec => h _ p; ENDCASE => CDProperties.PutObjectProp[ob, key, (h_NEW[PrivateRec])]; }; EachChild: CDDirectory.EnumerateObjectsProc = { IF me.class.inDirectory THEN IF DoRecurse[handle, me].new THEN new _ TRUE; }; EachDirectoryEntry: CDDirectory.EachEntryAction = { IF DoRecurse[handle, ob].new THEN new _ TRUE; }; p: REF PrivateRec; IF ob=NIL THEN { IF handle.design=NIL THEN ERROR; [] _ CDDirectory.Enumerate[handle.design, EachDirectoryEntry]; <<--check also real instances in case silly user violates directory invarinces>> FOR il: CD.InstanceList _ CDOps.InstList[handle.design], il.rest WHILE il#NIL DO IF il.first.ob.class.inDirectory THEN IF DoRecurse[handle, il.first.ob].new THEN new _ TRUE ENDLOOP; RETURN; --the pushed in levels are not delt with... }; p _ GetPrivate[handle.class.key, ob]; IF handle.invocation=p.lastInvocation THEN RETURN [p.lastVal, handle.invocation=p.originalInvocation]; CDDirectory.EnumerateChildObjects[me: ob, p: EachChild, x: handle]; new _ new OR p.lastInvocation=NIL; IF ~new AND handle.class.reUse#NIL THEN { new _ handle.class.reUse[handle, ob, p.lastVal].shouldDoAain }; IF new THEN { p.lastVal _ handle.class.do[handle, ob]; p.originalInvocation _ handle.invocation; }; p.lastInvocation _ handle.invocation; RETURN [p.lastVal, new]; }; END.