<> <> <> <> DIRECTORY CD, CDBottomUp, CDDirectory, CDImports, 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] = { 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, enumerateChildren: EnumChildsProc_NIL, key: REF, reRegistrationKey: REF, classData: REF, xDesign: BOOL] RETURNS [class: Class] = { IF key=NIL THEN key _ NEW[INT]; class _ NEW[ClassRec _ [do, reUse, enumerateChildren, key, classData, xDesign]]; [] _ 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, ob: CD.Object, design: CD.Design, 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.EachObjectProc = { IF me.class.composed THEN IF DoRecurse[handle, me].new THEN new _ TRUE; }; p: REF PrivateRec; IF ob=NIL THEN { IF handle.design=NIL THEN ERROR; [] _ CDDirectory.EnumerateDesign[handle.design, EachChild]; RETURN; }; p _ GetPrivate[handle.class.key, ob]; IF handle.invocation=p.lastInvocation THEN RETURN [p.lastVal, handle.invocation=p.originalInvocation]; IF handle.class.enumerateChildren#NIL THEN [] _ handle.class.enumerateChildren[me: ob, proc: EachChild, data: handle] ELSE [] _ CDDirectory.EnumerateChildObjects[me: ob, proc: EachChild, data: handle]; IF ob.class.xDesign AND handle.class.xDesign THEN { WITH ob.specific SELECT FROM ip: CDImports.ImportSpecific => IF ip.boundOb#NIL AND ip.boundOb.class.composed THEN { h: Handle _ MakeHandle[handle.class, ip.boundDesign, handle.data, handle.invocation]; IF DoRecurse[h, ip.boundOb].new THEN new _ TRUE } ENDCASE => ERROR; }; 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.