LichenRead.Mesa
Last Edited by: Spreitzer, July 15, 1985 7:40:30 pm PDT
DIRECTORY
Asserting USING [Assertions, Assertion, Terms, RelnOf, TermsOf, ToAssertions, Assert, Test],
AssertingIO, Atom, Basics, DFUtilities, FS, IO, LichenDataStructure, LichenOps, List, RedBlackTree, RedBlackTreeExtras, Rope;
LichenRead: CEDAR PROGRAM
IMPORTS Asserting, AssertingIO, Atom, DFUtilities, FS, IO, LichenDataStructure, LichenOps, List, RedBlackTree, RedBlackTreeExtras, Rope
EXPORTS LichenOps =
BEGIN OPEN Asserting, LichenDataStructure, LichenOps;
DFTest: PROC [dfName: ROPE] =
BEGIN
PerItem: PROC [item: REF ANY] RETURNS [stop: BOOLFALSE] =
{Log["%g\n", IO.refAny[item]]};
from: IO.STREAMFS.StreamOpen[dfName];
Log["\nTesting DF file %g\n", IO.rope[dfName]];
DFUtilities.ParseFromStream[in: from, proc: PerItem, filter: [comments: TRUE]];
from.Close[];
Log["\nDone testing DF file %g\n", IO.rope[dfName]];
END;
EasyOpen: PROC [fileName: ROPE] RETURNS [stream: IO.STREAM] =
{stream ← FS.StreamOpen[fileName]};
ReadDesign: PROC [dfName: ROPE, keepAll: BOOLFALSE] RETURNS [design: Design] =
BEGIN
NonGrok: PROC [context: REF ANY, source: Source, assn: Assertion] = {
WITH context SELECT FROM
design: Design => {
CheckIgnore[source, LIST[RelnOf[assn], $Design]];
IF keepAll THEN design.other ← CONS[assn, design.other];
};
cellType: CellType => {
CheckIgnore[source, LIST[RelnOf[assn], $CellType, $Design]];
IF keepAll THEN Warn[source, "Can't represent assertion %g about %g's name", IO.refAny[assn], IO.rope[GlobalCellTypeName[cellType]]];
};
ENDCASE => ERROR;
};
ReadFrom: PROC [dfName: ROPE, usingList: REF DFUtilities.UsingList] =
BEGIN
assns: Assertions ← NIL;
dir, dfShort: ROPENIL;
s: Source;
DiscardAssns: PROC =
{FOR assns ← assns, assns.rest WHILE assns # NIL DO NonGrok[design, s, assns.first] ENDLOOP};
DesignAssns: PROC =
{FOR assns ← assns, assns.rest WHILE assns # NIL DO
WITH RelnOf[assns.first] SELECT FROM
a: ATOM => SELECT a FROM
$Design, $CreatingUser, $CreationTime, $CreationSite, $Version, $DerivingProgram, $Source => NULL --absorb accounting information, because it'll become invalid--;
$DesignName => {r: ROPENARROW[TermsOf[assns.first].first];
design.name ← r};
ENDCASE => NonGrok[design, s, assns.first];
ENDCASE => NonGrok[design, s, assns.first];
ENDLOOP};
PerItem: PROC [item: REF ANY] RETURNS [stop: BOOLFALSE] =
BEGIN
WITH item SELECT FROM
di: REF DFUtilities.DirectoryItem => {dir ← di.path1; DesignAssns[]};
fi: REF DFUtilities.FileItem => {
verless: ROPE ← DFUtilities.RemoveVersionNumber[dir.Cat[fi.name]];
IF NOT DFUtilities.SearchUsingList[file: verless, list: usingList].found THEN assns ← NIL
ELSE {
typeName: Naming ← ["?"];
ct: CellType ← NIL;
FOR assns ← assns, assns.rest WHILE assns # NIL DO
assn: Assertion ← assns.first;
WITH RelnOf[assn] SELECT FROM
a: ATOM => SELECT a FROM
$CellType => {
IF ct # NIL THEN Warn[s, "Multiple CellTypes for file %g in %g", IO.rope[fi.name], IO.rope[dfName]];
ct ← NEW [CellTypeRep ← [design: design, names: [], file: verless]];
typeName ← [NARROW[TermsOf[assn].first]];
FOR ctnas: Assertions ← ToAssertions[TermsOf[assn].rest], ctnas.rest WHILE ctnas # NIL DO
ctna: Assertion ← ctnas.first;
WITH RelnOf[ctna] SELECT FROM
ia: ATOM => SELECT a FROM
$G => typeName ← AddG[typeName, ctna, LIST[$CellType, $Design], ct];
$A => typeName ← AddA[typeName, ctna, LIST[$CellType, $Design], ct];
ENDCASE => NonGrok[ct, s, ctna];
ENDCASE => NonGrok[ct, s, ctna];
ENDLOOP;
};
ENDCASE => NonGrok[design, s, assn];
ENDCASE => NonGrok[design, s, assn];
ENDLOOP;
IF ct # NIL THEN {
ct.names ← NamingNames[typeName];
AddCellType[ct];
}
ELSE {
IF NOT dfShort.Equal[fi.name, FALSE] THEN Warn[s, "Non-understood file entry: %g", IO.rope[fi.name]];
};
};
};
ii: REF DFUtilities.ImportsItem => {ReadFrom[ii.path1, IntUL[usingList, ii.list]]; DiscardAssns[]};
ii: REF DFUtilities.IncludeItem => {ReadFrom[ii.path1, usingList]; DiscardAssns[]};
ci: REF DFUtilities.CommentItem => assns ← AddAssn[ci.text, assns];
wi: REF DFUtilities.WhiteSpaceItem => NULL;
ENDCASE => ERROR;
END;
IF usingList = NIL OR usingList.nEntries > 0 THEN {
from: IO.STREAMFS.StreamOpen[dfName];
cp: FS.ComponentPositions;
dfFull: ROPE;
s ← [from, dfName];
[dfFull, cp, ] ← FS.ExpandName[dfName];
dfShort ← dfFull.Substr[start: cp.base.start, len: cp.ext.start+cp.ext.length-cp.base.start];
DFUtilities.ParseFromStream[in: from, proc: PerItem, filter: [comments: TRUE]];
from.Close[];
};
END;
cp: FS.ComponentPositions;
fullDFName: ROPE;
[fullDFName, cp, ] ← FS.ExpandName[dfName];
design ← NEW [DesignRep ← [
name: fullDFName.Substr[start: cp.base.start, len: cp.base.length],
cellTypesByName: RedBlackTree.Create[GetAliasKey, CompareAliases],
cellTypesByAddress: RedBlackTree.Create[GetIDKey, CompareByAddress],
allKept: keepAll
]];
ReadFrom[dfName: dfName, usingList: NIL];
END;
AddCellType: PUBLIC PROC [ct: CellType] = {
Insert[ct.design.cellTypesByName, ct.names, ct];
ct.design.cellTypesByAddress.Insert[ct, ct];
};
AddAssn: PROC [comment: ROPE, assns: Assertions] RETURNS [with: Assertions] = {
in: IO.STREAMIO.RIS[comment];
char: CHAR;
assn: Assertion;
[] ← in.SkipWhitespace[flushComments: FALSE];
IF (char ← in.GetChar[]) # '- THEN ERROR;
IF (char ← in.GetChar[]) # '- THEN ERROR;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN RETURN [assns];
IF (char ← in.GetChar[]) = '^ THEN {
IF in.EndOf[] THEN RETURN [assns];
char ← in.GetChar[];
};
IF char # '( THEN RETURN [assns];
in.Backup['(];
assn ← AssertingIO.ReadAssn[in];
with ← CONS[assn, assns];
in.Close[];
};
IntUL: PROC [a, b: REF DFUtilities.UsingList] RETURNS [c: REF DFUtilities.UsingList] = {
IF a = NIL AND b = NIL THEN RETURN [NIL];
IF b = NIL THEN RETURN [a];
DFUtilities.SortUsingList[b];
IF a = NIL THEN RETURN [b];
c ← NEW [DFUtilities.UsingList[MIN[a.nEntries, b.nEntries]]];
c.nEntries ← 0;
FOR i: NAT IN [0 .. a.nEntries) DO
found: BOOL ← DFUtilities.SearchUsingList[file: a[i].name, list: b].found;
IF found THEN {c[c.nEntries] ← a[i]; c.nEntries ← c.nEntries + 1};
ENDLOOP;
c ← c;
};
ReadCellType: PROC [ct: CellType, privateToo: BOOL] =
BEGIN
from: IO.STREAM;
currentlyPrivate: BOOLFALSE;
s: Source;
IF ct.publicKnown AND (ct.privateKnown OR NOT privateToo) THEN RETURN;
s ← [from ← FS.StreamOpen[ct.file], ct.file];
DO
assn: Assertion;
NonGrok: PROC = {
CheckIgnore[s, LIST[RelnOf[assn], $CellType]];
IF NOT ct.design.allKept THEN NULL
ELSE IF currentlyPrivate THEN ct.otherPrivate ← CONS[assn, ct.otherPrivate]
ELSE ct.otherPublic ← CONS[assn, ct.otherPublic]};
[] ← from.SkipWhitespace[];
IF from.EndOf[] THEN EXIT;
assn ← AssertingIO.ReadAssn[from];
WITH RelnOf[assn] SELECT FROM
a: ATOM => SELECT a FROM
$PrivateFollows => {IF currentlyPrivate THEN Warn[s, "(PrivateFollows) seen more than once"]; currentlyPrivate ← TRUE};
ENDCASE;
ENDCASE;
IF currentlyPrivate AND NOT privateToo THEN EXIT;
IF ct.publicKnown AND NOT currentlyPrivate THEN LOOP;
WITH RelnOf[assn] SELECT FROM
a: ATOM => SELECT a FROM
$PrivateFollows => NULL;
$CreatingUser, $CreationTime, $CreationSite, $Version, $DerivingProgram, $Source => NULL --absorb old audit trail--;
$CellTypeName => {naming: Naming ← [NARROW[TermsOf[assn].first]];
FOR ctnas: Assertions ← ToAssertions[TermsOf[assn].rest], ctnas.rest WHILE ctnas # NIL DO
ctna: Assertion ← ctnas.first;
NonRep: PROC = {
CheckIgnore[s, LIST[RelnOf[ctna], $CellTypeName, $CellType]];
IF ct.design.allKept THEN Warn[s, "Cant' represent assertion %g about %g's name", IO.refAny[ctna], IO.rope[GlobalCellTypeName[ct]]];
};
WITH RelnOf[ctna] SELECT FROM
ia: ATOM => SELECT ia FROM
$G => naming ← AddG[naming, ctna, LIST[$CellTypeName, $CellType], ct];
$A => naming ← AddA[naming, ctna, LIST[$CellTypeName, $CellType], ct];
ENDCASE => NonRep[];
ENDCASE => NonRep[];
ENDLOOP;
InsistSameNames[ct.names, NamingNames[naming], ct.design];
};
$EC => {reln: ROPENARROW[TermsOf[assn].first];
equivClass: ROPENARROW[TermsOf[assn].rest.first];
IF NOT reln.Equal["Structure"] THEN {
CheckIgnore[s, LIST[Atom.MakeAtom[reln], $EC, $CellType]];
IF NOT ct.design.allKept THEN NULL
ELSE IF currentlyPrivate THEN ct.otherPrivate ← CONS[assn, ct.otherPrivate]
ELSE ct.otherPublic ← CONS[assn, ct.otherPublic];
}
ELSE IF ct.equivClass = implicitClass THEN ct.equivClass ← equivClass
ELSE IF NOT equivClass.Equal[ct.equivClass] THEN Warn[s, "Multiple %g equivalence classes for %g: %g and %g", IO.rope[reln], IO.rope[GlobalCellTypeName[ct]], IO.rope[ct.equivClass], IO.rope[equivClass]];
};
$Ports => ReadPorts[ct, assn];
$PN => {
portName: ROPENARROW[TermsOf[assn].first];
netName: ROPENARROW[TermsOf[assn].rest.first];
portIndex: NAT ← FindPort[ct.ports, portName];
IF portIndex = notFound THEN Warn[s, "CellType %g has no port named %g", IO.rope[GlobalCellTypeName[ct]], IO.refAny[portName]]
ELSE ct.ports[portIndex].netNames ← CONS[netName, ct.ports[portIndex].netNames];
};
$N => ReadNet[ct, assn];
$CI => ReadCellInstance[ct, assn];
$InsidesUnspecified => {
IF ct.parts # NIL THEN Warn[s, "Unspecified insides were specified for cell type %g", IO.rope[GlobalCellTypeName[ct]]];
};
ENDCASE => NonGrok[];
ENDCASE => NonGrok[];
ENDLOOP;
IF ct.parts # NIL AND ct.mirror = NIL THEN AddWorld[ct];
ct.publicKnown ← TRUE;
ct.privateKnown ← privateToo;
from.Close[];
IF ExpansionKnown[ct] THEN {
FOR pi: NAT IN [0 .. ct.ports.length) DO
net: Vertex ← NIL;
FOR nnl: RopeList ← ct.ports[pi].netNames, nnl.rest WHILE nnl # NIL DO
n: Vertex ← NARROW[Lookup[ct.parts, nnl.first]];
SELECT TRUE FROM
n = NIL => Err[[], "No net %g in cell type %g", IO.refAny[nnl.first], IO.rope[GlobalCellTypeName[ct]]];
net = NIL => net ← n;
net # n => Err[[], "Multiple nets connected to port %g", IO.rope[GlobalPortName[ct, pi]]];
ENDCASE;
ENDLOOP;
ENDLOOP;
};
END;
InsistSameNames: PROC [n1, n2: Names, design: Design] = {
st: SymbolTable ← RedBlackTree.Create[GetAliasKey, CompareAliases];
inBoth, in1, in2: ROPENIL;
Add: PROC [rl: RopeList, ns: ATOM] = {
FOR rl ← rl, rl.rest WHILE rl # NIL DO
a: Alias ← NEW [AliasRep ← [name: rl.first, thing: ns]];
st.Insert[a, a.name];
ENDLOOP;
};
Remove: PROC [rl: RopeList, ns: ATOM] = {
FOR rl ← rl, rl.rest WHILE rl # NIL DO
n: RedBlackTree.Node ← st.Delete[rl.first];
SELECT TRUE FROM
n = NIL => in2 ← AddName[in2, rl.first];
n # NIL => inBoth ← AddName[inBoth, rl.first];
ENDCASE => ERROR;
ENDLOOP;
};
NoteRest: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
a: Alias ← NARROW[ra];
in1 ← AddName[in1, a.name];
stop ← FALSE;
};
AddName: PROC [r, n: ROPE] RETURNS [nr: ROPE] = {
SELECT TRUE FROM
r = NIL => nr ← n;
r # NIL => nr ← r.Cat[", ", n];
ENDCASE => ERROR;
};
Add[n1.designed, $D];
Add[n1.unknown, $U];
Add[n1.progged, $P];
Remove[n2.designed, $D];
Remove[n2.unknown, $U];
Remove[n2.progged, $P];
st.EnumerateIncreasing[NoteRest];
IF in1 # NIL OR in2 # NIL THEN {
Warn[[], "In design %g, CellType certainly named (%g) also named (%g) in DF file only and (%g) in cell file only", IO.rope[design.name], IO.rope[inBoth], IO.rope[in1], IO.rope[in2]];
};
};
ReadCellInstance: PROC [ct: CellType, assn: Assertion] = {
instanceName: ROPENARROW[TermsOf[assn].first];
typeName: ROPENARROW[TermsOf[assn].rest.first];
instanceType: CellType ← NARROW[Lookup[ct.design.cellTypesByName, typeName]];
cv: Vertex;
naming: Naming ← [instanceName];
IF ct.parts = NIL THEN {
ct.parts ← RedBlackTree.Create[GetAliasKey, CompareAliases];
};
IF ct.mirror = NIL THEN AddWorld[ct];
cv ← NEW [VertexRep ← [
names: [],
type: instanceType,
parent: ct,
class: cell]];
FOR cial: Assertions ← ToAssertions[TermsOf[assn].rest.rest], cial.rest WHILE cial # NIL DO
cia: Assertion ← cial.first;
NonGrok: PROC = {
CheckIgnore[[], LIST[RelnOf[cia], $CI, $CellType]];
IF ct.design.allKept THEN cv.other ← CONS[cia, cv.other];
};
WITH RelnOf[cia] SELECT FROM
a: ATOM => SELECT a FROM
$G => naming ← AddG[naming, cia, LIST[$CI, $CellType], cv];
$A => naming ← AddA[naming, cia, LIST[$CI, $CellType], cv];
$CIC => {
portIndex: NAT ← 0;
EnsurePorts[instanceType];
FOR cicl: LORA ← TermsOf[cia], cicl.rest WHILE cicl # NIL DO
cic: LORANARROW[cicl.first];
portName: ROPENARROW[cic.first];
netName: ROPENARROW[cic.rest.first];
net: Vertex ← NARROW[Lookup[ct.parts, netName]];
IF NOT NamesInclude[instanceType.ports[portIndex].names, portName] THEN Err[[], "Cell instance connections not in order on %g.%g", IO.rope[GlobalCellTypeName[ct]], IO.rope[instanceName]];
Connect[cv, net, portIndex];
IF cic.rest.rest # NIL THEN Warn[[], "Extra cell instance connection info for %g.%g.%g", IO.rope[GlobalCellTypeName[ct]], IO.refAny[instanceName], IO.refAny[portName]];
portIndex ← portIndex + 1;
ENDLOOP;
IF portIndex # instanceType.ports.length THEN Warn[[], "Extra cell instance connections for %g.%g", IO.rope[GlobalCellTypeName[ct]], IO.refAny[instanceName]];
};
ENDCASE => NonGrok[];
ENDCASE => NonGrok[];
ENDLOOP;
cv.names ← NamingNames[naming];
AddVertex[cv];
LinkInstance[cv];
};
AddWorld: PUBLIC PROC [ct: CellType] =
BEGIN
cv: Vertex;
IF ct.ports = NIL THEN ERROR;
ct.mirror ← cv ← NEW [VertexRep ← [names: [NIL, NIL, LIST[MirrorName]], type: ct, parent: ct, class: cell]];
AddVertex[cv]; --AM1
LinkInstance[cv]; --AM2
FOR i: CARDINAL IN [0 .. ct.ports.length) DO
port: Port ← ct.ports[i];
nv: Vertex ← NARROW[Lookup[ct.parts, ct.ports[i].netNames.first]];
Connect[cv, nv, i];
ENDLOOP;
END;
ReadNet: PROC [ct: CellType, assn: Assertion] = {
netName: ROPENARROW[TermsOf[assn].first];
nv: Vertex ← NEW [VertexRep ← [names: [], parent: ct, class: net]];
naming: Naming ← [netName];
IF ct.parts = NIL THEN {
ct.parts ← RedBlackTree.Create[GetAliasKey, CompareAliases];
};
FOR nal: Assertions ← ToAssertions[TermsOf[assn].rest], nal.rest WHILE nal # NIL DO
na: Assertion ← nal.first;
NonGrok: PROC = {
CheckIgnore[[], LIST[RelnOf[na], $N, $CellType]];
IF ct.design.allKept THEN nv.other ← CONS[na, nv.other];
};
WITH RelnOf[na] SELECT FROM
a: ATOM => SELECT a FROM
$G => naming ← AddG[naming, na, LIST[$N, $CellType], nv];
$A => naming ← AddA[naming, na, LIST[$N, $CellType], nv];
ENDCASE => NonGrok[];
ENDCASE => NonGrok[];
ENDLOOP;
nv.names ← NamingNames[naming];
AddVertex[nv];
};
AddG: PROC [in: Naming, assn: Assertion, context: LORA, owner: REF ANY] RETURNS [out: Naming] = {
gener: ATOMNARROW[TermsOf[assn].first];
out ← in;
IF RelnOf[assn] # $G THEN ERROR;
IF out.first = NIL THEN ERROR;
SELECT gener FROM
$D => out.designed ← CONS[out.first, out.designed];
$P => out.progged ← CONS[out.first, out.progged];
ENDCASE => {
CheckIgnore[[], CONS[gener, CONS[$G, context]]];
IF KeepAll[owner] THEN Warn[[], "Unable to represent assertion %g about %g's name", IO.refAny[assn], IO.rope[GlobalName[owner, out]]];
};
out.first ← NIL;
};
AddA: PROC [in: Naming, assn: Assertion, context: LORA, owner: REF ANY] RETURNS [out: Naming] = {
out ← in;
context ← CONS[$A, context];
IF RelnOf[assn] # $A THEN ERROR;
FOR aliasList: LORA ← TermsOf[assn], aliasList.rest WHILE aliasList # NIL DO
alias: LORANARROW[aliasList.first];
newName: ROPENARROW[alias.first];
known, designed: BOOLFALSE;
FOR aal: Assertions ← ToAssertions[alias.rest], aal.rest WHILE aal # NIL DO
aa: Assertion ← aal.first;
NonRep: PROC [firstArg: BOOL] = {
ctx: LORACONS[RelnOf[aa], context];
IF firstArg THEN ctx ← CONS[TermsOf[aa].first, ctx];
CheckIgnore[[], ctx];
IF KeepAll[owner] THEN Warn[[], "Unable to represent assertion %g about name %g of %g", IO.refAny[aa], IO.rope[newName], IO.rope[GlobalName[owner, out]]];
};
WITH RelnOf[aa] SELECT FROM
a: ATOM => SELECT a FROM
$G => {gener: ATOMNARROW[TermsOf[aa].first];
SELECT gener FROM
$D => designed ← known ← TRUE;
$P => designed ← NOT (known ← TRUE);
ENDCASE => NonRep[TRUE];
};
ENDCASE => NonRep[FALSE];
ENDCASE => NonRep[FALSE];
ENDLOOP;
SELECT TRUE FROM
NOT known => out.unknown ← CONS[newName, out.unknown];
designed => out.designed ← CONS[newName, out.designed];
ENDCASE => out.progged ← CONS[newName, out.progged];
ENDLOOP;
};
NamingNames: PUBLIC PROC [naming: Naming] RETURNS [names: Names] = {
names ← [designed: ReverseRopeList[naming.designed], unknown: ReverseRopeList[naming.unknown], progged: ReverseRopeList[naming.progged]];
IF naming.first # NIL THEN names.unknown ← CONS[naming.first, names.unknown];
};
ReverseRopeList: PROC [inHead: RopeList] RETURNS [outHead: RopeList] = {
cur: RopeList ← inHead;
prev: RopeList ← NIL;
WHILE cur # NIL DO
next: RopeList ← cur.rest;
cur.rest ← prev;
prev ← cur;
cur ← next;
ENDLOOP;
outHead ← prev;
};
ReadPorts: PROC [ct: CellType, assn: Assertion] = {
len: NAT ← List.Length[TermsOf[assn]];
i: NAT ← 0;
s: Socket ← NEW [SocketRep ← [ct, NullPortIndex]];
IF ct.ports # NIL THEN ERROR;
ct.ports ← NEW [PortSeq[len]];
FOR psl: LORA ← TermsOf[assn], psl.rest WHILE psl # NIL DO
portSpec: LORANARROW[psl.first];
naming: Naming ← [NARROW[portSpec.first]];
ct.ports[i] ← [];
s.portIndex ← i;
FOR pal: Assertions ← ToAssertions[portSpec.rest], pal.rest WHILE pal # NIL DO
pa: Assertion ← pal.first;
NonGrok: PROC = {
CheckIgnore[[], LIST[RelnOf[pa], $Ports, $CellType]];
IF ct.design.allKept THEN ct.ports[i].other ← CONS[pa, ct.ports[i].other];
};
WITH RelnOf[pa] SELECT FROM
paa: ATOM => SELECT paa FROM
$EC => {
reln: ROPENARROW[TermsOf[pa].first];
equivClass: ROPENARROW[TermsOf[pa].rest.first];
IF reln.Equal["Structure"] THEN {
IF ct.ports[i].equivClass = implicitClass THEN ct.ports[i].equivClass ← equivClass
ELSE IF NOT ct.ports[i].equivClass.Equal[equivClass] THEN Warn[[], "Multiple Sturcture equivalence classes for port %g : %g and %g", IO.rope[GlobalPortName[ct, i]], IO.refAny[ct.ports[i].equivClass], IO.refAny[equivClass]];
};
};
$G => naming ← AddG[naming, pa, LIST[$Ports, $CellType], s];
$A => naming ← AddA[naming, pa, LIST[$Ports, $CellType], s];
ENDCASE => NonGrok[];
ENDCASE => NonGrok[];
ENDLOOP;
ct.ports[i].names ← NamingNames[naming];
i ← i + 1;
ENDLOOP;
IF i # len THEN ERROR;
};
Connect: PUBLIC PROC [cv, nv: Vertex, portIndex: PortIndex] =
BEGIN
e: Edge ← NEW [EdgeRep ← [
sides: [net: [nv, NIL, nv.lastEdge], cell: [cv, NIL, cv.lastEdge]],
color: noColor,
portIndex: portIndex]];
IF nv.lastEdge # NIL THEN nv.lastEdge.sides[net].next ← e ELSE nv.firstEdge ← e;
IF cv.lastEdge # NIL THEN cv.lastEdge.sides[cell].next ← e ELSE cv.firstEdge ← e;
nv.lastEdge ← cv.lastEdge ← e;
END;
EnsureAllIn: PUBLIC PROC [design: Design] = {
PerType: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
ct: CellType ← NARROW[ra];
EnsureParts[ct];
stop ← FALSE};
IF design.allKnown THEN RETURN;
design.allKnown ← TRUE;
RedBlackTreeExtras.StatelessEnumerateIncreasing[design.cellTypesByAddress, PerType, GetIDKey];
};
EnsurePorts: PUBLIC PROC [ct: CellType] = {
IF NOT ct.publicKnown THEN ReadCellType[ct, FALSE];
IF ct.ports = NIL THEN ERROR;
};
EnsureParts: PUBLIC PROC [ct: CellType] = {
IF NOT ct.privateKnown THEN ReadCellType[ct, TRUE];
};
ExpansionKnown: PUBLIC PROC [ct: CellType] RETURNS [known: BOOL] = {
known ← ct.parts # NIL OR ct.asArray # NIL;
};
GetInternalStyle: PUBLIC PROC [ct: CellType] RETURNS [is: InternalStyle] = {
is ← SELECT TRUE FROM
ct.asArray # NIL => array,
ct.parts # NIL => graph,
ENDCASE => ERROR;
};
NoteChange: PUBLIC PROC [ct: CellType] = {
IF NOT (ct.publicKnown AND ct.privateKnown) THEN ERROR;
ct.file ← NIL;
ct.inittedFor ← 0;};
WriteAll: PUBLIC PROC [when: ROPE, a, b: CellType, hashTable: HashTable] =
BEGIN
Log["\n%g\n", IO.rope[when]];
WriteHashTable[hashTable];
WriteSymbolTable["A", a.parts];
WriteSymbolTable["B", b.parts];
Log["\nDone %g\n", IO.rope[when]];
END;
WriteHashTable: PROC [hashTable: HashTable] =
BEGIN
Log["\nHashTable:\n"];
FOR hti: HashTableIndex ← hashTable.firstNonEmpty, hashTable[hti].nextNonEmpty WHILE hti # NullIndex DO
hte: HashTableEntry ← hashTable[hti];
Log["%05d %4g %4g", IO.card[hti], IO.card[hte.count[A]], IO.card[hte.count[B]]];
Log[" %05d %5g %5g", IO.card[hte.newColor], IO.bool[hte.multicolored], IO.bool[hte.suspect]];
FOR v: Vertex ← hte.v, v.colorNext WHILE v # NIL DO
Log[" %g.%g", IO.rope[graphIDToRope[v.graph]], IO.rope[PickAName[v.names]]];
ENDLOOP;
Log["\n"];
ENDLOOP;
END;
WriteSymbolTable: PROC [graphID: ROPE, vertices: SymbolTable] =
BEGIN
WriteVertex: PROC [any: REF ANY] RETURNS [stop: BOOL] =
BEGIN
a: Alias ← NARROW[any];
v: Vertex ← NARROW[a.thing];
stop ← FALSE;
IF PickAName[v.names] # a.name THEN RETURN;
Log["(%05d)\t%05d\t%5g\t%5g\t%12g", IO.card[v.oldColor], IO.card[v.curColor], IO.bool[v.unique], IO.bool[v.suspect], IO.rope[PickAName[v.names]]];
IF v.equiv # NIL THEN Log["\t%g\n", IO.rope[PickAName[v.equiv.names]]] ELSE Log["\n"];
END;
Log["\nGraph %g vertices:\n", IO.rope[graphID]];
vertices.EnumerateIncreasing[WriteVertex];
END;
ignorable: Asserting.Assertions ← NIL;
CheckIgnore: PROC [source: Source, what: LORA] = {
IF NOT Asserting.Test[what.first, what.rest, ignorable] THEN Warn[source, "Unknown assertion %g", IO.refAny[what]];
};
AddIgnorance: PROC [spec: LORA, context: LORA] = {
FOR spec ← spec, spec.rest WHILE spec # NIL DO
WITH spec.first SELECT FROM
a: ATOM => ignorable ← Asserting.Assert[a, context, ignorable];
l: LORA => AddIgnorance[l.rest, CONS[l.first, context]];
ENDCASE => ERROR;
ENDLOOP;
};
Start: PROC = {
ignoreSpec: LORANARROW[FS.StreamOpen["Lichen.ignorable"].GetRefAny[]];
AddIgnorance[ignoreSpec, NIL];
};
Start[];
END.