BCDery>MakeDoImpl.Mesa
Last Edited by: Spreitzer, March 3, 1984 5:42:36 pm PST
IF A is needed & an A does not exist & C makes A THEN C needs to be done
IF an A exists & C makes A from B & a B exists & current A was not made from current B THEN C needs to be done
IF C needs to be done & C uses B THEN B is needed
IF C needs to be done & C uses B & no B exists THEN C cannot be done because of missing B
DIRECTORY Commander, CommandTool, FS, IO, MakeDo, OrderedSymbolTableRef, Rope, TimeStamp, ViewerIO;
MakeDoImpl:
CEDAR
PROGRAM
IMPORTS CommandTool, FS, IO, OrderedSymbolTableRef, Rope, ViewerIO
EXPORTS MakeDo =
BEGIN OPEN MakeDo;
Warning: PUBLIC SIGNAL [message: ROPE] = CODE;
Error: PUBLIC ERROR [message: ROPE] = CODE;
nodes: OrderedSymbolTableRef.Table ← OrderedSymbolTableRef.CreateTable[CompareNodes];
depth: INT ← 0;
debugging: BOOLEAN ← TRUE;
log, in: IO.STREAM;
Log:
PUBLIC
PROC [fmt:
ROPE, v1, v2, v3, v4, v5:
IO.Value ← [null[]]] =
BEGIN
IF NOT debugging THEN RETURN;
FOR i: INT IN [0 .. depth) DO log.PutChar['\t] ENDLOOP;
log.PutF[fmt, v1, v2, v3, v4, v5];
log.PutChar['\n];
END;
Confirm:
PROC [action:
ROPE] =
BEGIN
IF NOT debugging THEN RETURN;
FOR i: INT IN [0 .. depth) DO log.PutChar['\t] ENDLOOP;
log.PutF["Ready to %g ? ", IO.rope[action]];
WHILE in.GetChar[] # '\n DO NULL ENDLOOP;
END;
GetNode:
PUBLIC
PROC [name:
ROPE]
RETURNS [node: Node] = {
IF (node ←
NARROW[nodes.Lookup[name]]) =
NIL
THEN nodes.Insert[node ←
NEW [NodeRep ← [
name: name,
needers: OrderedSymbolTableRef.CreateTable[CompareCommands]]]]};
CompareNodes:
--PROC [r1, r2: Item] RETURNS [Comparison]--
PUBLIC OrderedSymbolTableRef.CompareProc =
BEGIN
GetKey:
PROC [ra:
REF
ANY]
RETURNS [r:
ROPE] = {
r ←
WITH ra
SELECT
FROM
n: Node => n.name,
x: ROPE => x,
ENDCASE => ERROR};
k1: ROPE ← GetKey[r1];
k2: ROPE ← GetKey[r2];
RETURN [k1.Compare[k2]];
END;
CompareCommands: OrderedSymbolTableRef.CompareProc
--PROC [r1, r2: Item] RETURNS [Comparison]-- =
TRUSTED
BEGIN
k1: INT ← LOOPHOLE[r1];
k2: INT ← LOOPHOLE[r2];
RETURN [IF k1 < k2 THEN less ELSE IF k1 > k2 THEN greater ELSE equal];
END;
Needed: PROC [n: Node] RETURNS [b: BOOLEAN] = {b ← n.needers.Size[] > 0};
EnsureNeed:
PROC [needed: Node, needer: Command] =
{IF needed.needers.Lookup[needer] = NIL THEN needed.needers.Insert[needer]};
EnsureNotNeed:
PROC [needed: Node, needer: Command] =
{[] ← needed.needers.Delete[needer]};
FileExists:
--PROC [result: Node, c: Command] RETURNS [exists: BOOLEAN]--
PUBLIC ExistProc =
BEGIN
exists ← TRUE;
[] ← FS.FileInfo[result.name !FS.Error => {exists ← FALSE; CONTINUE}];
END;
ClearAllLinks:
PROC =
BEGIN
Clear:
PROC [any:
REF
ANY]
RETURNS [stop:
BOOLEAN] = {
n: Node ← NARROW[any];
n.producer ← NIL;
n.consumers ← NIL;
n.derivedCmds ← NIL;
n.needers.DeleteAllItems[];
stop ← FALSE};
nodes.EnumerateIncreasing[Clear];
END;
finders: LIST OF Finder ← NIL;
AddFinder:
PUBLIC
PROC [finder: Finder, end: End] =
BEGIN
SELECT end
FROM
front => finders ← CONS[finder, finders];
back => {fl:
LIST
OF Finder;
IF finders = NIL THEN {finders ← LIST[finder]; RETURN};
FOR fl ← finders, fl.rest WHILE fl.rest # NIL DO NULL ENDLOOP;
fl.rest ← LIST[finder]};
ENDCASE => ERROR;
EnsureNodeProduced:
PROC [node: Node] =
BEGIN
IF node.producer # NIL THEN RETURN;
IF EnsureProduced[node.name] = NIL THEN node.producer ← leaf;
END;
EnsureProduced:
PROC [resultName:
ROPE]
RETURNS [c: Command] =
BEGIN
FOR fl:
LIST
OF Finder ← finders, fl.rest
WHILE fl #
NIL
DO
found: BOOLEAN;
makes, from: NodeList;
cmd: ROPE;
why: Node;
NotCurrent: NotCurrentProc;
Rederive: RederiveProc;
Exists: ExistProc;
foundData: REF ANY;
[found, makes, from, cmd, why, NotCurrent, Rederive, Exists, foundData] ← fl.first.finderProc[resultName: resultName, finderData: fl.first.finderData];
IF found
THEN {
first: BOOLEAN ← TRUE;
already: Command ← NIL;
FOR ml: NodeList ← makes, ml.rest
WHILE ml #
NIL
DO
IF first
THEN {already ← ml.first.producer; first ← FALSE}
ELSE {
IF ml.first.producer # already
THEN
ERROR Error[
IO.PutFR[
"Command %g doesn't precisely cover command %g (e.g., at %g)",
IO.refAny[cmd],
IO.refAny[IF already # NIL THEN already.cmd ELSE NIL],
IO.rope[ml.first.name]]]};
ENDLOOP;
IF already # NIL THEN RETURN [already];
c ←
NEW [CommandRep ←
[cmd: cmd, makes: makes, from: from, dependencySource: why, NotCurrent: NotCurrent, Rederive: Rederive, Exists: Exists, foundData: foundData]];
FOR ml: NodeList ← c.makes, ml.rest
WHILE ml #
NIL
DO
IF ml.first.producer # NIL THEN ERROR;
ml.first.producer ← c;
ENDLOOP;
FOR fl: NodeList ← c.from, fl.rest
WHILE fl #
NIL
DO
fl.first.consumers ← CONS[c, fl.first.consumers];
ENDLOOP;
why.derivedCmds ← CONS[c, why.derivedCmds];
RETURN};
ENDLOOP;
c ← NIL;
END;
root: Command ← NEW [CommandRep ← [cmd: "-- root"]];
leaf: Command ← NEW [CommandRep ← [cmd: "-- leaf", Exists: FileExists]];
Ensure:
PUBLIC
PROC [what: RopeList, ch: Commander.Handle] =
BEGIN
ClearAllLinks[];
commanderHandle ← ch;
FOR what ← what, what.rest
WHILE what #
NIL
DO
c: Command ← EnsureProduced[what.first];
IF c #
NIL
THEN {
FOR ml: NodeList ← c.makes, ml.rest
WHILE ml #
NIL
DO
EnsureNeed[ml.first, root];
ENDLOOP;
EnsureWork[c, FALSE];
};
ENDLOOP;
commanderHandle ← NIL;
Log["\n"];
END;
commanderHandle: Commander.Handle;
EnsureWork:
PROC [c: Command, perturbed:
BOOLEAN] =
BEGIN
PostAmble: PROC = {Log["EW <- %g", IO.rope[c.cmd]]; depth ← depth - 1};
oldNeeds: BOOLEAN;
IF c = leaf THEN RETURN;
IF c.computed AND NOT perturbed THEN RETURN;
depth ← depth + 1;
Log["EW -> %g ", IO.rope[c.cmd]];
FOR sl: NodeList ← c.from, sl.rest
WHILE sl #
NIL
DO
EnsureNodeProduced[sl.first];
EnsureWork[sl.first.producer, FALSE];
ENDLOOP;
oldNeeds ← c.needsToBeDone; c.needsToBeDone ← FALSE;
FOR ml: NodeList ← c.makes, ml.rest
WHILE ml #
NIL
DO
IF Needed[ml.first] AND NOT c.Exists[ml.first, c] THEN c.needsToBeDone ← TRUE;
ENDLOOP;
IF (NOT c.needsToBeDone) AND c.NotCurrent[c] THEN c.needsToBeDone ← TRUE;
c.computed ← TRUE;
IF oldNeeds AND NOT c.needsToBeDone THEN ERROR;
IF oldNeeds = c.needsToBeDone THEN {PostAmble[]; RETURN};
FOR sl: NodeList ← c.from, sl.rest
WHILE sl #
NIL
DO
(IF c.needsToBeDone THEN EnsureNeed ELSE EnsureNotNeed)[sl.first, c];
ENDLOOP;
FOR sl: NodeList ← c.from, sl.rest
WHILE sl #
NIL
DO
EnsureWork[sl.first.producer, TRUE];
ENDLOOP;
IF c.needsToBeDone
THEN {
ofll: LIST OF NodeList ← NIL;
rcl: CommandList ← NIL;
FOR sl: NodeList ← c.from, sl.rest WHILE sl # NIL DO
IF NOT sl.first.producer.Exists[sl.first, sl.first.producer] THEN ERROR;
ENDLOOP;
Confirm[c.cmd];
doans ← CommandTool.DoCommand[commandLine: c.cmd, parent: commanderHandle];
c.needsToBeDone ← FALSE;
FOR sl: NodeList ← c.from, sl.rest
WHILE sl #
NIL
DO
EnsureNotNeed[sl.first, c];
ENDLOOP;
FOR ml: NodeList ← c.makes, ml.rest
WHILE ml #
NIL
DO
FOR cl: CommandList ← ml.first.derivedCmds, cl.rest
WHILE cl #
NIL
DO
ofll ← CONS[RederiveCommand[cl.first], ofll];
ENDLOOP;
ENDLOOP;
FOR rcl ← rcl, rcl.rest WHILE rcl # NIL DO EnsureWork[rcl.first, TRUE] ENDLOOP;
FOR ofll ← ofll, ofll.rest
WHILE ofll #
NIL
DO
ofl: NodeList ← ofll.first;
FOR ofl ← ofl, ofl.rest
WHILE ofl #
NIL
DO
EnsureWork[ofl.first.producer, TRUE];
ENDLOOP;
ENDLOOP;
FOR sl: NodeList ← c.from, sl.rest
WHILE sl #
NIL
DO
EnsureWork[sl.first.producer, TRUE];
ENDLOOP;
FOR dl: NodeList ← c.makes, dl.rest
WHILE dl #
NIL
DO
FOR cl: CommandList ← dl.first.consumers, cl.rest
WHILE cl #
NIL
DO
EnsureWork[cl.first, TRUE];
ENDLOOP;
ENDLOOP;
};
PostAmble[];
END;
doans: REF ANY;
RederiveCommand:
PROC [c: Command]
RETURNS [oldFroms: NodeList] =
BEGIN
oldFroms ← c.from;
FOR fl: NodeList ← c.from, fl.rest
WHILE fl #
NIL
DO
fl.first.consumers ← RemoveCommand[c, fl.first.consumers];
IF c.needsToBeDone THEN EnsureNotNeed[fl.first, c];
ENDLOOP;
c.from ← c.Rederive[c];
FOR fl: NodeList ← c.from, fl.rest
WHILE fl #
NIL
DO
fl.first.consumers ← CONS[c, fl.first.consumers];
IF c.needsToBeDone THEN EnsureNeed[fl.first, c];
ENDLOOP;
END;
RemoveCommand:
PROC [c: Command, l: CommandList]
RETURNS [ohne: CommandList] =
BEGIN
last: CommandList ← NIL;
ohne ← l;
FOR l ← l, l.rest
WHILE l #
NIL
DO
IF l.first = c
THEN {
IF last = NIL THEN ohne ← l.rest ELSE last.rest ← l.rest;
RETURN};
last ← l;
ENDLOOP;
ERROR;
END;
[in: in, out: log] ← ViewerIO.CreateViewerStreams["MakeDo Log"];
END.