SiroccoDeps.Mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Bill Jackson (bj) September 18, 1986 10:09:49 am PDT
Mike Spreitzer July 29, 1986 4:44:51 pm PDT
Last tweaked by Mike Spreitzer on April 26, 1990 9:18:13 am PDT
DIRECTORY
BasicTime USING [earliestGMT, GMT, Period],
FS USING [ComponentPositions, Error, EnumerateForNames, ExpandName, StreamOpen],
IO USING [Close, EndOf, EndOfStream, Error, GetCedarTokenRope, GetLineRope, PutFR, rope, SkipWhitespace, STREAM, TokenKind],
MakeDo USING [Action, ActionClass, ActionClassRep, ActionDep, AddFinder, fileClass, From, GetNode, InnerEnumerateSources, InnerGetCreated, Node, NodeList, notExistTime, PublicPartsOfAction, PublicPartsOfNode, Time],
Rope USING [Cat, Concat, Equal, InlineFetch, Length, ROPE, SkipTo, Substr];
SiroccoDeps: CEDAR PROGRAM
IMPORTS BasicTime, FS, IO, MakeDo, Rope ~ {
Copied Types
Action: TYPE ~ MakeDo.Action;
ActionClass: TYPE ~ MakeDo.ActionClass;
ActionDep: TYPE ~ MakeDo.ActionDep;
From: TYPE ~ MakeDo.From;
Node: TYPE ~ MakeDo.Node;
NodeList: TYPE ~ MakeDo.NodeList;
ROPE: TYPE ~ Rope.ROPE;
Time: TYPE ~ MakeDo.Time;
Types
CourierProgramList: TYPE ~ LIST OF CourierProgram;
CourierProgram: TYPE ~ REF CourierProgramObject;
CourierProgramObject: TYPE ~ RECORD [
dependsUpon: ReferencedProgramList,
filename: ROPE,
found: BOOL,
interface: ROPE,
program: ROPE,
pid: ROPE,
resultPrefix: ROPE,
sourceNode: Node,
switchFile: ROPE,
switchesNode: Node,
vid: ROPE
];
DependsParse: TYPE ~ { name, leftparen, pid, rightparen, version, vid };
ProgramParse: TYPE ~ { name, colon, program, pid, version, vid };
ReferencedProgramList: TYPE ~ LIST OF ReferencedProgram;
ReferencedProgram: TYPE ~ REF ReferencedProgramObject;
ReferencedProgramObject: TYPE ~ RECORD [
name: ROPE,
pid: ROPE,
valid: BOOL,
vid: ROPE
];
SiroccoAction: TYPE ~ CourierProgram;
Constants
COMMA: ROPE ~ ",";
DEPENDS: ROPE ~ "DEPENDS";
EQUAL: ROPE ~ "=";
SEMI: ROPE ~ ";";
Global State
siroccoClass: ActionClass ← NEW [MakeDo.ActionClassRep ← [
CheckConsistency: CheckConsistency,
Rederive: Rederive
]];
Procs
CheckConsistency: PROC [a: Action, result: Node] RETURNS [consistent: BOOL, reason: ROPE] --MakeDo.ConsistencyChecker-- =
BEGIN
resultTime: Time = result.InnerGetCreated[];
resultName: ROPE = result.PublicPartsOfNode[].name;
resultExists: BOOL ~ resultTime # MakeDo.notExistTime;
someIngredientsExist: BOOL;
missingIngredient, latestIngredientNode: Node;
latestIngredientTime: Time;
[someIngredientsExist, missingIngredient, latestIngredientNode, latestIngredientTime] ← FindLatestIngredient[a];
IF NOT someIngredientsExist THEN RETURN [TRUE, "no ingredients exist to indicate inconsistency"];
IF NOT resultExists THEN RETURN [FALSE, "some inputs but no outputs exist"];
IF latestIngredientTime.Period[resultTime] < 0 THEN RETURN [
FALSE,
IO.PutFR[
"result %g (of %g) predates ingredient %g (of %g)",
[rope[resultName]],
[time[resultTime]],
[rope[latestIngredientNode.PublicPartsOfNode[].name]],
[time[latestIngredientTime]]
]];
RETURN [TRUE, "result dated later than any existing ingredient"];
END;
FindLatestIngredient: PROC [a: Action] RETURNS [someIngredientsExist: BOOLFALSE, missingIngredient, latestIngredientNode: Node ← NIL, latestIngredientTime: Time ← BasicTime.earliestGMT] = {
PerSource: PROC [n: Node, which: ActionDep, optional: BOOL] = {
fromTime: BasicTime.GMT ← MakeDo.InnerGetCreated[n];
IF fromTime = MakeDo.notExistTime THEN {IF NOT optional THEN missingIngredient ← n}
ELSE {someIngredientsExist ← TRUE;
IF latestIngredientTime.Period[fromTime] > 0 THEN {
latestIngredientTime ← fromTime;
latestIngredientNode ← n;
};
};
};
MakeDo.InnerEnumerateSources[a, data, PerSource];
RETURN};
Rederive: PROC [a: Action] RETURNS [from: From, cmd: ROPE] ~ {
spec: CourierProgram ← NARROW[a.PublicPartsOfAction[].foundData];
from ← DeriveFrom[spec];
cmd ← DeriveCmd[spec];
};
Worker Procs
Basename: PROC [in: ROPE] RETURNS [out: ROPE] ~ {
parts: FS.ComponentPositions;
tmp: ROPE;
[tmp, parts, ] ← FS.ExpandName[in];
out ← Rope.Substr[base: tmp, start: parts.base.start, len: parts.base.length];
};
CourierBasename: PROC [in: ROPE] RETURNS [out: ROPE] ~ {
i: NAT;
j: NAT ← 0;
length: NAT ~ Rope.Length[in];
WHILE (j # length) DO
i ← j;
j ← Rope.SkipTo[in, (i+1), "Pp"];
ENDLOOP;
out ← Rope.Substr[base: in, start: 0, len: i];
};
DeriveCmd: PROC [spec: CourierProgram] RETURNS [cmd: ROPE] ~ {
formatOne: ROPEIO.PutFR["%g%g%g",
IO.rope["Sirocco %g;"],
IO.rope["TiogaMesa %g; Sleep 1;"],
IO.rope["TiogaMesa %gInit; Sleep 1;"]
];
formatTwo: ROPEIO.PutFR["%g%g%g%g%g",
IO.rope["%g"], -- first half
IO.rope["TiogaMesa %gAux; Sleep 1;"],
IO.rope["TiogaMesa %gAuxImpl; Sleep 1; "],
IO.rope["TiogaMesa %gClientImpl; Sleep 1; "],
IO.rope["TiogaMesa %gServerImpl; Sleep 1; "]
];
cmd ← IO.PutFR[formatOne,
IO.rope[GetSwitches[spec.resultPrefix]],
IO.rope[Basename[spec.filename]],
IO.rope[spec.interface],
IO.rope[spec.interface]
];
cmd ← IO.PutFR[formatTwo,
IO.rope[cmd],
IO.rope[spec.interface],
IO.rope[spec.interface],
IO.rope[spec.interface],
IO.rope[spec.interface]
];
};
DeriveFrom: PROC [spec: CourierProgram] RETURNS [from: From] ~ {
from ← [mustHave: LIST[spec.sourceNode], optional: NIL];
FOR each: ReferencedProgramList ← spec.dependsUpon, each.rest
WHILE (each # NIL) DO
interface: ROPE ~ Rope.Cat[each.first.name, "P", each.first.pid, "V", each.first.vid];
table: ROPE ~ Rope.Cat[interface, ".Tables"];
from.mustHave ← CONS [ MakeDo.GetNode[table, MakeDo.fileClass], from.mustHave];
ENDLOOP;
};
GetDependsUpon: PROC [spec: IO.STREAM] RETURNS [list: ReferencedProgramList ← NIL] ~ {
ENABLE {
IO.EndOfStream => {
GOTO ParseError;
};
IO.Error => {
GOTO ParseError;
};
};
shiftBox: ARRAY DependsParse OF ROPEALL[NIL];
skip: INT;
token: ROPE;
tokenKind: IO.TokenKind;
list ← CONS [NEW [ReferencedProgramObject], list];
DO
[tokenKind, token, skip] ← IO.GetCedarTokenRope[spec];
SELECT tokenKind FROM
tokenID => {
IF ( Rope.Equal[token, DEPENDS] ) THEN {
EXIT;
};
};
tokenSINGLE,
tokenDECIMAL,
tokenOCTAL,
tokenHEX,
tokenREAL,
tokenROPE,
tokenCHAR,
tokenATOM,
tokenDOUBLE,
tokenCOMMENT => {
NULL;
};
tokenERROR,
tokenEOF => {
RETURN [NIL];
};
ENDCASE;
ENDLOOP;
DO
[tokenKind, token, skip] ← IO.GetCedarTokenRope[spec];
SELECT tokenKind FROM
tokenID,
tokenDECIMAL,
tokenSINGLE => {
IF ( Rope.Equal[token, COMMA] ) THEN {
list.first.valid ← TRUE;
list.first.name ← shiftBox[name];
list.first.pid ← shiftBox[pid];
list.first.vid ← shiftBox[vid];
list ← CONS [NEW [ReferencedProgramObject], list];
};
IF ( Rope.Equal[token, SEMI] ) THEN {
list.first.valid ← TRUE;
list.first.name ← shiftBox[name];
list.first.pid ← shiftBox[pid];
list.first.vid ← shiftBox[vid];
EXIT;
};
FOR i: DependsParse IN [name .. version] DO
shiftBox[i] ← shiftBox[SUCC[i]];
ENDLOOP;
shiftBox[vid] ← token;
};
tokenOCTAL,
tokenHEX,
tokenREAL,
tokenROPE,
tokenCHAR,
tokenATOM,
tokenDOUBLE,
tokenCOMMENT => {
NULL;
};
tokenERROR,
tokenEOF => {
list.first.valid ← FALSE;
};
ENDCASE;
ENDLOOP;
IF (list.first.valid = FALSE) THEN list ← list.rest;
RETURN [list];
EXITS
ParseError => { RETURN [NIL]; };
};
GetSwitches: PROC [resultPrefix: ROPE] RETURNS [switches: ROPE] ~ {
ss: IO.STREAMNIL;
ss ← FS.StreamOpen[Rope.Cat[resultPrefix, ".SiroccoSwitches"]
! FS.Error => CONTINUE
];
IF (ss = NIL) THEN RETURN [NIL];
[] ← ss.SkipWhitespace[];
IF (ss.EndOf[]) THEN RETURN [NIL];
switches ← ss.GetLineRope[];
IO.Close[ss];
};
GuessForSpec: PROC [in: ROPE] RETURNS [list: CourierProgramList ← NIL] ~ {
ParseEachSpec: PROC [fullFName: ROPE] RETURNS [continue: BOOLTRUE] ~ {
ENABLE {
IO.EndOfStream => {
GOTO ParseError;
};
IO.Error => {
GOTO ParseError;
};
};
shiftBox: ARRAY ProgramParse OF ROPEALL[NIL];
skip: INT;
spec: IO.STREAMNIL;
token: ROPE;
tokenKind: IO.TokenKind;
spec ← FS.StreamOpen[fullFName
! FS.Error => CONTINUE
];
IF (spec = NIL) THEN RETURN [TRUE];
list ← CONS [NEW [CourierProgramObject], list];
DO
[tokenKind, token, skip] ← IO.GetCedarTokenRope[spec];
SELECT tokenKind FROM
tokenID,
tokenDECIMAL,
tokenSINGLE => {
IF ( Rope.Equal[token, EQUAL] ) THEN {
list.first.found ← TRUE;
EXIT;
};
FOR i: ProgramParse IN [name .. version] DO
shiftBox[i] ← shiftBox[SUCC[i]];
ENDLOOP;
shiftBox[vid] ← token;
};
tokenOCTAL,
tokenHEX,
tokenREAL,
tokenROPE,
tokenCHAR,
tokenATOM,
tokenDOUBLE,
tokenCOMMENT => {
NULL;
};
tokenERROR,
tokenEOF => {
list.first.found ← FALSE;
};
ENDCASE;
ENDLOOP;
list.first.filename ← fullFName;
list.first.program ← shiftBox[name];
list.first.pid ← shiftBox[pid];
list.first.vid ← shiftBox[vid];
list.first.interface ← Rope.Cat[list.first.program, "P", list.first.pid, "V", list.first.vid];
IF (list.first.found = TRUE) THEN list.first.dependsUpon ← GetDependsUpon[spec];
IO.Close[spec];
RETURN [TRUE];
EXITS
ParseError => {
list ← list.rest;
RETURN [TRUE];
};
};
FS.EnumerateForNames[in, ParseEachSpec];
};
Heuristic: PROC [interfaceName: ROPE]
RETURNS [specDetails: CourierProgram ← NIL] ~ {
FOR j: INT DECREASING IN (0 .. interfaceName.Length[]) DO
SELECT interfaceName.InlineFetch[j] FROM
IN ['0 .. '9], 'V => NULL;
'P => {
filename: ROPE ~ interfaceName.Substr[len: j].Concat["*.cr"];
list: CourierProgramList ~ GuessForSpec[filename];
FOR each: CourierProgramList ← list, each.rest WHILE (each # NIL) DO
specDetails ← each.first;
IF specDetails.interface.Equal[interfaceName, FALSE] THEN RETURN;
ENDLOOP;
specDetails ← NIL;
};
ENDCASE => EXIT;
ENDLOOP;
RETURN;
};
SiroccoFind: PROC [resultName: ROPE, finderData: REF ANY] RETURNS [found: BOOLEAN, sought: Node, makes, cmdFrom: NodeList, from: From, cmd: ROPE, class: ActionClass, foundData: REF ANY] ~ {
Global State (EndsIn side effects)
discoveredSuffix: ROPE;
programLength: INT ← 0--only to prevent compiler warnings about uninitialized--;
interfaceName: ROPE;
spec: CourierProgram;
resultCP: FS.ComponentPositions;
resultFull: ROPE;
resultShort: ROPE;
basenameLength: INT;
specDetails: CourierProgram;
EndsIn: PROC [word: ROPE, suffix: ROPE] RETURNS [ans: BOOL] ~ {
suffixLength: INT ~ suffix.Length[];
wordLength: INT ~ word.Length[];
tail: ROPE;
IF (suffixLength > wordLength) THEN RETURN [FALSE];
tail ← Rope.Substr[base: word, start: (wordLength - suffixLength), len: suffixLength];
IF (ans ← Rope.Equal[s1: suffix, s2: tail, case: FALSE]) THEN {
programLength ← (wordLength - suffixLength);
discoveredSuffix ← suffix;
};
};
Tail: PROC [suffix: ROPE] RETURNS [node: Node] ~ {
node ← MakeDo.GetNode[Rope.Cat[specDetails.resultPrefix, suffix], MakeDo.fileClass];
IF (Rope.Equal[suffix, discoveredSuffix]) THEN sought ← node;
};
sought ← NIL;
found ← TRUE;
[resultFull, resultCP, ] ← FS.ExpandName[resultName
! FS.Error => {found ← FALSE; CONTINUE}
];
IF (NOT found) THEN RETURN;
basenameLength ← (resultCP.ext.start + resultCP.ext.length) - resultCP.base.start;
resultShort ← Rope.Substr[base: resultFull, start: resultCP.base.start, len: basenameLength];
found ← EndsIn[resultShort, ".Tables"]
OR EndsIn[resultShort, ".Mesa"]
OR EndsIn[resultShort, "Init.Mesa"]
OR EndsIn[resultShort, "Aux.Mesa"]
OR EndsIn[resultShort, "AuxImpl.Mesa"]
OR EndsIn[resultShort, "ClientImpl.Mesa"]
OR EndsIn[resultShort, "ServerImpl.Mesa"];
IF (NOT found) THEN RETURN;
interfaceName ← Rope.Substr[base: resultShort, start: 0, len: programLength];
specDetails ← Heuristic[interfaceName];
IF (specDetails = NIL) THEN {
found ← FALSE;
RETURN;
};
specDetails.resultPrefix ← Rope.Substr[base: resultFull, start: 0, len: resultCP.base.start];
specDetails.resultPrefix ← Rope.Concat[specDetails.resultPrefix, specDetails.interface];
specDetails.switchFile ← Rope.Cat[specDetails.resultPrefix, ".SiroccoSwitches"];
cmdFrom ← LIST[
specDetails.sourceNode ← MakeDo.GetNode[specDetails.filename, MakeDo.fileClass],
specDetails.switchesNode ← MakeDo.GetNode[specDetails.switchFile, MakeDo.fileClass]
];
foundData ← spec ← specDetails;
cmd ← DeriveCmd[spec];
makes ← LIST[
Tail[".Tables"],
Tail[".Mesa"],
Tail["Init.Mesa"],
Tail["Aux.Mesa"],
Tail["AuxImpl.Mesa"],
Tail["ClientImpl.Mesa"],
Tail["ServerImpl.Mesa"]
];
IF (sought = NIL) THEN ERROR;
from ← DeriveFrom[spec];
class ← siroccoClass;
};
MakeDo.AddFinder[["Sirocco", SiroccoFind], back];
}.