dumpFileName: Rope.ROPE ← NIL;
DoOnePLA:
PROC [pt: Parquet.PlacedTile,
oldTop: INT, -- top of last tile after stretching
tt: BoolOps.TruthTable,
name: Rope.ROPE,
outputLoc: INT, -- desired output location after stretching
dontPosition: BOOL]
RETURNS
[virtualOutputLoc: INT, -- actual output location after stretching
virtualTop: INT, -- top of this tile after stretching
newPt: Parquet.PlacedTile] = BEGIN
ENABLE
MakePLA.Error => {ERROR Error[BadPLA, Rope.Cat["Could not create base PLA: ", msg]]};
InsertName:
PROC [base, insert: Rope.
ROPE]
RETURNS [Rope.
ROPE] =
BEGIN
dotPos: INT ← -1;
IF base = NIL OR insert = NIL THEN RETURN[base];
DO
t: INT ← Rope.Find[base, ".", dotPos+1];
IF t = -1 THEN EXIT;
dotPos ← t;
ENDLOOP;
RETURN[Rope.Cat[Rope.Substr[base, 0, dotPos], "-", insert, Rope.Substr[base, dotPos]]];
END;
OrientOption:
TYPE =
RECORD [
orient: Parquet.Orientation,
endLoc, stretch: INT
];
errorMsg: Rope.ROPE ← NIL;
errors: INT;
plaName: Rope.ROPE ← Rope.Cat["PLA", name];
aPLA: Parquet.Module;
aTile: Parquet.Tile;
normal, mirror, chosen: OrientOption;
mark: Parquet.Mark;
-- Set up options just as a user would
[] ← SymTab.Delete[desc.context.parameters, "TruthTableFile"];
ExprRead.StoreRefAny[desc.context.parameters, "TruthTable", tt];
ExprRead.StoreRope[desc.context.parameters, "TruthTableDumpFile", InsertName[desc.dumpFileName, name]];
-- make a PLA
aPLA ← MakePLA.Create[desc.context];
[errors, aTile] ← Parquet.ModuleIntoTile[module: aPLA, name: plaName, context: context, bbox: TRUE];
IF errors > 0
THEN
TerminalIO.WriteRope[Rope.Cat["Warning: ", Convert.RopeFromInt[errors], " error(s) found in PLA '", plaName, "', area(s) in question are indicated by highlighting.\n"]];
-- find the output and decide if we want to mirror the module
mark ← Parquet.GetMark[aTile, "outputBottom"];
IF mark =
NIL
THEN {
TerminalIO.WriteRope[Rope.Cat["Error: could not find mark called 'outputBottom' in the base PLA.\n"]];
mark ← Parquet.GetMark[aTile, "lr"];
};
normal.orient ← NormalOrient;
normal.endLoc ← outputLoc + (aTile.obj.size.y - mark.pos.y);
normal.stretch ← outputLoc - (oldTop + mark.pos.y);
IF desc.mirrorOK
THEN {
mark ← Parquet.GetMark[aTile, "outputTop"];
IF mark =
NIL
THEN {
TerminalIO.WriteRope[Rope.Cat["Error: could not find mark called 'outputTop' in the base PLA.\n"]];
mark ← Parquet.GetMark[aTile, "lr"];
};
mirror.orient ← MirroredOrient;
mirror.endLoc ← outputLoc + mark.pos.y;
mirror.stretch ← outputLoc - (oldTop + (aTile.obj.size.y - mark.pos.y));
}
ELSE {
mirror ← normal;
};
SELECT
TRUE
FROM
(dontPosition
OR (mirror.stretch >= 0
AND normal.stretch >= 0)) => {
-- Either will work, pick the one which extends up the least.
IF mirror.endLoc < normal.endLoc THEN chosen ← mirror ELSE chosen ← normal;
};
(mirror.stretch >= 0) => chosen ← mirror;
(normal.stretch >= 0) => chosen ← normal;
(mirror.stretch < 0
AND normal.stretch < 0) => {
-- neither will work, pick the closest
IF mirror.stretch > normal.stretch THEN chosen ← mirror ELSE chosen ← normal;
};
ENDCASE => ERROR;
newPt ← Parquet.AdjacentTileCorners[pt, aTile, above, chosen.orient];
-- now place a stretch line
IF dontPosition
OR chosen.stretch < 0
THEN {
RETURN[outputLoc - chosen.stretch, chosen.endLoc - chosen.stretch, newPt];
}
ELSE {
oldY, minX, maxX: INT;
info: Parquet.StretchData;
outLoc: INT ← outputLoc;
endLoc: INT ← chosen.endLoc;
amount: INT ← (chosen.stretch + l - 1) / l;
-- stretch only by whole lambda
outLoc ← outLoc + (amount * l - chosen.stretch);
endLoc ← endLoc + (amount * l - chosen.stretch);
[ymax: oldY, xmin: minX, xmax: maxX] ← Parquet.PlacedTileLoc[pt];
info ← [point: [minX, oldY], length: maxX - minX, direction: up, type: pointed, label: Convert.RopeFromInt[from: amount, showRadix: FALSE]];
Parquet.PlaceStretch[into: pt.owner, data: info];
RETURN[outLoc, endLoc, newPt];
};
END;
Stretch:
PROC [mod: Parquet.Module]
RETURNS [Parquet.Module] =
BEGIN
errors: INT;
aTile: Parquet.Tile;
newMod: Parquet.Module;
place: Parquet.PlacedTile;
[errors, aTile] ← Parquet.ModuleIntoTile[mod, "MakeCP", context];
IF errors > 0
THEN
TerminalIO.WriteRope[Rope.Cat["Warning: ", Convert.RopeFromInt[errors], " error(s) found in resulting module, area(s) in question are indicated by highlighting.\n"]];
[newMod, place] ← Parquet.NewModule[context];
[] ← Parquet.AdjacentTile[place, aTile, rightOf];
RETURN[newMod];
END;
FOR tt:
LIST
OF BoolOps.TruthTable ← desc.truthTables, tt.rest
WHILE tt #
NIL
DO
name: Rope.ROPE;
outputLocation, actualLoc: INT;
IF outputNames #
NIL
THEN {
name ← outputNames.first;
outputNames ← outputNames.rest;
}
IF outList #
NIL
THEN
outputLocation ← outList.first + outputOffset
ELSE
outputLocation ← outputOffset;
[actualLoc, lastRightSide, lastPlace] ← DoOnePLA[lastPlace, lastRightSide, tt.first, name, outputLocation, first];
TerminalIO.WriteRope[Rope.Concat[" ", name]];
IF first
THEN {
first ← FALSE;
outputOffset ← actualLoc - outputLocation;
}
ELSE {
IF actualLoc # outputLocation THEN mismatch ← TRUE;
};
IF outList # NIL THEN outList ← outList.rest;
ENDLOOP;