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
Donahue on July 17, 1984 8:42:40 am PDT
Last Edited by: Butler, July 11, 1984 4:34:54 pm PDT
DIRECTORY
DB,
DBNames,
Nut,
Rope,
ViewerOps;
NutImpl: CEDAR MONITOR
IMPORTS DB, DBNames, Rope, ViewerOps
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: NutProc, -- a nut displayer for a domain
edit: NutProc, -- a nut editor for a domain
query: NutProc, -- a nut queryer for a domain
reset: PROC[v: Viewer] ]; -- the reset proc 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;
Exported procedures
Display: PUBLIC ENTRY PROC[eName, domain: ROPE, segment: DB.Segment, parent: Viewer← NIL] RETURNS[v: Viewer] =
BEGIN
ENABLE UNWIND => NULL;
implRec: ImplementationRecord = FindImpl[domain, segment];
lastSpawned: Viewer = IF parent = NIL THEN NIL ELSE GetSpawnedProperty[parent];
IF implRec = NIL THEN RETURN WITH ERROR NoProcRegistered[];
v ← implRec.procList.first.display[eName, domain, segment, lastSpawned ! ABORTED => CONTINUE];
IF v # NIL AND NOT v.destroyed THEN {
[] ← SetSpawnedProperty[parent, v]; IF v.iconic THEN ViewerOps.OpenIcon[v] }
END;
Edit: PUBLIC ENTRY PROC[eName, domain: ROPE, segment: DB.Segment, parent: Viewer← NIL] RETURNS[v: Viewer] =
BEGIN
ENABLE UNWIND => NULL;
implRec: ImplementationRecord = FindImpl[domain, segment];
lastSpawned: Viewer = IF parent = NIL THEN NIL ELSE GetSpawnedProperty[parent];
IF implRec = NIL THEN RETURN WITH ERROR NoProcRegistered[];
v ← implRec.procList.first.edit[eName, domain, segment, lastSpawned ! ABORTED => CONTINUE];
IF v # NIL AND NOT v.destroyed THEN {
[] ← SetSpawnedProperty[parent, v]; IF v.iconic THEN ViewerOps.OpenIcon[v] }
END;
Query: PUBLIC ENTRY PROC[eName, domain: ROPE, segment: DB.Segment, parent: Viewer← NIL] RETURNS[v: Viewer] =
BEGIN
ENABLE UNWIND => NULL;
implRec: ImplementationRecord = FindImpl[domain, segment];
lastSpawned: Viewer = IF parent = NIL THEN NIL ELSE GetSpawnedProperty[parent];
IF implRec = NIL OR implRec.procList.first.query = NIL THEN RETURN WITH ERROR NoProcRegistered[];
v ← implRec.procList.first.query[eName, domain, segment, lastSpawned ! ABORTED => CONTINUE];
IF v # NIL AND NOT v.destroyed THEN {
[] ← SetSpawnedProperty[parent, v]; IF v.iconic THEN ViewerOps.OpenIcon[v] }
END;
Register: PUBLIC ENTRY PROC[domain: ROPE, segment: DB.Segment, display: NutProc ← NIL, edit: NutProc ← NIL, query: NutProc ← NIL, reset: PROC[v: Viewer] ← 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, reset, TRUE];
END;
Push: PUBLIC ENTRY PROC[ domain: ROPE, segment: DB.Segment, display: NutProc ← NIL, edit: NutProc ← NIL, query: NutProc ← NIL, reset: PROC[v: Viewer] ← NIL, register: BOOLEANFALSE] =
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, reset, FALSE]
END;
SetSpawnedProperty: PUBLIC PROC [v: Viewer, new: Viewer] RETURNS [previous: Viewer] ~ {
IF v = NIL OR v.destroyed THEN RETURN[NIL];
previous ← NARROW[ViewerOps.FetchProp[v, $LastSpawned]];
ViewerOps.AddProp[v, $LastSpawned, new]
};
GetSpawnedProperty: PUBLIC PROC [v: Viewer] RETURNS [current: Viewer] ~ {
current ← NARROW[ViewerOps.FetchProp[v, $LastSpawned]];
IF GetFrozenProperty[current] THEN RETURN[NIL] };
SetFrozenProperty: PUBLIC PROC [v: Viewer, new: BOOL] RETURNS [previous: BOOL] ~ {
IF v = NIL THEN RETURN[TRUE]; -- the non-existent viewer is always frozen
{refFrozen: REF BOOL = NARROW[ViewerOps.FetchProp[v, $Frozen]];
IF refFrozen = NIL THEN
{previous ← FALSE; ViewerOps.AddProp[v, $Frozen, NEW[BOOL ← new]] }
ELSE {previous ← refFrozen^; refFrozen^ ← new} }
};
GetNutInfo: PUBLIC PROC[v: Viewer] RETURNS[segment: Segment, domain, entity: ROPE] = {
filePath: Rope.ROPE = NARROW[ViewerOps.FetchProp[v, $SegmentFile]];
entity ← NARROW[ViewerOps.FetchProp[v, $EntityName]];
segment ← NARROW[ViewerOps.FetchProp[v, $Segment]];
domain ← NARROW[ViewerOps.FetchProp[v, $DomainName]];
check to make sure that the segment hasn't mysteriously changed underneath you!!
IF NOT Rope.Equal[filePath, DB.GetSegmentInfo[segment].filePath] THEN RETURN[NIL, NIL, NIL]
};
SetNutInfo: PUBLIC PROC[v: Viewer, segment: Segment, domain, entity: ROPE] = {
ViewerOps.AddProp[v, $EntityName, entity];
ViewerOps.AddProp[v, $Segment, segment];
ViewerOps.AddProp[v, $SegmentFile, DB.GetSegmentInfo[segment].filePath];
ViewerOps.AddProp[v, $DomainName, domain]
};
ChangeName: PUBLIC PROC[v: Viewer, newName: ROPE] = {
ViewerOps.AddProp[v, $EntityName, newName] };
EntityNameForViewer: PUBLIC PROC [v: Viewer] RETURNS [entityName: ROPE] ~ {
segment: DB.Segment;
entity, domain: ROPE;
[segment, domain, entity] ← GetNutInfo[v];
RETURN[DBNames.MakeName[segment, domain, entity]]
};
GetFrozenProperty: PUBLIC PROC [v: Viewer] RETURNS [current: BOOL] ~ {
IF v = NIL THEN RETURN[TRUE]; -- the non-existent viewer is always frozen
{ refFrozen: REF BOOL = NARROW[ViewerOps.FetchProp[v, $Frozen]];
IF refFrozen = NIL THEN current ← FALSE ELSE current ← refFrozen^ }
};
LoadEntry: INTERNAL PROC[ domain: ROPE, segment: DB.Segment, display: NutProc ← NIL, edit: NutProc ← NIL, query: NutProc ← NIL, reset: PROC[v: Viewer] ← NIL, register: BOOLEANFALSE] =
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;
IF reset#NIL THEN implRec.procList.first.reset← reset;
END;
DeRegister: PUBLIC ENTRY PROC[domain: ROPE, segment: DB.Segment] =
Deregisters all procs for this domain
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] =
Deregisters top procs for this domain
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] =
Makes the defaults for the segment be registered as the ones to use.
BEGIN
defaultRec: ImplementationProcRecord← FindImpl[NIL, segment].procList.first;
LoadEntry[domain, segment, defaultRec.display, defaultRec.edit, defaultRec.query, defaultRec.reset, FALSE];
END;
Support procedures
FindImpl: INTERNAL PROC[d: ROPE, seg: Segment] RETURNS[ImplementationRecord] =
Try to find an implementation for domain d in segment seg. If not defined in seg, look for a default entry in seg=NIL then d=NIL and seg=NIL (NIL signifies a wildcard (default). If no defaults are found, return an empty record.
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] =
Looks for an exact match for d and seg. Returns the portion of the implementation list containing that record. If a match is not found, the returned object has NIL as its current field.
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.
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.
Donahue on July 12, 1984:
NutImpl is now a free standing implementation of Nut; it can be run independently of any other piece of Squirrel.