@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
62 lines • 3.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.processWhileLoop = processWhileLoop;
const info_1 = require("../../../../../info");
const linker_1 = require("../../../../linker");
const known_call_handling_1 = require("../known-call-handling");
const assert_1 = require("../../../../../../util/assert");
const unpack_argument_1 = require("../argument/unpack-argument");
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
const logger_1 = require("../../../../../logger");
const environment_1 = require("../../../../../environments/environment");
const edge_1 = require("../../../../../graph/edge");
const identifier_1 = require("../../../../../environments/identifier");
function processWhileLoop(name, args, rootId, data) {
if (args.length !== 2 || args[1] === r_function_call_1.EmptyArgument) {
logger_1.dataflowLogger.warn(`While-Loop ${name.content} does not have 2 arguments, skipping`);
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
}
const unpackedArgs = args.map(e => (0, unpack_argument_1.unpackArgument)(e));
if (unpackedArgs.some(assert_1.isUndefined)) {
logger_1.dataflowLogger.warn(`While-Loop ${name.content} has empty arguments in ${JSON.stringify(args)}, skipping`);
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
}
/* we inject the cf-dependency of the while-loop after the condition */
const { information, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({
name,
args: unpackedArgs,
rootId,
data,
markAsNSE: [1],
patchData: (d, i) => {
if (i === 1) {
return { ...d, controlDependencies: [...d.controlDependencies ?? [], { id: name.info.id, when: true }] };
}
return d;
}
});
const [condition, body] = processedArguments;
(0, assert_1.guard)(condition !== undefined && body !== undefined, () => `While-Loop ${name.content} has no condition or body, impossible!`);
const originalDependency = data.controlDependencies;
if ((0, info_1.alwaysExits)(condition)) {
logger_1.dataflowLogger.warn(`While-Loop ${rootId} forces exit in condition, skipping rest`);
return condition;
}
const remainingInputs = (0, linker_1.linkInputs)([
...(0, environment_1.makeAllMaybe)(body.unknownReferences, information.graph, information.environment, false),
...(0, environment_1.makeAllMaybe)(body.in, information.graph, information.environment, false)
], information.environment, [...condition.in, ...condition.unknownReferences], information.graph, true);
(0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph, condition.in)), body.out);
// as the while-loop always evaluates its condition
information.graph.addEdge(name.info.id, condition.entryPoint, edge_1.EdgeType.Reads);
return {
unknownReferences: [],
in: [{ nodeId: name.info.id, name: name.lexeme, controlDependencies: originalDependency, type: identifier_1.ReferenceType.Function }, ...remainingInputs],
out: [...(0, environment_1.makeAllMaybe)(body.out, information.graph, information.environment, true), ...condition.out],
entryPoint: name.info.id,
exitPoints: (0, info_1.filterOutLoopExitPoints)(body.exitPoints),
graph: information.graph,
environment: information.environment
};
}
//# sourceMappingURL=built-in-while-loop.js.map