CoreConnectImpl.mesa
Copyright c 1986 by Xerox Corporation. All rights resersed.
Last Edited by: Curry, August 20, 1986 5:40:38 pm PDT
DIRECTORY Core, CoreClasses, CoreConnect, CoreGlue, CoreName, CoreOps, CoreFrame, HashTable, IO, Rope;
CoreConnectImpl: CEDAR PROGRAM
IMPORTS CoreFrame, CoreName, CoreOps, HashTable, IO, Rope
EXPORTS CoreConnect
~ BEGIN
ROPE:  TYPE = Core.ROPE;
Path:  TYPE = LIST OF INT; -- [bottom .. top]
Addr:  TYPE = LIST OF INT; -- [top .. bottom]
CtxRec: TYPE = RECORD[addr: Addr, cnt: INT];
NodeContext:  TYPE = REF NodeContextRec;
NodeContextRec: TYPE = RECORD[
root: Core.CellType,
table: HashTable.Table];
Signal: SIGNAL = CODE;
log:  IO.STREAM ← CoreFrame.GetLog[];
Connect: PUBLIC PROC [frameCT: Core.CellType] RETURNS[success: BOOLTRUE] = {
ctx: NodeContext ← NEW[ NodeContextRec ← [
root: frameCT,
table: HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope ] ] ];
ConnectNodes[ctx];
CheckPublic[ctx];
success ← CheckConnects[frameCT];
success ← CheckForSingles[ctx];
LogFrame[frameCT, wireLogger];
LogFrame[frameCT, frameLogger];
};
ConnectNodes: PROC [
ctx:  NodeContext,
frameCT: Core.CellType ← NIL,
path:  Path    ← NIL ] = {
frame:   CoreFrame.Frame ← FCT[IF frameCT=NIL THEN ctx.root ELSE frameCT];
hereRef: Addr ← PathToAddr[path];
eachWire: CoreOps.EachWireProc = {
name:  ROPE ← CoreName.WireNm[wire].n;
IF wire=NIL   THEN Signal[];
IF wire.size#0  THEN RETURN;
IF name.Length[]=0 THEN RETURN;
eachWireRp[name]};
eachWireRp: PROC[name: ROPE] = {
probe:  Core.CellType;
start:  Core.CellType ← ctx.root;
oldRef: REF CtxRec ← NARROW[HashTable.Fetch[ctx.table, name].value];
old:  Addr ← NIL;
here:  Addr ← hereRef;
new:  Path ← NIL;
IF oldRef=NIL THEN {
frame.intOnly ← AddItem[name, frame.intOnly];
[]←HashTable.Store[ctx.table, name, NEW[CtxRec ← [here, 1]]];
RETURN };
old ← oldRef.addr;
DO
IF here=NIL OR old=NIL THEN EXIT;
IF here.first # old.first THEN EXIT;
new ← CONS[here.first, new];
start ← FCT[start].seq[here.first];
here ← here.rest;
old ← old.rest;
ENDLOOP;
oldRef.addr ← PathToAddr[new];
oldRef.cnt ← oldRef.cnt+1;
FCT[start].intOnly ← AddItem[name, FCT[start].intOnly];
probe ← start;
IF old#NIL THEN {
FOR old ← old, old.rest WHILE old#NIL DO
probe   ← FCT[probe].seq[old.first];
FCT[probe].public ← AddItem[name, FCT[probe].public];
ENDLOOP;
FCT[probe].intOnly ← RemoveItem[name, FCT[probe].intOnly] };
probe ← start;
FOR here ← here, here.rest WHILE here#NIL DO
probe   ← FCT[probe].seq[here.first];
FCT[probe].public ← AddItem[name, FCT[probe].public];
ENDLOOP };
IF frame.cell#NIL
THEN [ ] ← CoreOps.VisitWire[frame.cell.public, eachWire]
ELSE IF frame.seq.size#0
THEN FOR i: INT IN [0..frame.seq.size)
DO ConnectNodes[ctx, frame.seq[i], CONS[i, path]] ENDLOOP
ELSE IF frame.data=NIL OR NOT ISTYPE[frame.data, CoreGlue.Glue]
THEN Signal[]
ELSE FOR pubs: LIST OF ROPE ← frame.public, pubs.rest WHILE pubs#NIL
DO [ ] ← eachWireRp[pubs.first] ENDLOOP};
CheckPublic: PROC [ctx: NodeContext] = {
FOR public: LIST OF ROPEFCT[ctx.root].public, public.rest WHILE public#NIL DO
oldRef: REF CtxRec ← NARROW[HashTable.Fetch[ctx.table, public.first].value];
probe:  Core.CellType;
old:  Addr ← oldRef.addr;
probe ← ctx.root;
IF oldRef=NIL
THEN log.PutF["\n WARNING, %g's public: %g not exported by children",
IO.rope[CoreName.CellNm[ctx.root].n],
IO.rope[public.first] ]
ELSE{
FOR old: Addr ← oldRef.addr, old.rest WHILE old#NIL DO
probe   ← FCT[probe].seq[old.first];
FCT[probe].public ← AddItem[public.first, FCT[probe].public];
ENDLOOP;
oldRef.cnt ← oldRef.cnt+1;
oldRef.addr ← NIL};
FCT[probe].intOnly ← RemoveItem[public.first, FCT[probe].intOnly];
ENDLOOP};
This picks up on unnamed publics generated by extractor
CheckConnects: PROC [frameCT: Core.CellType] RETURNS[ok: BOOLTRUE] = {
frame: CoreFrame.Frame ← FCT[frameCT];
IF frame.seq.size=0
THEN { -- expect no intOnlys and publics match
count:  INT ← 0;
compare: INT ← 0;
data:  CoreClasses.RecordCellType ← NARROW[frame.cell.data];
FOR lst: LIST OF ROPE ← frame.intOnly, lst.rest WHILE lst#NIL DO
ok ← FALSE;
count ← count+1;
log.PutF["\n WARNING, %g is NOT connected", IO.rope[lst.first]]; ENDLOOP;
FOR lst: LIST OF ROPE ← frame.public, lst.rest WHILE lst#NIL
DO count ← count+1 ENDLOOP;
compare ← IF frame.cell.public.size=0 THEN 0 ELSE CoreOps.WireBits[frame.cell.public];
IF compare#count THEN {ok ← FALSE; Signal[]} }
ELSE FOR i: INT DECREASING IN [0..frame.seq.size) DO
ok ← CheckConnects[frame.seq[i]] AND ok ENDLOOP };
CheckForSingles: PROC [ctx: NodeContext] RETURNS[ok: BOOLTRUE] = {
singleChk: HashTable.EachPairAction = {
oldRef: REF CtxRec ← NARROW[value];
IF oldRef.cnt < 2 THEN {
name: ROPENARROW[key];
ok ← FALSE;
log.PutF["\n WARNING, %g is not connected", IO.rope[name]]} };
[ ] ← HashTable.Pairs[ctx.table, singleChk]};
LogFrame: PROC[frameCT: Core.CellType, logger: FrameLogger] = {
LogIt: PROC[fCT: Core.CellType, pathName: ROPENIL, depth: INT ← 0] = {
frame: CoreFrame.Frame ← FCT[fCT];
CoreOps.PrintIndent[depth, log];
log.PutF["Frame: %g", IO.rope[pathName]];
logger[fCT, depth];
FOR field: INT IN [0..frame.seq.size) DO
name ← CoreName.CellNm[frame.seq[field]].n;
IF name=NIL THEN name ← IO.PutFR["%g", IO.int[field]];
LogIt[frame.seq[field], Rope.Cat[pathName, ".", name], depth+1]; ENDLOOP};
name: ROPE ← CoreName.CellNm[frameCT].n;
IF name=NIL THEN name ← "top";
LogIt[frameCT, name]};
FrameLogger: TYPE = PROC[fCT: Core.CellType, depth: INT];
wireLogger: FrameLogger = {
frame: CoreFrame.Frame ← FCT[fCT];
IF frame.seq.size=0 THEN CoreOps.PrintWire[frame.cell.public, log, depth]};
frameLogger: FrameLogger = {
frame: CoreFrame.Frame ← FCT[fCT];
CoreOps.PrintIndent[depth, log];
log.PutRope[" Public:"];
FOR list: LIST OF ROPE ← frame.public, list.rest WHILE list#NIL DO
log.PutRope[" "]; log.PutRope[list.first]; ENDLOOP;
CoreOps.PrintIndent[depth, log];
log.PutRope[" IntOnly:"];
FOR list: LIST OF ROPE ← frame.intOnly, list.rest WHILE list#NIL DO
log.PutRope[" "]; log.PutRope[list.first]; ENDLOOP;
IF frame.seq.size=0 THEN CoreOps.PrintWire[frame.cell.public, log, depth];
};
FCT: PROC[frameCT: Core.CellType] RETURNS[frame: CoreFrame.Frame] = INLINE
{RETURN[CoreFrame.FCT[frameCT]]};
PathToAddr: PROC [path: Path] RETURNS[addr: Addr ← NIL] =
{FOR path ← path, path.rest WHILE path#NIL DO addr ← CONS[path.first, addr] ENDLOOP};
LogAddr: PROC [addr: Addr] =
{FOR addr ← addr, addr.rest WHILE addr#NIL DO log.PutF[" %g", IO.int[addr.first]] ENDLOOP};
RemoveItem: PROC[item: ROPE, list: LIST OF ROPE]
RETURNS[new: LIST OF ROPENIL] = {
FOR list ← list, list.rest WHILE list#NIL DO
IF NOT Rope.Equal[item, list.first] THEN new ← CONS[list.first, new] ENDLOOP};
AddItem: PROC[item: ROPE, list: LIST OF ROPE] RETURNS[new: LIST OF ROPENIL] = {
FOR lst: LIST OF ROPE ← list, lst.rest WHILE lst#NIL DO
IF Rope.Equal[item, lst.first] THEN RETURN[list] ENDLOOP;
RETURN[CONS[item, list]]};
END.