@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
112 lines • 6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.diffOfControlFlowGraphs = diffOfControlFlowGraphs;
const diff_graph_1 = require("../util/diff-graph");
const diff_1 = require("../util/diff");
const control_flow_graph_1 = require("./control-flow-graph");
const arrays_1 = require("../util/collections/arrays");
/**
* Compare two control flow graphs and return a report on the differences.
* If you simply want to check whether they equal, use {@link GraphDifferenceReport#isEqual|`<result>.isEqual()`}.
* @see {@link diffDataflowGraph} - for dataflow graphs
*/
function diffOfControlFlowGraphs(left, right, config) {
if (left.graph === right.graph) {
return new diff_graph_1.GraphDifferenceReport();
}
const ctx = (0, diff_graph_1.initDiffContext)(left, right, config);
diffDataflowGraphs(ctx);
return ctx.report;
}
function diffDataflowGraphs(ctx) {
diffRootVertices(ctx);
diffVertices(ctx);
diff_graph_1.GraphDiff.outgoingEdges(ctx, diffEdges);
}
function diffRootVertices(ctx) {
(0, diff_1.setDifference)(ctx.left.rootIds(), ctx.right.rootIds(), {
...ctx,
position: `${ctx.position}Root vertices differ in graphs. `
});
}
function diffVertices(ctx) {
const lVert = [...ctx.left.vertices(false).entries()];
const rVert = [...ctx.right.vertices(false).entries()];
if (lVert.length < rVert.length && !ctx.config.leftIsSubgraph
|| lVert.length > rVert.length && !ctx.config.rightIsSubgraph) {
ctx.report.addComment(`Detected different number of vertices! ${ctx.leftname} has ${lVert.length}, ${ctx.rightname} has ${rVert.length}`);
}
for (const [id, lInfo] of lVert) {
const rInfo = ctx.right.getVertex(id, false);
if (rInfo === undefined) {
if (!ctx.config.rightIsSubgraph) {
ctx.report.addComment(`Vertex ${id} is not present in ${ctx.rightname}`, { tag: 'vertex', id });
}
continue;
}
const lType = control_flow_graph_1.CfgVertex.getType(lInfo);
const rType = control_flow_graph_1.CfgVertex.getType(rInfo);
if (lType !== rType) {
ctx.report.addComment(`Vertex ${id} differs in tags. ${ctx.leftname}: ${control_flow_graph_1.CfgVertex.typeToString(lType)} vs. ${ctx.rightname}: ${control_flow_graph_1.CfgVertex.typeToString(rType)}`, {
tag: 'vertex',
id
});
}
const lCt = control_flow_graph_1.CfgVertex.getCallTargets(lInfo);
const rCt = control_flow_graph_1.CfgVertex.getCallTargets(rInfo);
if (lCt !== undefined || rCt !== undefined) {
(0, diff_1.setDifference)(new Set(lCt ?? []), new Set(rCt ?? []), {
...ctx,
position: `${ctx.position}Vertex ${id} differs in call targets. `
});
}
const lElems = control_flow_graph_1.CfgVertex.isBlock(lInfo) ? control_flow_graph_1.CfgVertex.getBasicBlockElements(lInfo) : undefined;
const rElems = control_flow_graph_1.CfgVertex.isBlock(rInfo) ? control_flow_graph_1.CfgVertex.getBasicBlockElements(rInfo) : undefined;
if (lElems !== undefined || rElems !== undefined) {
if (!(0, arrays_1.arrayEqual)((lElems ?? []), (rElems ?? []), control_flow_graph_1.CfgVertex.equal)) {
ctx.report.addComment(`Vertex ${id} differs in elems.\n ${ctx.leftname}: ${JSON.stringify(lElems)}\n vs\n ${ctx.rightname}: ${JSON.stringify(rElems)}`, { tag: 'vertex', id });
}
}
(0, diff_1.setDifference)(new Set(control_flow_graph_1.CfgVertex.getMid(lInfo) ?? []), new Set(control_flow_graph_1.CfgVertex.getMid(rInfo) ?? []), {
...ctx,
position: `${ctx.position}Vertex ${id} differs in attached mid markers. `
});
(0, diff_1.setDifference)(new Set(control_flow_graph_1.CfgVertex.getEnd(lInfo) ?? []), new Set(control_flow_graph_1.CfgVertex.getEnd(rInfo) ?? []), {
...ctx,
position: `${ctx.position}Vertex ${id} differs in attached end markers. `
});
const lRoot = control_flow_graph_1.CfgVertex.getRootId(lInfo);
const rRoot = control_flow_graph_1.CfgVertex.getRootId(rInfo);
if (lRoot !== rRoot) {
ctx.report.addComment(`Vertex ${id} differs in root. ${ctx.leftname}: ${JSON.stringify(lRoot)} vs ${ctx.rightname}: ${JSON.stringify(rRoot)}`, {
tag: 'vertex',
id
});
}
(0, diff_1.setDifference)(new Set(control_flow_graph_1.CfgVertex.getChildren(lInfo)), new Set(control_flow_graph_1.CfgVertex.getChildren(rInfo)), {
...ctx,
position: `${ctx.position}Vertex ${id} differs in children. `
});
}
}
function diffEdge(edge, otherEdge, ctx, id, target) {
const el = control_flow_graph_1.CfgEdge.getType(edge);
const ol = control_flow_graph_1.CfgEdge.getType(otherEdge);
if (el !== ol) {
ctx.report.addComment(`Edge ${id}->${target} differs in labels. ${ctx.leftname}: ${el} vs ${ctx.rightname}: ${ol}`, { tag: 'edge', from: id, to: target });
}
const ec = control_flow_graph_1.CfgEdge.getCause(edge);
const oc = control_flow_graph_1.CfgEdge.getCause(otherEdge);
if (ec !== oc) {
ctx.report.addComment(`Edge ${id}->${target} differs in caused. ${ctx.leftname}: ${JSON.stringify(ec)} vs ${ctx.rightname}: ${JSON.stringify(oc)}`, { tag: 'edge', from: id, to: target });
}
const ew = control_flow_graph_1.CfgEdge.getWhen(edge);
const ow = control_flow_graph_1.CfgEdge.getWhen(otherEdge);
if (ew !== ow) {
ctx.report.addComment(`Edge ${id}->${target} differs in when. ${ctx.leftname}: ${JSON.stringify(ew)} vs ${ctx.rightname}: ${JSON.stringify(ow)}`, { tag: 'edge', from: id, to: target });
}
}
function diffEdges(ctx, id, lEdges, rEdges) {
diff_graph_1.GraphDiff.edges(ctx, id, lEdges, rEdges, diffEdge);
}
//# sourceMappingURL=diff-cfg.js.map