<> <> <> <> DIRECTORY CD, CDBottomUp, CDDirectory, CDEvents, CDProperties; CDBottomUpImpl: CEDAR MONITOR IMPORTS CDDirectory, CDEvents, CDProperties EXPORTS CDBottomUp = BEGIN OPEN CDBottomUp; registration: LIST OF REF ANY _ NIL; <<--these properties must be removed when objects change>> 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_NIL, key: REF_NIL, reRegistrationKey: REF_NIL] RETURNS [class: Class] = BEGIN RegisterProtected: ENTRY PROC [] = { ENABLE UNWIND => NULL; registration _ CONS[key, registration]; }; IF key=NIL THEN key _ NEW[INT]; class _ NEW[ClassRec_[do, reUse, key]]; [] _ CDProperties.RegisterProperty[key, reRegistrationKey]; RegisterProtected[]; END; GetPrivate: ENTRY PROC [key: REF, ob: CD.Object] RETURNS [h: REF PrivateRec] = BEGIN ENABLE UNWIND => NULL; WITH CDProperties.GetPropFromObject[ob, key] SELECT FROM p: REF PrivateRec => h _ p; ENDCASE => CDProperties.PutPropOnObject[ob, key, (h_NEW[PrivateRec])]; END; ObChanged: CDEvents.EventProc = BEGIN ENABLE UNWIND => NULL; WITH x SELECT FROM ob: CD.Object => FOR list: LIST OF REF ANY _ registration, list.rest WHILE list#NIL DO CDProperties.PutPropOnObject[ob, list.first, NIL]; ENDLOOP; ENDCASE => NULL; END; DoRecurse: PUBLIC PROC [handle: Handle, ob: CD.Object] RETURNS [val: REF_NIL, new: BOOL_FALSE] = BEGIN EachChild: CDDirectory.EnumerateObjectsProc = { IF me.class.inDirectory THEN IF DoRecurse[handle, me].new THEN new _ TRUE; }; p: REF PrivateRec; IF ob=NIL THEN ob _ NEW[CD.ObjectRep_handle.design.actual.first.dummyCell.ob^]; --copy, so will not find property again ? 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; CDEvents.RegisterEventProc[$AfterCellReplacement, ObChanged]; END.