LichenPrintingImpl.Mesa
Last tweaked by Mike Spreitzer on April 12, 1989 4:00:36 pm PDT
DIRECTORY AbSets, BasicTime, BiRels, FS, IntStuff, IO, LichenDataStructure, LichenIntBasics, LichenPrinting, Rope, SetBasics, StructuredStreams, TiogaAccess, UnparserBuffer;
LichenPrintingImpl: CEDAR PROGRAM
IMPORTS AbSets, BasicTime, BiRels, FS, IntStuff, IO, LichenDataStructure, LichenIntBasics, Rope, SetBasics, StructuredStreams, TiogaAccess, UnparserBuffer
EXPORTS LichenPrinting
=
BEGIN OPEN IB:LichenIntBasics, IB, LichenDataStructure, LichenPrinting, Ints:IntStuff, Sets:AbSets, SS:StructuredStreams, UB:UnparserBuffer;
printStep: INT ← 2;
printWidth: INT ← 74;
sortTops: BOOLTRUE;
PrintObject: PROC [to: IO.STREAM, united: BOOL, PrintIt: PROC] = {
SS.Bp[to, IF united THEN united ELSE lookLeft, printStep];
SS.Begin[to];
PrintIt[!UNWIND => SS.End[to]];
SS.End[to];
RETURN};
PrintRope: PROC [to: IO.STREAM, united: BOOL, rope: ROPE] = {
SS.Bp[to, IF united THEN united ELSE lookLeft, printStep];
SS.Begin[to];
to.PutRope[rope !UNWIND => SS.End[to]];
SS.End[to];
RETURN};
PrintDesignOnFiles: PUBLIC PROC [d: Design, nameGen: NameGenerator ← NIL, fnPrefix, fnSuffix: ROPENIL, tioga: BOOLFALSE, pacify: IO.STREAMNIL, Filter: CellTypeFilter ← NIL] = {
realFNPrefix: ROPE ~ IF fnPrefix#NIL THEN fnPrefix ELSE Describe[d: d, subject: d, nameGen: nameGen];
realFNSuffix: ROPE ~ IF fnSuffix#NIL THEN fnSuffix ELSE "design";
n: NAT ← 0;
order: Sets.Order ~ BiRels.MapOrder[d.ctName, leftToRight, Sets.fwd, Sets.alleq];
CtPrint: PROC [ctv: Sets.Value] RETURNS [BOOL] = {
ct: CellType = NARROW[ctv.VA];
ctName: ROPE ~ ct.ACtName[];
realFileName: ROPE ~ Rope.Cat[realFNPrefix, "/", ctName.Translate[translator: BlandifyChar], ".", realFNSuffix];
ss, fs: IO.STREAM;
taw: TiogaAccess.Writer;
start: BasicTime.Pulses;
IF tioga
THEN {
taw ← TiogaAccess.Create[];
ss ← SS.Create[UB.NewInittedHandle[[output: [access[taw, printStep]], margin: printWidth]]];
}
ELSE {
fs ← FS.StreamOpen[fileName: realFileName, accessOptions: create, keep: 10];
ss ← SS.Create[UB.NewInittedHandle[[output: [stream[fs]], margin: printWidth]]];
};
IF pacify#NIL THEN {
pacify.PutF["%g: %g ", [integer[n ← n+1]], [rope[Describe[d, ct, d, nameGen]]]];
start ← BasicTime.GetClockPulses[]};
PrintCellType[ss, ct, nameGen];
ss.PutRope["\n"];
IF pacify#NIL THEN {
stop: BasicTime.Pulses ~ BasicTime.GetClockPulses[];
pacify.PutF[" %g\n", [real[BasicTime.PulsesToSeconds[stop-start]]]]};
IF tioga THEN TiogaAccess.WriteFile[taw, realFileName] ELSE IO.Close[fs];
ss.Close[];
RETURN [FALSE]};
IF pacify#NIL THEN {
pacify.PutF["Total: %g\nCrossed=", [integer[d.cellTypes.Size.EN]]];
d.crossedCellTypes.PrintSet[pacify];
pacify.PutRope[".\n"]};
IF d.cellTypes.Scan[CtPrint, order].found THEN ERROR;
RETURN};
BlandifyChar: PROC [old: CHAR] RETURNS [new: CHAR] ~ {
SELECT old FROM
IN ['a .. 'z], IN ['A .. 'Z], IN ['0 .. '9], '., '- => RETURN [old];
', => RETURN ['.];
': => RETURN ['~];
ENDCASE => RETURN ['$]};
PrintDesignOnFile: PUBLIC PROC [d: Design, nameGen: NameGenerator ← NIL, fileName: ROPENIL, tioga: BOOLFALSE, pacify: IO.STREAMNIL, Filter: CellTypeFilter ← NIL] = {
realFileName: ROPE = IF fileName # NIL THEN fileName ELSE Rope.Cat[Describe[d: d, subject: d, nameGen: nameGen], ".design"];
ss, fs: IO.STREAM;
taw: TiogaAccess.Writer;
IF tioga
THEN {
taw ← TiogaAccess.Create[];
ss ← SS.Create[UB.NewInittedHandle[[output: [access[taw, printStep]], margin: printWidth]]];
}
ELSE {
fs ← FS.StreamOpen[fileName: realFileName, accessOptions: create, keep: 10];
ss ← SS.Create[UB.NewInittedHandle[[output: [stream[fs]], margin: printWidth]]];
};
PrintDesignSubset[ss, d, nameGen, pacify, Filter];
IF tioga THEN TiogaAccess.WriteFile[taw, realFileName] ELSE IO.Close[fs];
ss.Close[];
RETURN};
PrintDesign: PUBLIC PROC [to: IO.STREAM, d: Design, nameGen: NameGenerator ← NIL, pacify: IO.STREAMNIL] = {
PrintDesignSubset[to, d, nameGen, pacify, NIL];
RETURN};
PrintDesignSubset: PUBLIC PROC [to: IO.STREAM, d: Design, nameGen: NameGenerator ← NIL, pacify: IO.STREAMNIL, Filter: CellTypeFilter ← NIL] = {
n: NAT ← 0;
order: Sets.Order ~ BiRels.MapOrder[d.ctName, leftToRight, Sets.fwd, Sets.alleq];
CTPrint: PROC [ra: REF ANY] = {
ct: CellType = NARROW[ra];
Inner: PROC = {
start: BasicTime.Pulses;
IF pacify#NIL THEN {
pacify.PutF["%g: %g ", [integer[n ← n+1]], [rope[Describe[d, ct, d, nameGen]]]];
start ← BasicTime.GetClockPulses[]};
PrintCellType[to, ct, nameGen];
IF pacify#NIL THEN {
stop: BasicTime.Pulses ~ BasicTime.GetClockPulses[];
pacify.PutF[" %g\n", [real[BasicTime.PulsesToSeconds[stop-start]]]]};
RETURN};
IF Filter=NIL OR Filter[ct] THEN PrintObject[to, TRUE, Inner];
RETURN};
IF pacify#NIL AND Filter=NIL THEN pacify.PutF["Total: %g\n", [integer[d.cellTypes.Size.EN]]];
IF NOT SS.IsAnSS[to] THEN to ← SS.Create[UB.NewInittedHandle[[output: [stream[to]], margin: printWidth]]];
to.PutF["%g: Design {", [rope[Describe[d: d, subject: d, nameGen: nameGen]]]];
IF d.scale#0.0 THEN to.PutF["linear unit = %g microns, ", [real[d.scale*1.0E6]]];
d.cellTypes.EnumA[CTPrint, order];
to.PutF["}"];
RETURN};
PrintNameAndAliases: PROC [to: IO.STREAM, names: Set--of SteppyName--, nonrelnames: Set ← nilSet] ~ {
first, second: BOOLTRUE;
prefix: ROPENIL;
PerName: PROC [val: Sets.Value] ~ {
name: SteppyName ~ VSn[val];
IF first THEN first ← FALSE ELSE {
IF second THEN {to.PutRope["(a.k.a."]; second ← FALSE} ELSE to.PutRope[","];
SS.Bp[to, width, printStep, " "];
};
to.PutRope[prefix];
to.PutRope[UnparseSteppyName[name]];
RETURN};
names.Enumerate[PerName];
IF nonrelnames#nilSet THEN {
prefix ← "/";
nonrelnames.Enumerate[PerName]};
IF NOT second THEN to.PutRope[")"];
RETURN};
PrintCellType: PUBLIC PROC [to: IO.STREAM, ct: CellType, nameGen: NameGenerator ← NIL] = {
CrossPrint: PROC ~ {to.PutRope[IF ct.d.crossedCellTypes.HasMemA[ct] THEN "crossed" ELSE "uncrossed"]};
BBPrint: PROC ~ {to.PutF["bbox: [%g,%g,%g,%g]", [integer[ct.bbox[X].min]], [integer[ct.bbox[Y].min]], [integer[ct.bbox[X].maxPlusOne]], [integer[ct.bbox[Y].maxPlusOne]]]};
PortPrint: PROC = {
tops: Set ~ ct.TopParts[p];
sep: ROPENIL;
PrintAPort: PROC [pv: Sets.Value] RETURNS [BOOL] ~ {
p: Port ~ NARROW[pv.VA];
PPrint: PROC ~ {PrintPW[to, ct, p, p, NIL, nameGen]};
to.PutRope[sep]; PrintObject[to, FALSE, PPrint];
sep ← ", "; RETURN [FALSE]};
to.PutRope["ports: ["];
IF tops.Scan[PrintAPort, IF sortTops THEN ct.nameOrder[p] ELSE Sets.alleq].found THEN ERROR;
to.PutRope["]"];
RETURN};
IWPrint: PROC = {
tops: Set ~ ct.TopParts[w];
sep: ROPENIL;
PrintAWire: PROC [wv: Sets.Value] RETURNS [BOOL] ~ {
w: Wire ~ NARROW[wv.VA];
WPrint: PROC ~ {PrintPW[to, ct, w, w, NIL, nameGen]};
to.PutRope[sep]; PrintObject[to, FALSE, WPrint];
sep ← ", "; RETURN [FALSE]};
to.PutRope["internal wires: ["];
IF tops.Scan[PrintAWire, IF sortTops THEN ct.nameOrder[w] ELSE Sets.alleq].found THEN ERROR;
to.PutRope["]"];
RETURN};
CIPrint: PROC = {
to.PutF["connection sites: "];
PrintCells[to, ct, ct.Subcells, ct, nameGen];
RETURN};
AyPrint: PROC = {
to.PutRope["asArray: "];
PrintArray[to, ct, nameGen]
};
IF NOT SS.IsAnSS[to] THEN to ← SS.Create[UB.NewInittedHandle[[output: [stream[to]], margin: printWidth]]];
to.PutRope[Describe[ct.d, ct, ct.d, nameGen]];
to.PutRope[": CellType["];
PrintObject[to, FALSE, CrossPrint];
to.PutRope[", "];
IF ct.d.physd THEN {PrintObject[to, FALSE, BBPrint]; to.PutRope[", "]};
PrintObject[to, TRUE, PortPrint];
IF ct.asu # NIL THEN {
to.PutRope[", "]; PrintObject[to, TRUE, IWPrint];
to.PutRope[", "]; PrintObject[to, TRUE, CIPrint];
};
IF ct.asArray # NIL THEN {
to.PutRope[", "]; PrintObject[to, TRUE, AyPrint];
};
to.PutRope["]"];
};
PrintPW: PROC [to: IO.STREAM, ct: CellType, class: PWClass, pw: PW, parent: PWNIL, nameGen: NameGenerator ← NIL] ~ {
[] ← ct.d.SteppyDescribe[pw, IF parent#NIL THEN parent ELSE ct, nameGen];
{fullNames: Set ~ ct.fullName[class].MappingA[pw];
IF parent#NIL THEN {
relNames: Set ~ RelativeNames[ct, class, parent, pw];
reldNames: Set ~ SNsCat[ct.fullName[class].MappingA[parent], relNames];
nonRelNames: Set ~ fullNames.Difference[reldNames];
PrintNameAndAliases[to, relNames, nonRelNames];
to ← to}
ELSE PrintNameAndAliases[to, fullNames];
IF ct.d.Atomic[pw] THEN RETURN;
{shape: LOI ~ Shape[ct, class, pw];
IF shape#NIL THEN {
IF shape.rest=NIL THEN ERROR;
FOR dims: LOI ← shape, dims.rest WHILE dims.rest#NIL DO
to.PutF["*%g", [integer[dims.first]]];
ENDLOOP;
RETURN};
{kids: Seq ~ BiRels.DeRef[ct.d.sub.ApplyA[pw].MA];
first: BOOLTRUE;
to.PutRope["["];
FOR i: INT IN [0 .. kids.Size.EN) DO
kid: PW ~ kids.ApplyI[i].MA;
PWPrint: PROC ~ {PrintPW[to, ct, class, kid, pw, nameGen]};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, FALSE, PWPrint];
ENDLOOP;
to.PutRope["]"];
RETURN}}}};
listOne: LOI ~ LIST[1];
Shape: PROC [ct: CellType, class: PWClass, pw: PW] RETURNS [LOI] ~ {
IF ct.d.Atomic[pw] THEN RETURN [listOne];
{kids: Seq ~ BiRels.DeRef[ct.d.sub.ApplyA[pw].MA];
width: LNAT ~ kids.Size.EN;
subShape: LOINIL;
FOR i: INT IN [0 .. width) DO
kid: PW ~ kids.ApplyI[i].MA;
thissub: LOI;
AcceptIndex: PROC [sn: SteppyName] RETURNS [BOOL] ~ {
IF sn.grade.nonsubs#0 OR sn.grade.subs#1 THEN RETURN [FALSE];
IF NARROW[sn.steps.first, REF INT]^ # i THEN RETURN [FALSE];
RETURN [TRUE]};
IF NOT ct.ScanRelativeNames[class, pw, kid, AcceptIndex].found THEN RETURN [NIL];
thissub ← Shape[ct, class, kid];
IF thissub=NIL THEN RETURN [NIL];
IF subShape=NIL THEN subShape ← thissub ELSE IF NOT LoiEqual[subShape, thissub] THEN RETURN [NIL];
ENDLOOP;
RETURN [CONS[width, subShape]]}};
LoiEqual: PROC [l1, l2: LOI] RETURNS [BOOL] ~ {
WHILE l1#l2 DO
IF l1=NIL OR l2=NIL OR l1.first#l2.first THEN RETURN [FALSE];
l1 ← l1.rest;
l2 ← l2.rest;
ENDLOOP;
RETURN [TRUE]};
PrintNeighborhood: PROC [to: IO.STREAM, cct: CellType, of: Set--of Wire--, radius: NAT] ~ {
d: Design ~ cct.d;
notPub: Set--of Wire-- ~ cct.asu.publics.Negate[];
transes: Set--of CellInstance-- ~ d.ciType.Image[d.transistorCellTypes, rightToLeft];
wires: Set--of Wire-- ~ of.CreateHashCopy[];
cells: Set--of CellInstance-- ← Sets.CreateHashSet[d.eSpace];
frontier: Set--of Wire-- ← wires;
FOR i: NAT IN [1 .. radius] DO
cis: Set ~ d.iwConns.Image[frontier, rightToLeft];
IF NOT cells.AddSet[cis].new.some THEN EXIT;
IF i=radius THEN EXIT;
{newXstrs: Set ~ cis.Intersection[transes];
condWires: Set ~ d.iwConns.Image[newXstrs, leftToRight];
frontier ← condWires.Difference[wires].CreateHashCopy[];
IF frontier.Empty THEN EXIT;
IF NOT wires.AddSet[frontier].new.some THEN ERROR;
}ENDLOOP;
};
PrintCells: PUBLIC PROC [to: IO.STREAM, cct: CellType, set: Set--OF Cell--, and: Cell ← NIL, nameGen: NameGenerator ← NIL] = {
order: Sets.Order ~ cct.nameOrder[i];
first: BOOLTRUE;
PrintIt: PROC [cell: Cell] = {
IPrint: PROC = {PrintCell[to, cct, cell, nameGen]};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, TRUE, IPrint];
};
to.PutRope["["];
set.EnumA[PrintIt, order];
IF and#NIL THEN PrintIt[and];
to.PutRope["]"];
};
PrintCell: PUBLIC PROC [to: IO.STREAM, cct: CellType, cell: Cell, nameGen: NameGenerator ← NIL] = {
WITH cell SELECT FROM
ct: CellType => {
IF ct # cct THEN ERROR;
to.PutRope["exports"];
PrintForPorts[to, ct.asu.exports, cct.d.sub, cct.d.parent, ct, BiRels.EnumSeqOfSet[ct.TopParts[p], IF sortTops THEN ct.nameOrder[p] ELSE Sets.alleq], ct, cct.d.eSpace, nameGen];
RETURN};
ci: CellInstance => {
ict: CellType ~ cct.d.CiT[ci];
xfm: Transform ~ IF cct.d.physd THEN VXfm[cct.d.ciXfm.ApplyA[ci].Val] ELSE [];
[] ← cct.d.SteppyDescribe[ci, cct, nameGen];
PrintNameAndAliases[to, cct.INames[ci]];
to.PutF[": %g", [rope[cct.d.Describe[ict, cct.d, nameGen]]] ];
IF cct.d.physd THEN to.PutF["{%g %g,%g}", [rope[FormatTransform[xfm]]], [integer[ci.offset[X]]], [integer[ci.offset[Y]]]];
PrintForPorts[to, ci.conns, cct.d.sub, cct.d.parent, ict, BiRels.EnumSeqOfSet[ict.TopParts[p], IF sortTops THEN ict.nameOrder[p] ELSE Sets.alleq], ict, cct.d.eSpace, nameGen];
RETURN};
ENDCASE => ERROR;
};
PrintForPorts: PROC [to: IO.STREAM, conns, sub, parent: BiRel, pct: CellType, ports: Seq--of Port--, rel: REF ANY, wSpace: Sets.Space, nameGen: NameGenerator] = {
first: BOOLTRUE;
PrintForPort: PROC [pair: BiRels.Pair] RETURNS [BOOL] ~ {
p: Port ~ NARROW[pair[right].VA];
CPrint: PROC ~ {
wmv: Sets.MaybeValue ~ conns.ApplyA[p];
to.PutRope[pct.d.Describe[p, rel, nameGen]];
to.PutRope[": "];
IF wmv.found THEN {to.PutRope[wSpace.SFormat[wmv.it]]; RETURN};
{pkids: Seq--of Port-- ~ BiRels.DeRef[pct.d.sub.ApplyA[p].MDA];
IF pkids=nilBiRel THEN {to.PutRope["??"]; RETURN};
{wkids: Seq--of Wire-- ~ pkids.Compose[conns];
nwkids: NATURAL ~ wkids.Size.EN;
npkids: NATURAL ~ pkids.Size.EN;
IF nwkids#npkids THEN GOTO NotEasy;
{ws: Set--of Wire-- ~ wkids.SetOn[right];
IF ws.Size=Ints.one THEN {to.PutF["%g*%g", [rope[wSpace.SFormat[ws.TheElt]]], [integer[pkids.Size.EN]]]; RETURN};
{wparents: Set--of Wire-- ~ parent.Image[ws];
IF wparents.Size#Ints.one THEN GOTO NotEasy;
{wparent: Sets.Value ~ wparents.TheElt;
allwkids: Seq--of Wire-- ~ BiRels.VB[sub.Apply[wparent].Val];
mi: Sets.MaybeValue ~ allwkids.Index[wkids];
IF NOT mi.found THEN GOTO NotEasy;
{base: NATURAL ~ mi.it.VI;
to.PutRope[wSpace.SFormat[wparent]];
IF base#0 OR allwkids.Size.EN#npkids THEN to.PutF["[%g..%g]", [integer[base]], [integer[base+npkids-1]] ];
RETURN}}}};
EXITS NotEasy => NULL};
PrintForPorts[to, conns, sub, parent, pct, pkids, p, wSpace, nameGen];
RETURN}};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, FALSE, CPrint];
RETURN [FALSE]};
to.PutRope["["];
IF ports.Scan[PrintForPort].found THEN ERROR;
to.PutRope["]"];
RETURN};
printStatRep: BOOLTRUE;
printDumbRep: BOOLFALSE;
printStatExports: BOOLTRUE;
PrintArray: PUBLIC PROC [to: IO.STREAM, act: CellType, nameGen: NameGenerator ← NIL] = {
a: Array = act.asArray;
ect: CellType ~ act.EltType[];
BasePrint: PROC = {
to.PutF["base period = [%g, %g]", [integer[a.basePeriod[X]]], [integer[a.basePeriod[Y]]]]};
StatPrint: PROC = {
to.PutRope["static graph = ["];
PrintStatRep[to, act, nameGen];
to.PutRope["]"]};
PhysPrint: PROC ~ {
first: BOOLTRUE;
to.PutRope["transforms = ["];
FOR fx: Int IN [0 .. a.basePeriod[X]) DO FOR fy: Int IN [0 .. a.basePeriod[Y]) DO
f: Int2 ~ [fx, fy];
cf: NATURAL ~ ComposePhase[a, f];
IF first THEN first ← FALSE ELSE {to.PutRope[";"]; SS.Bp[to, width, printStep, " "]};
to.PutF["{%g,%g :", [integer[fx]], [integer[fy]]];
to.PutChar[' ];
to.PutRope[VXfm[a.fXfm.Apply[I2V[f]].Val].FormatTransform];
to.PutF[" %g,%g", [integer[a.offsets[cf].o0[X]]], [integer[a.offsets[cf].o0[Y]]] ];
IF a.size2#a.basePeriod THEN to.PutF[" + %g,%g", [integer[a.offsets[cf].o1[X]]], [integer[a.offsets[cf].o1[Y]]] ];
to.PutRope["}"];
ENDLOOP ENDLOOP;
to.PutRope["]"]};
StatExpPrint: PROC = {
to.PutRope["static exports = "];
PrintStatExp[to, act, nameGen];
RETURN};
to.PutF["{%g BY %g OF %g, ",
[integer[a.size2[X]]], [integer[a.size2[Y]]],
[rope[act.d.Describe[ect, act.d, nameGen]]]
];
PrintObject[to, FALSE, BasePrint];
IF act.d.physd THEN {
to.PutRope[", "];
PrintObject[to, TRUE, PhysPrint]};
IF printStatRep THEN {
to.PutRope[", "];
PrintObject[to, TRUE, StatPrint];
};
IF printStatExports THEN {
to.PutRope[", "];
PrintObject[to, TRUE, StatExpPrint];
};
IF printDumbRep THEN ERROR nyet;
to.PutRope["}"];
};
PrintStatRep: PROC [to: IO.STREAM, act: CellType, nameGen: NameGenerator] ~ {
a: Array = act.asArray;
ect: CellType ~ act.EltType[];
firstEdge: BOOLTRUE;
EnsureNamed: PROC [part: Part] ~ {
[] ← act.d.SteppyDescribe[part, ect, nameGen];
RETURN};
PrintEdge: PROC [val: Sets.Value] ~ {
IF firstEdge THEN firstEdge ← FALSE ELSE to.PutRope[", "];
PrintRope[to, TRUE, a.statrep.edgeSpace.SFormat[val]];
RETURN};
ect.EnumCTParts[p, TRUE, TRUE, EnsureNamed];
a.statrep.edges.Enumerate[PrintEdge, a.statrep.edgeNameOrder];
RETURN};
PrintStatExp: PROC [to: IO.STREAM, act: CellType, nameGen: NameGenerator] ~ {
a: Array = act.asArray;
ect: CellType ~ act.EltType[];
first: BOOLTRUE;
EnsureNamed: PROC [part: Part] ~ {
[] ← act.d.SteppyDescribe[part, ect, nameGen];
RETURN};
IF NOT printStatRep THEN ect.EnumCTParts[p, TRUE, TRUE, EnsureNamed];
PrintForPorts[to, a.dumrep.apToWire, a.dumrep.dwSub, a.dumrep.dwParent, act, BiRels.EnumSeqOfSet[act.TopParts[p], IF sortTops THEN act.nameOrder[p] ELSE Sets.alleq], act, a.dumrep.dwSpace, nameGen];
RETURN};
IsArray: PROC [ct: CellType] RETURNS [pass: BOOL] = {pass ← ct.asArray # NIL};
Is1D: PROC [ct: CellType] RETURNS [BOOL]
~ {RETURN [ct.asArray#NIL AND (ct.asArray.size2[X]=1 OR ct.asArray.size2[Y]=1)]};
Is2D: PROC [ct: CellType] RETURNS [BOOL]
~ {RETURN [ct.asArray#NIL AND ct.asArray.size2[X]#1 AND ct.asArray.size2[Y]#1]};
PrintArrays: PROC [to: IO.STREAM, d: Design, nameGen: NameGenerator ← NIL, pacify: IO.STREAMNIL] = {
PrintDesignSubset[to, d, nameGen, pacify, IsArray];
};
END.