-- 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
Last Edited by: Butler, July 11, 1984 4:34: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;
Exported procedures
Display:
PUBLIC
ENTRY
PROC[
eName: ROPE ← NIL,
e: DB.Entity,
d: DB.Domain ← NIL,
seg: DB.Segment ← NIL,
newV: Viewer←
NIL] =
Displays a new nut viewing entity e. If a nut implementation has
-- registered itself for e's type, that implementation will be called,
-- else the standard NutViewer browser will be used.
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] =
Uses newV to edit entity e. If a nut implementation has
-- registered itself for e's type, that implementation will be called,
-- else the standard NutViewer browser will be used.
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] =
Uses newV to query entity e. If a nut implementation has
-- registered itself for e's type, that implementation will be called,
-- else the standard NutViewer browser will be used.
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;
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] =
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.
Mainly for debugging new display et al procs. An implementor
can use this to actually see the things that a specialized displayer
is attempting to display.
BEGIN
defaultRec: ImplementationProcRecord← FindImpl[NIL, segment].procList.first;
LoadEntry[domain, segment, defaultRec.display, defaultRec.edit, defaultRec.query, 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.
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.