<> <> <> <> DIRECTORY CD, CDBottomUp, CDDirectory, CDProperties; CDBottomUpImpl: CEDAR MONITOR IMPORTS CDDirectory, 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] = BEGIN handle _ NEW[HandleRec_[ class: class, design: design, data: data, invocation: IF invocation#NIL THEN invocation ELSE NEW[INT] ]]; END; Register: PUBLIC PROC[do: DoProc, reUse: ReUseProc, key: REF, reRegistrationKey: REF, classData: REF] RETURNS [class: Class] = BEGIN IF key=NIL THEN key _ NEW[INT]; class _ NEW[ClassRec _ [do, reUse, key, classData]]; [] _ CDProperties.RegisterAndInstall[key, [autoRem: TRUE], reRegistrationKey]; END; Peek: PUBLIC PROC [key: REF, ob: CD.Object] RETURNS [val: REF_NIL] = BEGIN WITH CDProperties.GetObjectProp[ob, key] SELECT FROM p: REF PrivateRec => val _ p.lastVal; ENDCASE => NULL; END; StartRecurse: PUBLIC PROC [class: Class, design: CD.Design, ob: CD.Object, data: REF_NIL] RETURNS [val: REF, new: BOOL, handle: Handle] = BEGIN handle _ MakeHandle[class, design, data]; [val, new] _ DoRecurse[handle, ob]; END; DoRecurse: PUBLIC PROC [handle: Handle, ob: CD.Object] RETURNS [val: REF_NIL, new: BOOL_FALSE] = BEGIN 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; }; p: REF PrivateRec; IF ob=NIL THEN --copy, so will not find property again ? ob _ NEW[CD.ObjectRep_handle.design.actual.first.dummyCell.ob^]; 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; END.