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:
BOOL ←
FALSE]
--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:
ROPE ←
NIL]
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:
ROPE ←
NIL] = {
out: IO.STREAM = FS.StreamOpen[fileName: fileName, accessOptions: create];
Print[out, dg, wDir];
out.Close[];
};
Print:
PUBLIC
PROC [to:
IO.
STREAM, dg: DependencyGraph, wDir:
ROPE ←
NIL] = {
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:
ROPE ←
NIL]
RETURNS [dg: DependencyGraph] = {
in: IO.STREAM = FS.StreamOpen[fileName];
dg ← Read[in, wDir];
in.Close[];
};
Read:
PUBLIC
PROC [from:
IO.
STREAM, wDir:
ROPE ←
NIL]
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:
BOOL ←
FALSE]
--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.STREAM ← IO.ROS[]
];
UpdateCmd:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- = {
in: IO.STREAM = IO.RIS[cmd.commandLine];
doBringOver: BOOL ← TRUE;
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.STREAM ← IO.ROS[];
errors, warnings, bogons: INT ← 0;
goals: MakeDo.RefTable = MakeDo.MakeRefTable[];
modifiable: MakeDo.ModifiabilitySpec = MakeDo.MakeRefTable[];
changes: BOOL ← FALSE;
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:
BOOL ←
FALSE, abortMessageForLog:
ROPE ←
NIL, response:
REF
ANY ←
NIL]
--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"];
}.