<<-- File: NutImpl.mesa -- Contents: Implementation of Nut.mesa. -- Created by: Rick Cattell on January, 1982 -- Last edited by: -- Cattell on July 27, 1983 8:14 pm -- Willie-Sue on July 11, 1984 4:22:36 pm PDT -- Widom on June 14, 1984 2:02:54 pm PDT>> <> DIRECTORY DB, MessageWindow USING [ Append ], Nut, NutOps USING [IsSystemDomain, IsSystemEntity, SafeDomainOf, SafeNameOf, SafeSegmentOf], NutViewer USING [SpawnViewer, Message], Rope, ViewerOps; NutImpl: CEDAR MONITOR IMPORTS DB, Rope, ViewerOps, MessageWindow, NutOps, NutViewer EXPORTS Nut = BEGIN OPEN Nut, DB; -- Types and global variables implementations: PUBLIC ImplementationList _ NIL; ImplementationProcList: TYPE = LIST OF ImplementationProcRecord _ NIL; ImplementationProcRecord: TYPE = REF ImplementationProcRecordObject; ImplementationProcRecordObject: TYPE = RECORD[ display: ProcType, -- a nut displayer for a domain edit: ProcType, -- a nut editor for a domain query: ProcType]; -- a nut queryer for a domain ImplementationList: TYPE = LIST OF ImplementationRecord _ NIL; ImplementationRecord: TYPE = REF ImplementationRecordObject; ImplementationRecordObject: TYPE = RECORD[ domain: ROPE, -- name of domain segment: DB.Segment, -- the segment of the domain procList: ImplementationProcList]; -- stack of procedures for this domain PlaceRecord: TYPE = REF PlaceRecordObject; PlaceRecordObject: TYPE = RECORD[ previous: ImplementationList, current: ImplementationList, next: ImplementationList]; NoProcRegistered: PUBLIC ERROR = CODE; <> Display: PUBLIC ENTRY PROC[ eName: ROPE _ NIL, e: DB.Entity, d: DB.Domain _ NIL, seg: DB.Segment _ NIL, newV: Viewer_ NIL] = <> BEGIN ENABLE UNWIND => { IF newV # NIL THEN ViewerOps.DestroyViewer[newV] }; IF Null[e] THEN {MessageWindow.Append["Entity has been deleted!"]; RETURN}; IF d = NIL THEN d _ NutOps.SafeDomainOf[e]; IF eName = NIL THEN eName _ NutOps.SafeNameOf[e]; IF newV = NIL THEN newV _ NutViewer.SpawnViewer[eName, e, d, seg]; IF newV = NIL THEN RETURN ELSE BEGIN IF d = NIL THEN d _ NutOps.SafeDomainOf[e]; BEGIN dName: ROPE = NutOps.SafeNameOf[d]; segment: DB.Segment = IF DB.IsSystemEntity[e] THEN seg ELSE NutOps.SafeSegmentOf[e]; implRec: ImplementationRecord = FindImpl[dName, segment]; IF implRec = NIL THEN RETURN WITH ERROR NoProcRegistered[]; newV.newVersion _ TRUE; ViewerOps.PaintViewer[newV, caption]; implRec.procList.first.display[eName, d, segment, newV ! ABORTED => CONTINUE]; newV.newVersion _ FALSE; ViewerOps.PaintViewer[newV, caption]; END; END; END; Edit: PUBLIC ENTRY PROC[ eName: ROPE, e: DB.Entity _ NIL, d: Domain, seg: DB.Segment _ NIL, newV: Viewer_ NIL] = <> BEGIN ENABLE UNWIND => { IF newV # NIL THEN ViewerOps.DestroyViewer[newV] }; IF NutOps.IsSystemEntity[e] THEN BEGIN [] _ NutViewer.Message[NIL, eName, " is a system entity. You may not edit it."]; RETURN; END; IF newV = NIL THEN newV _ NutViewer.SpawnViewer[eName, e, d, seg]; IF newV = NIL THEN RETURN ELSE BEGIN dName: ROPE = GetName[d]; segment: DB.Segment = IF NutOps.IsSystemDomain[d] THEN seg ELSE NutOps.SafeSegmentOf[d]; implRec: ImplementationRecord = FindImpl[dName, segment]; IF implRec = NIL THEN RETURN WITH ERROR NoProcRegistered[]; newV.newVersion _ TRUE; ViewerOps.PaintViewer[newV, caption]; implRec.procList.first.edit[eName, d, segment, newV ! ABORTED => CONTINUE]; newV.newVersion _ FALSE; ViewerOps.PaintViewer[newV, caption]; END; END; Query: PUBLIC ENTRY PROC[ eName: ROPE _ NIL, e: DB.Entity _ NIL, d: Domain, seg: DB.Segment _ NIL, newV: Viewer_ NIL] = <> BEGIN ENABLE UNWIND => { IF newV # NIL THEN ViewerOps.DestroyViewer[newV] }; IF eName = NIL THEN eName _ NutOps.SafeNameOf[e]; IF NutOps.IsSystemEntity[e] THEN BEGIN [] _ NutViewer.Message[NIL, eName, " is a system entity. You may not query it."]; RETURN; END; IF newV = NIL THEN newV _ NutViewer.SpawnViewer[eName, e, d, seg]; IF newV = NIL THEN RETURN ELSE BEGIN dName: ROPE = GetName[d]; segment: DB.Segment = IF NutOps.IsSystemDomain[d] THEN seg ELSE NutOps.SafeSegmentOf[d]; implRec: ImplementationRecord = FindImpl[dName, seg]; IF implRec = NIL THEN RETURN WITH ERROR NoProcRegistered[]; implRec.procList.first.query[eName, d, segment, newV ! ABORTED => CONTINUE]; END; END; Register: PUBLIC ENTRY PROC[ domain: ROPE, segment: DB.Segment, display: ProcType_ NIL, edit: ProcType_ NIL, query: ProcType_ NIL] = <<--Registers a display, create, query, and/or notify proc for given domain. These will -- supersede any previous non-NIL registrations for this domain.>> BEGIN LoadEntry[domain, segment, display, edit, query, TRUE]; END; Push: PUBLIC ENTRY PROC[ domain: ROPE, segment: DB.Segment, display: ProcType_ NIL, edit: ProcType_ NIL, query: ProcType_ NIL, register: BOOLEAN _ FALSE] = <<--Registers a display, create, query, and/or notify proc for given domain. These will -- supersede any previous non-NIL registrations for this domain.>> BEGIN LoadEntry[domain, segment, display, edit, query, FALSE] END; LoadEntry: INTERNAL PROC[ domain: ROPE, segment: DB.Segment, display: ProcType_ NIL, edit: ProcType_ NIL, query: ProcType_ NIL, register: BOOLEAN _ FALSE] = <<--Actually inserts new records into the implementation list>> BEGIN implRec: ImplementationRecord_ FindImpl[domain, segment]; IF implRec = NIL THEN BEGIN implRec _ NEW[ImplementationRecordObject]; implRec.domain _ domain; implRec.segment _ segment; implRec.procList _ CONS[ NEW[ImplementationProcRecordObject], NIL]; implementations _ CONS[ implRec, implementations ]; END; IF ~register THEN implRec.procList _ CONS[ NEW[ImplementationProcRecordObject], implRec.procList ]; IF display#NIL THEN implRec.procList.first.display_ display; IF edit#NIL THEN implRec.procList.first.edit_ edit; IF query#NIL THEN implRec.procList.first.query_ query; END; DeRegister: PUBLIC ENTRY PROC[domain: ROPE, segment: DB.Segment] = <> BEGIN placeRec: PlaceRecord _ FindPlace[domain, segment]; IF placeRec.previous = NIL THEN implementations_ placeRec.next ELSE placeRec.previous.rest _ placeRec.next; END; Pop: PUBLIC ENTRY PROC[domain: ROPE, segment: DB.Segment] = <> BEGIN placeRec: PlaceRecord _ FindPlace[domain, segment]; IF placeRec.current # NIL THEN BEGIN procRec: ImplementationProcRecord _ placeRec.current.first.procList.first; IF placeRec.current.first.procList.rest = NIL THEN IF placeRec.previous = NIL THEN implementations _ placeRec.next ELSE placeRec.previous.rest _ placeRec.next ELSE placeRec.current.first.procList _ placeRec.current.first.procList.rest; END; END; PushDefaults: PUBLIC ENTRY PROC[domain: ROPE, segment: DB.Segment] = <> BEGIN defaultRec: ImplementationProcRecord_ FindImpl[NIL, segment].procList.first; LoadEntry[domain, segment, defaultRec.display, defaultRec.edit, defaultRec.query, FALSE]; END; <> FindImpl: INTERNAL PROC[d: ROPE, seg: Segment] RETURNS[ImplementationRecord] = <> BEGIN placeRec: PlaceRecord; IF (placeRec _ FindPlace[d, seg]).current = NIL THEN BEGIN implRec: ImplementationRecord; IF (placeRec _ FindPlace[d, NIL]).current = NIL THEN IF (placeRec _ FindPlace[NIL, NIL]).current = NIL THEN RETURN[NIL]; implRec _ NEW[ImplementationRecordObject]; implRec.domain _ d; implRec.segment _ seg; implRec.procList _ CONS[ NEW[ImplementationProcRecordObject], NIL]; implRec.procList.first^ _ placeRec.current.first.procList.first^; implementations _ CONS[ implRec, implementations ]; RETURN[implRec]; END; RETURN[placeRec.current.first]; END; FindPlace: INTERNAL PROC[d: ROPE, seg: Segment] RETURNS[PlaceRecord] = <> <> <> BEGIN placeRec: PlaceRecord _ NEW[PlaceRecordObject]; placeRec.current _ implementations; FOR iL: ImplementationList _ implementations, iL.rest UNTIL iL=NIL DO placeRec.previous _ placeRec.current; placeRec.current _ iL; placeRec.next _ iL.rest; IF Rope.Equal[iL.first.domain, d] AND (seg = iL.first.segment) THEN RETURN[placeRec]; ENDLOOP; placeRec.current _ NIL; RETURN[placeRec]; END; END. Change Log: Cattell on January 16, 1984 12:12 pm: passing NIL in for segment when registering means will take any segment. Butler on June 4, 1984: Users can register their own defaults. They are no longer built in. NIL in the place of the domain and/or segment will register a default for a domain and/or segment. Change Log: Cattell on January 16, 1984 12:12 pm: passing NIL in for segment when registering means will take any segment. Butler on June 4, 1984: Users can register their own defaults. They are no longer built in. NIL in the place of the domain and/or segment will register a default for a domain and/or segment. Butler on June 26, 1984: Major Revision of code has been completed. Dependencies between Squirrel and Nut and whiteboards have been altered. Nut is now independent of Squirrel. The creation of all viewers is now done through NutViewer.