[Indigo]<Rosemary>®>Rosemary.DF=>RoseCreateImplB.Mesa
Last Edited by: Spreitzer, May 2, 1985 12:51:29 pm PDT
DIRECTORY Asserting, Basics, IO, OrderedSymbolTableRef, PrincOps, Rope, RoseCreate, RoseEvents, RoseTypes;
RoseCreateImplB: CEDAR PROGRAM
IMPORTS Asserting, IO, OSTR: OrderedSymbolTableRef, Rope, RoseCreate, RoseEvents, RoseTypes
EXPORTS RoseCreate =
BEGIN OPEN RoseCreate, RoseTypes;
cellTypes: SymbolTable ← OSTR.CreateTable[CompareCellTypes];
RegisterCellType: PUBLIC PROC
[
incrementally: BOOLFALSE,
Identification:
name: ROPE,
Structure:
expandProc: ExpandProc ← NIL,
Behavior:
ioCreator: IOCreator ← NIL,
driveCreator: DriveCreator ← NIL,
initializer: Initializer ← NIL,
evals: EvalProcs ← [],
tests: CellTestList ← NIL,
Other:
ports: Ports,
typeData: REF ANYNIL,
other: Assertions ← NIL
]
RETURNS [type: CellType] =
BEGIN
replace: BOOL = NOT incrementally;
conformingInterface, equalInterface: BOOLFALSE;
oldHadBehavior: BOOLFALSE;
newHasBehavior: BOOL ← evals.EvalSimple # NIL OR evals.PropUD # NIL;
simpleWordCount, switchWordCount: CARDINAL ← 0;
hasASwitchPort: BOOLFALSE;
FOR portIndex: PortIndex IN [0 .. ports.length) DO
port: Port ← ports[portIndex];
simpleWordCount ← MAX[simpleWordCount, MinSize[port.simple]];
switchWordCount ← MAX[switchWordCount, MinSize[port.switch]];
IF port.type = NIL THEN ERROR Error[IO.PutFR["No NodeType given for Port %g", IO.rope[port.name]]];
IF NOT port.type.simple THEN hasASwitchPort ← TRUE;
ENDLOOP;
type ← NARROW[cellTypes.Lookup[name]];
IF type = NIL THEN {
type ← NEW [CellTypeRep ← [name: name, testers: OSTR.CreateTable[CompareTests]]];
cellTypes.Insert[type];
}
ELSE {
[conformingInterface, equalInterface] ← EqualInterfaces[ports, type.ports];
oldHadBehavior ← type.evals.EvalSimple # NIL OR type.evals.PropUD # NIL;
};
IF type.firstInstance # NIL THEN {
firstLeaf: BOOLTRUE;
IF NOT incrementally THEN ERROR Error["Can't forget about instances", type];
IF NOT conformingInterface THEN ERROR Error["Can't change interface structure of existing instances", type];
FOR instance: Cell ← type.firstInstance, instance.nextInstance WHILE instance # NIL DO
IF instance.type # type THEN ERROR;
IF instance.expansion = Leaf THEN {
IF firstLeaf THEN {
firstLeaf ← FALSE;
IF NOT oldHadBehavior THEN ERROR;
IF NOT newHasBehavior THEN ERROR Error["Can't relieve existing instances of behavior", type];
IF NOT equalInterface THEN ERROR Error["Can't change interface of existing instances", type];
};
IF instance.realCellStuff.evals # type.evals THEN ERROR;
instance.realCellStuff.evals ← evals;
};
ENDLOOP;
};
type.ports ← ports;
IF NOT equalInterface THEN {
type.simpleWordCount ← simpleWordCount;
type.switchWordCount ← switchWordCount;
type.hasASwitchPort ← hasASwitchPort;
};
IF replace OR expandProc # NIL THEN type.expand ← expandProc;
IF replace OR ioCreator # NIL THEN type.ioCreator ← ioCreator;
IF replace OR driveCreator # NIL THEN type.driveCreator ← driveCreator;
IF replace OR initializer # NIL THEN type.initializer ← initializer;
IF replace OR evals # [] THEN type.evals ← evals;
IF replace OR typeData # NIL THEN type.typeData ← typeData;
IF incrementally
THEN type.other ← Asserting.Union[other, type.other]
ELSE type.other ← other;
IF NOT incrementally THEN type.testers.DeleteAllItems[];
FOR tests ← tests, tests.rest WHILE tests # NIL DO
[] ← SetTest[test: NEW [CellTestRep ← tests.first], of: type, mayOverwriteOld: incrementally];
ENDLOOP;
END;
GetCellType: PUBLIC PROC [name: ROPE] RETURNS [type: CellType] =
{type ← NARROW[cellTypes.Lookup[name]]};
GetTest: PUBLIC PROC [name: ROPE, from: CellType] RETURNS [t: CellTest] =
{t ← NARROW[from.testers.Lookup[name]]};
SetTest: PUBLIC PROC [test: CellTest, of: CellType, mayOverwriteOld: BOOLFALSE] RETURNS [old: CellTest] = {
old ← NARROW[of.testers.Lookup[test]];
IF old # NIL THEN {
IF mayOverwriteOld
THEN {IF of.testers.Delete[test] # old THEN ERROR}
ELSE ERROR Error[IO.PutFR["Duplicate Test (named %g) given for cell type %g", IO.rope[test.name], IO.rope[of.name]]];
};
of.testers.Insert[test];
};
EqualInterfaces: PUBLIC PROC [a, b: Ports] RETURNS [structurally, fully: BOOL] = {
structurally ← fully ← a.length = b.length;
FOR portIndex: PortIndex IN [0 .. a.length) WHILE structurally DO
IF NOT (
Conforming[a[portIndex].type, b[portIndex].type] AND
a[portIndex].input = b[portIndex].input AND
a[portIndex].output = b[portIndex].output AND
a[portIndex].name.Equal[b[portIndex].name]
)
THEN structurally ← fully ← FALSE;
IF NOT (
FieldEqual[a[portIndex].simple, b[portIndex].simple] AND
FieldEqual[a[portIndex].switch, b[portIndex].switch] AND
a[portIndex].type = b[portIndex].type AND
a[portIndex].XPhobic = b[portIndex].XPhobic
)
THEN fully ← FALSE;
ENDLOOP;
};
CreateSim: PUBLIC PROC [steady: BOOL] RETURNS [sim: Simulation] = {
sim ← NEW [SimulationRep ← [steady: steady]];
RoseEvents.Notify[event: $NewSim, handleAborted: TRUE, arg: sim];
};
Possible: PUBLIC PROC [cell: Cell, whatToDo: ExpandDecision] RETURNS [possible: BOOLEAN] =
BEGIN
evalable: BOOL ← cell.type.evals.EvalSimple # NIL OR cell.type.evals.PropUD # NIL;
iok: BOOL ← (cell.type.simpleWordCount = 0 AND cell.type.switchWordCount = 0) OR cell.type.ioCreator # NIL;
RETURN [SELECT whatToDo FROM
Leaf => evalable AND iok,
Expand => cell.type.expand # NIL,
ENDCASE => ERROR];
END;
XPhobicize: PUBLIC PROC [n: Node] RETURNS [m: Node-- = n --] =
{(m ← n).XPhobic ← TRUE};
EnumerateConnections: PUBLIC PROC [asRope: ROPE, to: PROC [key: Key, nodeName: ROPE]] = {
index: CARDINAL ← 0;
in: IO.STREAMIO.RIS[asRope];
[] ← in.GetIndex[]; --wake up generic GetIndex impl
FOR i: NAT ← in.SkipWhitespace[], in.SkipWhitespace[] WHILE NOT in.EndOf[] DO
nodeName: ROPE ← GetName[in];
[] ← in.SkipWhitespace[];
IF (NOT in.EndOf[]) AND (in.PeekChar[] = ':) THEN {
portName: ROPE ← nodeName;
IF in.GetChar[] # ': THEN ERROR;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN ERROR Error[IO.PutFR["Interface spec syntax error, at %g", IO.int[in.GetIndex[]]]];
nodeName ← GetName[in];
to[[keyword[portName]], nodeName];
}
ELSE {
to[[position[index]], nodeName];
};
index ← index + 1;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN EXIT;
IF in.GetChar[] # ', THEN ERROR Error[IO.PutFR["Interface spec syntax error (missing comma?), at %g", IO.int[in.GetIndex[]]]];
ENDLOOP;
in.Close[];
};
FillInInterfaceNodes: PUBLIC PROC [cell: Cell, interfaceNodes: ROPE] =
BEGIN
PerConnection: PROC [key: Key, nodeName: ROPE] = {
portName: ROPE;
portIndex: PortIndex;
WITH key SELECT FROM
x: Key.position => {
IF x.index >= cell.interfaceNodes.length THEN ERROR Error[IO.PutFR["No %g'th element in %g's Interface", IO.int[x.index], IO.rope[cell.type.name]]];
portName ← cell.type.ports[portIndex ← x.index].name;
};
x: Key.keyword => {
IF (portIndex ← GetIndex[cell.type.ports, portName ← x.name]) = notFound THEN ERROR Error[IO.PutFR["No such port (%g) for CellType %g", IO.rope[portName], IO.rope[cell.type.name]]];
};
ENDCASE => ERROR;
IF cell.interfaceNodes[portIndex] # NIL THEN ERROR Error[IO.PutFR["Port %g specified twice in \"%g\"", IO.rope[portName], IO.rope[interfaceNodes]]];
cell.interfaceNodes[portIndex] ← LookupCellNode[cell.parent, nodeName];
IF cell.interfaceNodes[portIndex] = NIL THEN ERROR Error[IO.PutFR["Node %g not found", IO.rope[nodeName]]];
IF NOT Conforming[cell.interfaceNodes[portIndex].type, cell.type.ports[portIndex].type] THEN ERROR InterfaceMismatch[
cell: cell,
index: portIndex,
expected: cell.type.ports[portIndex].type,
got: cell.interfaceNodes[portIndex].type];
};
EnumerateConnections[interfaceNodes, PerConnection];
FOR portIndex: PortIndex IN [0 .. cell.interfaceNodes.length) DO
IF cell.interfaceNodes[portIndex] = NIL THEN
BEGIN
nodeName: ROPE ← cell.type.ports[portIndex].name;
cell.interfaceNodes[portIndex] ← LookupCellNode[cell.parent, nodeName];
IF cell.interfaceNodes[portIndex] = NIL THEN ERROR Error[IO.PutFR["Port %g not specified in \"%g\"", IO.rope[nodeName], IO.rope[interfaceNodes]]];
END;
ENDLOOP;
END;
GetName: PROC [from: IO.STREAM] RETURNS [name: ROPE] = {
first: CHAR ← from.PeekChar[];
SELECT first FROM
'" => name ← from.GetRopeLiteral[];
ENDCASE => name ← from.GetTokenRope[IDBreak].token;
};
IDBreak: IO.BreakProc =
{RETURN [SELECT char FROM
IO.SP, IO.CR, IO.LF, IO.TAB => sepr,
',, ': => break,
ENDCASE => other]};
MinSize: PROC [f: Field] RETURNS [words: CARDINAL] = {
words ← f.wordOffset + (INTEGER[f.bitOffset] + f.bitCount + Basics.bitsPerWord - 1)/Basics.bitsPerWord;
};
FieldEqual: PROC [f1, f2: Field] RETURNS [eq: BOOL] =
{eq ← f1 = f2};
CompareRopes: PUBLIC PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
ToKey: SAFE PROC [ref: REF ANY] RETURNS [ROPE] =
{RETURN [WITH ref SELECT FROM r: ROPE => r, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
CompareComponents: PUBLIC PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
ToKey: SAFE PROC [ref: REF ANY] RETURNS [ROPE] =
{RETURN [WITH ref SELECT FROM
r: ROPE => r, c: Cell => c.name, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
CompareNodes: PUBLIC PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
k1, k2: ROPE;
WITH r1 SELECT FROM
r: ROPE => k1 ← r;
n: Node => k1 ← n.name;
ENDCASE => ERROR;
k2 ← WITH r2 SELECT FROM
r: ROPE => r,
n: Node => n.name,
ENDCASE => ERROR;
RETURN [k1.Compare[k2]];
END;
CompareCellTypes: PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
ToKey: SAFE PROC [ref: REF ANY] RETURNS [ROPE] =
{RETURN [WITH ref SELECT FROM
r: ROPE => r, ct: CellType => ct.name, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
CompareTests: PROC [r1, r2: REF ANY] RETURNS [Basics.Comparison] --OSTR.CompareProc-- =
BEGIN
ToKey: SAFE PROC [ref: REF ANY] RETURNS [ROPE] =
{RETURN [WITH ref SELECT FROM
r: ROPE => r, a: CellTest => a.name, ENDCASE => ERROR]};
RETURN [ToKey[r1].Compare[ToKey[r2]]];
END;
END.