UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

123 lines 5.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GraphDiff = exports.GraphDifferenceReport = void 0; exports.initDiffContext = initDiffContext; const json_1 = require("./json"); /** * To be produced by a function differencing two graphs (e.g., {@link DataflowGraph|DFGs} or {@link ControlFlowGraph|CFGs}). * @see {@link GraphDifferenceReport#isEqual|isEqual} - to check whether the graphs are equal * @see {@link GraphDifferenceReport#addComment|addComment} - to add comments to the report * @see {@link GraphDifferenceReport#comments|comments} - to get the attached comments * @see {@link GraphDifferenceReport#problematic|problematic} - to get the problematic vertices/edges */ class GraphDifferenceReport { _comments = undefined; _problematic = undefined; addComment(comment, ...related) { if (this._comments === undefined) { this._comments = [comment]; } else { this._comments.push(comment); } if (related.length > 0) { if (this._problematic === undefined) { this._problematic = [...related]; } else { this._problematic.push(...related); } } } comments() { return this._comments; } problematic() { return this._problematic; } isEqual() { return this._comments === undefined; } } exports.GraphDifferenceReport = GraphDifferenceReport; /** * Create the context for differencing two graphs */ function initDiffContext(left, right, config) { return { left: left.graph, leftname: left.name, right: right.graph, rightname: right.name, report: new GraphDifferenceReport(), position: '', config: { rightIsSubgraph: false, leftIsSubgraph: false, ...config } }; } /** The edge-differencing steps shared by the dataflow and the control flow graph diff. */ exports.GraphDiff = { name: 'GraphDiff', /** Compares all edges of both graphs vertex by vertex, handing each pair to `diffEdges`. */ outgoingEdges(ctx, diffEdges) { const lEdges = new Map(ctx.left.edges()); const rEdges = new Map(ctx.right.edges()); if (lEdges.size < rEdges.size && !ctx.config.leftIsSubgraph || lEdges.size > rEdges.size && !ctx.config.rightIsSubgraph) { ctx.report.addComment(`Detected different number of edges! ${ctx.leftname} has ${lEdges.size} (${JSON.stringify(lEdges, json_1.jsonReplacer)}). ${ctx.rightname} has ${rEdges.size} ${JSON.stringify(rEdges, json_1.jsonReplacer)}`); } for (const [id, edge] of lEdges) { /* This has nothing to do with the subset relation as we verify this in the same graph. * Yet we still do the check as a subgraph may not have to have all source vertices for edges. */ if (!ctx.left.hasVertex(id)) { if (!ctx.config.leftIsSubgraph) { ctx.report.addComment(`The source ${id} of edges ${JSON.stringify(edge, json_1.jsonReplacer)} is not present in ${ctx.leftname}. This means that the graph contains an edge but not the corresponding vertex.`); continue; } } diffEdges(ctx, id, edge, rEdges.get(id)); } // just to make it both ways in case the length differs for (const [id, edge] of rEdges) { if (!ctx.right.hasVertex(id)) { if (!ctx.config.rightIsSubgraph) { ctx.report.addComment(`The source ${id} of edges ${JSON.stringify(edge, json_1.jsonReplacer)} is not present in ${ctx.rightname}. This means that the graph contains an edge but not the corresponding vertex.`); continue; } } if (!ctx.config.leftIsSubgraph && !lEdges.has(id)) { diffEdges(ctx, id, undefined, edge); } /* otherwise, we already cover the edge above */ } }, /** Compares the outgoing edges of a single vertex, handing each pair of edges to `diffEdge`. */ edges(ctx, id, lEdges, rEdges, diffEdge) { if (lEdges === undefined || rEdges === undefined) { if ((lEdges === undefined && !ctx.config.leftIsSubgraph) || (rEdges === undefined && !ctx.config.rightIsSubgraph)) { ctx.report.addComment(`Vertex ${id} has undefined outgoing edges. ${ctx.leftname}: ${JSON.stringify(lEdges, json_1.jsonReplacer)} vs ${ctx.rightname}: ${JSON.stringify(rEdges, json_1.jsonReplacer)}`, { tag: 'vertex', id }); } return; } if (lEdges.size < rEdges.size && !ctx.config.leftIsSubgraph || lEdges.size > rEdges.size && !ctx.config.rightIsSubgraph) { ctx.report.addComment(`Vertex ${id} differs in number of outgoing edges. ${ctx.leftname}: [${[...lEdges.keys()].join(',')}] vs ${ctx.rightname}: [${[...rEdges.keys()].join(',')}] `, { tag: 'vertex', id }); } // order independent compare for (const [target, edge] of lEdges) { const otherEdge = rEdges.get(target); if (otherEdge === undefined) { if (!ctx.config.rightIsSubgraph) { ctx.report.addComment(`Target of ${id}->${target} in ${ctx.leftname} is not present in ${ctx.rightname}`, { tag: 'edge', from: id, to: target }); } continue; } diffEdge(edge, otherEdge, ctx, id, target); } } }; //# sourceMappingURL=diff-graph.js.map