DFDependenciesImpl.Mesa
Mike Spreitzer September 27, 1986 3:50:11 pm PDT
DIRECTORY Asserting, Basics, CedarProcess, Commander, CommandTool, DFDependencies, DFDependenciesPrivate, DFOperations, FileSets, FS, GraphOps, Graphs, HashTable, IO, MakeDo, RedBlackTree, Rope;
DFDependenciesImpl: CEDAR PROGRAM
IMPORTS CedarProcess, Commander, DFOperations, FileSets, FS, Graphs, GraphOps, HashTable, IO, MakeDo, RedBlackTree, Rope
EXPORTS DFDependencies
= {OPEN DFDependencies, DFDependenciesPrivate;
NewDG: PROC RETURNS [dg: DependencyGraph] = {
dgr: DependencyGraphRep = NEW [DependencyGraphRepPrivate ← [
verticesByBase: HashTable.Create[hash: HashTable.HashRopeModCase, equal: HashTable.RopeEqualModCase]
]];
dg ← [dgr, dependencyGraphClass];
};
dependencyGraphClass: Graphs.GraphClass = NEW [Graphs.GraphClassPrivate ← [
ChangeOther: ChangeGraphOther,
EnumerateVertices: EnumerateVertices
]];
ChangeGraphOther: PROC [g: Graphs.Graph, Change: PROC [Asserting.Assertions] RETURNS [Asserting.Assertions]] = {
dgr: DependencyGraphRep = NARROW[g.rep];
dgr.other ← Change[dgr.other];
};
EnumerateVertices: PROC [graph: Graph, Consume: PROC [Graphs.Vertex]] = {
dgr: DependencyGraphRep = NARROW[graph.rep];
SeeVertex: PROC [key, value: REF ANY] RETURNS [quit: BOOLFALSE]--HashTable.EachPairAction-- = {
dgv: DGVertex = NARROW[value];
Consume[[dgv, vClass]];
};
[] ← dgr.verticesByBase.Pairs[SeeVertex];
};
vClass: Graphs.VertexClass = NEW [Graphs.VertexClassPrivate ← [
ChangeOther: ChangeOther,
Expand: Expand,
GetLabel: GetLabel]];
GetLabel: PROC [vertex: Graphs.Vertex] RETURNS [label: ROPE] = {
dgv: DGVertex = NARROW[vertex.rep];
label ← dgv.naming.base;
};
ChangeOther: PROC [v: Graphs.Vertex, Change: PROC [Asserting.Assertions] RETURNS [Asserting.Assertions]] = {
dgv: DGVertex = NARROW[v.rep];
dgv.other ← Change[dgv.other];
};
Expand: PROC [vertex: Graphs.Vertex, Consume: Graphs.EdgeConsumer, filter: Graphs.DirectionFilter ← Graphs.allDirections] = {
dgv: DGVertex = NARROW[vertex.rep];
IF filter[Incoming] THEN {
FOR vl: DependentList ← dgv.dependents, vl.rest WHILE vl # NIL DO
Consume[Graphs.dullEdge, Incoming, [vl.first, vClass]];
ENDLOOP;
};
IF filter[Outgoing] THEN {
FOR vl: ProviderList ← dgv.providers, vl.rest WHILE vl # NIL DO
Consume[Graphs.dullEdge, Outgoing, [vl.first, vClass]];
ENDLOOP;
};
};
ForDependents: PROC [dgv: DGVertex, Consume: PROC [DGVertex]] = {
FOR vl: DependentList ← dgv.dependents, vl.rest WHILE vl # NIL DO
Consume[vl.first];
ENDLOOP;
dgv ← dgv;
};
ForProviders: PROC [dgv: DGVertex, Consume: PROC [DGVertex]] = {
FOR vl: DependentList ← dgv.providers, vl.rest WHILE vl # NIL DO
Consume[vl.first];
ENDLOOP;
dgv ← dgv;
};
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: DGVertex = 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: DGVertex = GetVertex[dg, naming2];
Link[v, w];
};
};
mentions.EnumSet[SeeProvider];
};
dg ← NewDG[];
dfs.EnumSet[PerDF];
};
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 [dgv: DGVertex] = {
dgr: DependencyGraphRep = NARROW[dg.rep];
dgv ← NARROW[dgr.verticesByBase.Fetch[naming.base].value];
IF dgv = NIL THEN {
dgv ← NEW [DGVertexPrivate ← [naming]];
IF NOT dgr.verticesByBase.Insert[naming.base, dgv] THEN ERROR;
};
};
Link: PROC [dependent, provider: DGVertex] = {
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 [v: Graphs.Vertex] = {
dgv: DGVertex = NARROW[v.rep];
PrintName[dgv];
to.PutRope[":"];
ForDependents[dgv, PrintDependent];
to.PutRope[";\n\n"];
};
PrintDependent: PROC [dgv: DGVertex] = {
to.PutRope[" "];
PrintName[dgv];
};
PrintName: PROC [dgv: DGVertex] = {
name: ROPE = dgv.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.class.EnumerateVertices[dg, 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: DGVertex = 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: DGVertex = GetVertex[dg, dependentNaming];
Link[dependent, provider];
ENDLOOP;
dg ← dg;
ENDLOOP;
};
Break: PROC [char: CHAR] RETURNS [cc: IO.CharClass] --IO.BreakProc-- = {
cc ← SELECT char FROM
':, '; => break,
IN [IO.NUL .. IO.SP] => sepr,
ENDCASE => other;
};
Track: PUBLIC PROC [dg: DependencyGraph, from: ROPE, parent: Commander.Handle, boo: BringOverOp] RETURNS [failures: RopeList] = {
dgr: DependencyGraphRep = NARROW[dg.rep];
root: DGVertex = NARROW[dgr.verticesByBase.Fetch[from].value];
byRankThenName: RedBlackTree.Table = RedBlackTree.Create[GetRNKey, CompareRNs];
Setup: PROC [dgv: DGVertex] = {
IF byRankThenName.Lookup[dgv] # NIL THEN RETURN;
byRankThenName.Insert[dgv, dgv];
dgv.avoid ← dgv.tried ← dgv.failed ← FALSE;
ForDependents[dgv, Setup];
};
Avoid: PROC [dgv: DGVertex] = {
dgv.avoid ← TRUE;
ForDependents[dgv, Avoid];
};
FixIt: PROC [data: REF ANY] RETURNS [stop: BOOLFALSE] --RedBlackTree.EachNode-- = {
dgv: DGVertex = NARROW[data];
IF NOT dgv.avoid THEN {
success: BOOL = Update[dgv.naming.long, parent, boo];
dgv.avoid ← TRUE;
dgv.tried ← TRUE;
dgv.failed ← NOT success;
IF dgv.failed THEN {
failures ← CONS[dgv.naming.base, failures];
ForDependents[dgv, Avoid];
};
data ← data;
};
};
IF NOT GraphOps.GraphRanked[dg, depDir] THEN GraphOps.RankGraph[dg, depDir];
ForDependents[root, Setup];
byRankThenName.EnumerateIncreasing[FixIt];
};
depDir: Graphs.Direction ← Outgoing;
GetRNKey: PROC [data: REF ANY] RETURNS [dgv: DGVertex] --RedBlackTree.GetKey-- = {
dgv ← NARROW[data];
};
CompareRNs: PROC [k, data: REF ANY] RETURNS [c: Basics.Comparison] --RedBlackTree.Compare-- = {
k1: DGVertex = NARROW[k];
k2: DGVertex = NARROW[data];
r1: INT = GraphOps.VertexRank[[k1, vClass], depDir];
r2: INT = GraphOps.VertexRank[[k2, vClass], depDir];
c ← SELECT r1 FROM
< r2 => less,
= r2 => k1.naming.long.Compare[k2.naming.long, FALSE],
> r2 => greater,
ENDCASE => ERROR;
};
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"];
}.