UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

100 lines 4.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addNonDefaultExitPoints = addNonDefaultExitPoints; exports.initializeCleanDataflowInformation = initializeCleanDataflowInformation; exports.happensInEveryBranch = happensInEveryBranch; exports.alwaysExits = alwaysExits; exports.filterOutLoopExitPoints = filterOutLoopExitPoints; exports.diffControlDependency = diffControlDependency; exports.diffControlDependencies = diffControlDependencies; const graph_1 = require("./graph/graph"); /** * Adds all non-default exit points to the existing list. */ function addNonDefaultExitPoints(existing, add) { existing.push(...add.filter(({ type }) => type !== 0 /* ExitPointType.Default */)); } /** * Initializes an empty {@link DataflowInformation} object with the given entry point and data. * This is to be used as a "starting point" when processing leaf nodes during the dataflow extraction. * * @see {@link DataflowInformation} */ function initializeCleanDataflowInformation(entryPoint, data) { return { unknownReferences: [], in: [], out: [], environment: data.environment, graph: new graph_1.DataflowGraph(data.completeAst.idMap), entryPoint, exitPoints: [{ nodeId: entryPoint, type: 0 /* ExitPointType.Default */, controlDependencies: undefined }] }; } /** * Checks whether the given control dependencies are exhaustive (i.e. if for every control dependency on a boolean, * the list contains a dependency on the `true` and on the `false` case). */ function happensInEveryBranch(controlDependencies) { if (controlDependencies === undefined) { /* the cds are unconstrained */ return true; } else if (controlDependencies.length === 0) { /* this happens only when we have no idea and require more analysis */ return false; } const trues = []; const falseSet = new Set(); for (const { id, when } of controlDependencies) { if (when) { trues.push(id); } else { falseSet.add(id); } } return trues.every(id => falseSet.has(id)); } /** * Checks whether the given dataflow information always exits (i.e., if there is a non-default exit point in every branch). * @see {@link ExitPoint} - for the different types of exit points */ function alwaysExits(data) { return data.exitPoints?.some(e => e.type !== 0 /* ExitPointType.Default */ && happensInEveryBranch(e.controlDependencies)) ?? false; } /** * Filters out exit points which end their cascade within a loop. */ function filterOutLoopExitPoints(exitPoints) { return exitPoints.filter(({ type }) => type === 1 /* ExitPointType.Return */ || type === 0 /* ExitPointType.Default */); } function diffControlDependency(a, b, info) { if (a === undefined || b === undefined) { if (a !== b) { info.report.addComment(`${info.position}Different control dependencies. ${info.leftname}: ${JSON.stringify(a)} vs. ${info.rightname}: ${JSON.stringify(b)}`); } return; } if (a.id !== b.id) { info.report.addComment(`${info.position}Different control dependency ids. ${info.leftname}: ${a.id} vs. ${info.rightname}: ${b.id}`); } if (a.when !== b.when) { info.report.addComment(`${info.position}Different control dependency when. ${info.leftname}: ${a.when} vs. ${info.rightname}: ${b.when}`); } } function diffControlDependencies(a, b, info) { if (a === undefined || b === undefined) { if (a !== b) { info.report.addComment(`${info.position}Different control dependencies: ${JSON.stringify(a)} vs. ${JSON.stringify(b)}`); } return; } if (a.length !== b.length) { info.report.addComment(`${info.position}Different control dependency lengths: ${a.length} vs. ${b.length}`); } for (let i = 0; i < a.length; ++i) { diffControlDependency(a[i], b[i], { ...info, position: `${info.position}Control dependency at index: ${i}: ` }); } } //# sourceMappingURL=info.js.map