DFDependenciesImpl.Mesa
Spreitzer, April 24, 1986 3:36:41 pm PST
DIRECTORY Basics, CedarProcess, Commander, CommandTool, DFDependencies, DFDependenciesPrivate, DFOperations, FileSets, FS, HashTable, IO, MakeDo, RedBlackTree, Rope;
DFDependenciesImpl: CEDAR PROGRAM
IMPORTS CedarProcess, Commander, DFOperations, FileSets, FS, HashTable, IO, MakeDo, RedBlackTree, Rope
EXPORTS DFDependencies
= {OPEN DFDependencies, DFDependenciesPrivate;
DependencyGraph: TYPE = REF DependencyGraphPrivate;
DependencyGraphPrivate: PUBLIC TYPE = DFDependenciesPrivate.DependencyGraphPrivate;
NewDG: PROC RETURNS [dg: DependencyGraph] = {
dg ← NEW [DependencyGraphPrivate ← [
verticesByBase: HashTable.Create[hash: HashTable.HashRopeModCase, equal: HashTable.RopeEqualModCase]
]];
};
Analyze: PUBLIC PROC [dfs: FileSet, filter: FileSets.Filter ← NIL] RETURNS [dg: DependencyGraph] = {
PerDF: PROC [fn: FileSets.FileNote] --FileSets.FileConsumer-- = {
naming: Naming = Canonize[fn.fsName];
v: Vertex = GetVertex[dg, naming];
mentions: FileSet = FileSets.MentionedDFs[fn.fsName, [], [version: FALSE]];
SeeProvider: PROC [fn: FileSets.FileNote] --FileSets.FileConsumer-- = {
IF filter = NIL OR filter.Eval[fn, filter.data] THEN {
naming2: Naming = Canonize[fn.fsName];
w: Vertex = GetVertex[dg, naming2];
Link[v, w];
};
};
mentions.EnumSet[SeeProvider];
};
dg ← NewDG[];
dfs.EnumSet[PerDF];
TopoSort[dg];
};
Canonize: PROC [given: ROPE, wDir: ROPENIL] RETURNS [naming: Naming] = {
cp: FS.ComponentPositions;
[naming.long, cp] ← FS.ExpandName[given, wDir];
naming.long ← naming.long.Substr[len: cp.base.start + cp.base.length];
naming.base ← naming.long.Substr[start: cp.base.start];
};
GetVertex: PROC [dg: DependencyGraph, naming: Naming] RETURNS [v: Vertex] = {
v ← NARROW[dg.verticesByBase.Fetch[naming.base].value];
IF v = NIL THEN {
v ← NEW [VertexPrivate ← [naming]];
IF NOT dg.verticesByBase.Insert[naming.base, v] THEN ERROR;
};
};
Link: PROC [dependent, provider: Vertex] = {
dependent.providers ← CONS[provider, dependent.providers];
provider.dependents ← CONS[dependent, provider.dependents];
};
PrintToFile: PUBLIC PROC [fileName: ROPE, dg: DependencyGraph, wDir: ROPENIL] = {
out: IO.STREAM = FS.StreamOpen[fileName: fileName, accessOptions: create];
Print[out, dg, wDir];
out.Close[];
};
Print: PUBLIC PROC [to: IO.STREAM, dg: DependencyGraph, wDir: ROPENIL] = {
wDirLen: INT = wDir.Length[];
PerVertex: PROC [key, value: REF ANY] RETURNS [quit: BOOLEANFALSE] --HashTable.EachPairAction-- = {
v: Vertex = NARROW[value];
PrintName[v];
to.PutRope[":"];
ForDependents[v, PrintDependent];
to.PutRope[";\n\n"];
};
PrintDependent: PROC [v: Vertex] = {
to.PutRope[" "];
PrintName[v];
};
PrintName: PROC [v: Vertex] = {
name: ROPE = v.naming.long;
clip: BOOL = wDirLen > 0 AND name.Length[] > wDirLen AND wDir.Equal[name.Substr[len: wDirLen], FALSE];
to.PutRope[IF clip THEN name.Substr[start: wDirLen] ELSE name];
};
[] ← dg.verticesByBase.Pairs[PerVertex];
dg ← dg;
};
ReadFromFile: PUBLIC PROC [fileName: ROPE, wDir: ROPENIL] RETURNS [dg: DependencyGraph] = {
in: IO.STREAM = FS.StreamOpen[fileName];
dg ← Read[in, wDir];
in.Close[];
};
Read: PUBLIC PROC [from: IO.STREAM, wDir: ROPENIL] RETURNS [dg: DependencyGraph] = {
dg ← NewDG[];
FOR i: INT ← from.SkipWhitespace[], from.SkipWhitespace[] WHILE NOT from.EndOf[] DO
providerGiven: ROPE = from.GetTokenRope[Break].token;
providerNaming: Naming = Canonize[providerGiven, wDir];
provider: Vertex = GetVertex[dg, providerNaming];
toke: ROPE ← from.GetTokenRope[Break].token;
IF NOT toke.Equal[":"] THEN ERROR;
FOR toke ← from.GetTokenRope[Break].token, from.GetTokenRope[Break].token WHILE NOT toke.Equal[";"] DO
dependentNaming: Naming = Canonize[toke, wDir];
dependent: Vertex = GetVertex[dg, dependentNaming];
Link[dependent, provider];
ENDLOOP;
dg ← dg;
ENDLOOP;
TopoSort[dg];
};
Break: PROC [char: CHAR] RETURNS [cc: IO.CharClass] --IO.BreakProc-- = {
cc ← SELECT char FROM
':, '; => break,
IN [IO.NUL .. IO.SP] => sepr,
ENDCASE => other;
};
TopoSort: PROC [dg: DependencyGraph] = {
ClearRank: PROC [v: Vertex] = {v.rank ← notRanked};
EnsureRanked: PROC [v: Vertex] = {
rank: INT ← 0;
RankProvider: PROC [w: Vertex] = {
IF w.rank = ranking THEN ERROR--discovered cycle in graph--;
EnsureRanked[w];
rank ← MAX[rank, w.rank+1];
};
IF v.rank # notRanked THEN RETURN;
rank ← 0;
v.rank ← ranking;
ForProviders[v, RankProvider];
v.rank ← rank;
};
EnumVertices[dg, ClearRank];
EnumVertices[dg, EnsureRanked];
};
ranking: INT = LAST[INT];
Track: PUBLIC PROC [dg: DependencyGraph, from: ROPE, parent: Commander.Handle, boo: BringOverOp] RETURNS [failures: RopeList] = {
root: Vertex = NARROW[dg.verticesByBase.Fetch[from].value];
byRankThenName: RedBlackTree.Table = RedBlackTree.Create[GetRNKey, CompareRNs];
Setup: PROC [v: Vertex] = {
IF byRankThenName.Lookup[v] # NIL THEN RETURN;
byRankThenName.Insert[v, v];
v.avoid ← v.tried ← v.failed ← FALSE;
ForDependents[v, Setup];
};
Avoid: PROC [v: Vertex] = {
v.avoid ← TRUE;
ForDependents[v, Avoid];
};
FixIt: PROC [data: REF ANY] RETURNS [stop: BOOLFALSE] --RedBlackTree.EachNode-- = {
v: Vertex = NARROW[data];
IF NOT v.avoid THEN {
success: BOOL = Update[v.naming.long, parent, boo];
v.avoid ← TRUE;
v.tried ← TRUE;
v.failed ← NOT success;
IF v.failed THEN {
failures ← CONS[v.naming.base, failures];
ForDependents[v, Avoid];
};
data ← data;
};
};
ForDependents[root, Setup];
byRankThenName.EnumerateIncreasing[FixIt];
};
GetRNKey: PROC [data: REF ANY] RETURNS [v: Vertex] --RedBlackTree.GetKey-- = {
v ← NARROW[data];
};
CompareRNs: PROC [k, data: REF ANY] RETURNS [c: Basics.Comparison] --RedBlackTree.Compare-- = {
k1: Vertex = NARROW[k];
k2: Vertex = NARROW[data];
c ← SELECT k1.rank FROM
< k2.rank => less,
= k2.rank => k1.naming.long.Compare[k2.naming.long, FALSE],
> k2.rank => greater,
ENDCASE => ERROR;
};
EnumVertices: PROC [dg: DependencyGraph, Consume: PROC [Vertex]] = {
SeeVertex: PROC [key, value: REF ANY] RETURNS [quit: BOOLFALSE]--HashTable.EachPairAction-- = {
v: Vertex = NARROW[value];
Consume[v];
};
[] ← dg.verticesByBase.Pairs[SeeVertex];
};
ForDependents: PROC [v: Vertex, Do: PROC [Vertex]] = {
v ← v;
FOR vl: DependentList ← v.dependents, vl.rest WHILE vl # NIL DO
Do[vl.first];
ENDLOOP;
v ← v;
};
ForProviders: PROC [v: Vertex, Do: PROC [Vertex]] = {
v ← v;
FOR vl: ProviderList ← v.providers, vl.rest WHILE vl # NIL DO
Do[vl.first];
ENDLOOP;
v ← v;
};
Tracking: TYPE = REF TrackingPrivate;
TrackingPrivate: TYPE = RECORD [
bogons: INT ← 0,
op: {BringOver, SModel, VerifyDF} ← BringOver,
myMsgs: IO.STREAMIO.ROS[]
];
UpdateCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ANYNIL, msg: ROPENIL] --Commander.CommandProc-- = {
in: IO.STREAM = IO.RIS[cmd.commandLine];
doBringOver: BOOLTRUE;
FOR i: INT ← in.SkipWhitespace[], in.SkipWhitespace[] WHILE NOT in.EndOf[] DO
given: ROPE = in.GetTokenRope[IO.IDProc].token;
SELECT TRUE FROM
given.Equal["-b", FALSE] => doBringOver ← FALSE;
given.Equal["+b", FALSE] => doBringOver ← TRUE;
ENDCASE => {
success: BOOL = Update[given, cmd, [doBringOver, []]];
IF NOT success THEN RETURN [$Failure];
};
ENDLOOP;
in.Close[];
};
Update: PUBLIC PROC [subject: ROPE, cmd: Commander.Handle, boo: BringOverOp] RETURNS [success: BOOL] = {
naming: Naming = Canonize[subject];
log: IO.STREAM = cmd.out;
dfName: ROPE = naming.long.Concat[".DF"];
dfShortName: ROPE = naming.base.Concat[".DF"];
t: Tracking = NEW [TrackingPrivate ← []];
ros: IO.STREAMIO.ROS[];
errors, warnings, bogons: INT ← 0;
goals: MakeDo.RefTable = MakeDo.MakeRefTable[];
modifiable: MakeDo.ModifiabilitySpec = MakeDo.MakeRefTable[];
changes: BOOLFALSE;
CedarProcess.CheckAbort[];
log.PutF["\n%l%g:%l ", [rope["lb"]], [rope[naming.base]], [rope["LB"]]];
IF boo.doBringOver THEN {
log.PutRope[" . BringOver . "];
[errors: errors, warnings: warnings] ← DFOperations.BringOver[
dfFile: dfName,
filter: boo.filter,
action: checkAndEnter,
interact: Interact,
clientData: t,
log: ros
];
IF errors#0 OR warnings#0 THEN {
log.PutRope["\n"];
cmd.out.PutRope[ros.RopeFromROS[]];
RETURN [FALSE];
};
};
log.PutRope[" . MakeDo . "];
warnings ← 0;
{ENABLE MakeDo.Warning => {
log.PutRope[Rope.Cat["\n", message, "\n"]];
warnings ← warnings + 1;
RESUME
};
nSteps: INT;
nonOKGoalList: MakeDo.NodeList ← NIL;
MakeDo.AnalyzeDFFile[dfShortName, goals, modifiable, makeGoal, makeModifiable];
[nonOKGoalCount: errors, nonOKGoalList: nonOKGoalList, nSteps: nSteps] ← MakeDo.Ensure[goals, modifiable, cmd];
IF nonOKGoalList # NIL THEN {
cmd.out.PutF["%lNot OK:", [rope["b"]]];
FOR nonOKGoalList ← nonOKGoalList, nonOKGoalList.rest WHILE nonOKGoalList # NIL DO
cmd.out.PutRope[" "];
cmd.out.PutRope[nonOKGoalList.first.DescribeNode[]];
ENDLOOP;
cmd.out.PutF["%l\n", [rope["B"]]];
};
changes ← nSteps # 0;
};
IF errors#0 OR warnings#0 THEN RETURN [FALSE];
IF changes THEN {
log.PutRope[" . SModel . "];
ros ← IO.ROS[];
t.myMsgs ← IO.ROS[];
t.op ← SModel;
[errors: errors, warnings: warnings] ← DFOperations.SModel[
dfFile: dfName,
interact: Interact,
clientData: t,
log: ros
];
IF errors#0 OR warnings#0 THEN {
log.PutRope["\n"];
cmd.out.PutRope[ros.RopeFromROS[]];
RETURN [FALSE];
};
log.PutRope[" . VerifyDF . "];
ros ← IO.ROS[];
t.myMsgs ← IO.ROS[];
t.op ← VerifyDF;
[errors: errors, warnings: warnings] ← DFOperations.Verify[
dfFile: dfName,
interact: Interact,
clientData: t,
log: ros
];
IF errors#0 OR warnings-t.bogons#0 THEN {
log.PutRope["\n"];
cmd.out.PutRope[ros.RopeFromROS[]];
RETURN [FALSE];
};
};
log.PutRope["\n"];
success ← TRUE;
};
Interact: PROC [interaction: REF ANY, clientData: REF ANY] RETURNS [abort: BOOLFALSE, abortMessageForLog: ROPENIL, response: REF ANYNIL] --DFOperations.InteractionProc-- = {
t: Tracking = NARROW[clientData];
WITH interaction SELECT FROM
x: REF DFOperations.InfoInteraction => {
IF t.op = VerifyDF AND x.class = warning AND Rope.Match[pattern: "*Imports*without a Using*", object: x.message, case: FALSE] THEN t.bogons ← t.bogons + 1
ELSE SELECT x.class FROM
info => NULL;
warning, error, abort => t.myMsgs.PutF["%g\n", [rope[x.message]]];
ENDCASE;
};
ENDCASE;
};
Commander.Register["Update", UpdateCmd, "Updates a package's DF file by BringOver; MakeDo; SModel; VerifyDF"];
}.