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: BOOLEANTRUE;
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: INTLOOPHOLE[r1];
k2: INTLOOPHOLE[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;
END;
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: BOOLEANTRUE;
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.