UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

62 lines 3.73 kB
"use strict"; 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