UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

94 lines 5.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processForLoop = processForLoop; const processor_1 = require("../../../../../processor"); 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 common_1 = require("../common"); const unpack_argument_1 = require("../argument/unpack-argument"); const logger_1 = require("../../../../../logger"); const overwrite_1 = require("../../../../../environments/overwrite"); const define_1 = require("../../../../../environments/define"); const append_1 = require("../../../../../environments/append"); const edge_1 = require("../../../../../graph/edge"); const identifier_1 = require("../../../../../environments/identifier"); const reference_to_maybe_1 = require("../../../../../environments/reference-to-maybe"); const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name"); /** * Processes a for-loop call: `for(<variable> in <vector>) <body>` * desugared as: * ```r * `for`(<variable>, <vector>, <body>) * ``` */ function processForLoop(name, args, rootId, data) { if (args.length !== 3) { logger_1.dataflowLogger.warn(`For-Loop ${identifier_1.Identifier.toString(name.content)} does not have three arguments, skipping`); return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information; } const [variableArg, vectorArg, bodyArg] = args.map(e => (0, unpack_argument_1.unpackNonameArg)(e)); // we store the original environment here, as we merge it back lter in case the for-loop never executes const origEnv = data.environment; (0, assert_1.guard)(variableArg !== undefined && vectorArg !== undefined && bodyArg !== undefined, () => `For-Loop ${JSON.stringify(args)} has missing arguments! Bad!`); const vector = (0, processor_1.processDataflowFor)(vectorArg, data); if ((0, info_1.alwaysExits)(vector)) { logger_1.dataflowLogger.warn(`For-Loop ${rootId} forces exit in vector, skipping rest`); return vector; } const variable = (0, processor_1.processDataflowFor)(variableArg, data); // this should not be able to exit always! const originalDependency = data.cds; let headEnvironments = (0, overwrite_1.overwriteEnvironment)(vector.environment, variable.environment); const headGraph = variable.graph.mergeWith(vector.graph); const writtenVariable = variable.unknownReferences.concat(variable.in); const writtenIds = new Set(); for (const write of writtenVariable) { writtenIds.add(write.nodeId); headEnvironments = (0, define_1.define)({ ...write, definedAt: name.info.id, type: identifier_1.ReferenceType.Variable }, false, headEnvironments); } data.environment = headEnvironments; const body = (0, processor_1.processDataflowFor)(bodyArg, data); const outEnvironment = (0, append_1.appendEnvironment)(headEnvironments, body.environment); const cd = [{ id: name.info.id, when: true }]; const bodyRefs = body.in.concat(body.unknownReferences); (0, reference_to_maybe_1.applyCdsToAllInGraphButConstants)(body.graph, bodyRefs, cd); const nextGraph = headGraph.mergeWith(body.graph); // now we have to identify all reads that may be effected by a circular redefinition // for this, we search for all reads with a non-local read resolve! const nameIdShares = (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(nextGraph, writtenIds)); for (const write of writtenVariable) { nextGraph.addEdge(write.nodeId, vector.entryPoint, edge_1.EdgeType.DefinedBy); nextGraph.setDefinitionOfVertex(write, [vector.entryPoint]); } (0, reference_to_maybe_1.applyCdToReferences)(body.out, cd); const outgoing = variable.out.concat(writtenVariable, body.out); (0, linker_1.linkCircularRedefinitionsWithinALoop)(nextGraph, nameIdShares, body.out); (0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences), nextGraph); (0, common_1.patchFunctionCall)({ nextGraph, rootId, name, data: { ...data, cds: originalDependency }, argumentProcessResult: [variable, vector, body], origin: built_in_proc_name_1.BuiltInProcName.ForLoop }); /* mark the last argument as nse */ nextGraph.addEdge(rootId, body.entryPoint, edge_1.EdgeType.NonStandardEvaluation); // as the for-loop always evaluates its condition nextGraph.addEdge(name.info.id, vector.entryPoint, edge_1.EdgeType.Reads); return { unknownReferences: [], // we only want those not bound by a local variable in: [{ nodeId: rootId, name: name.content, cds: originalDependency, type: identifier_1.ReferenceType.Function }, ...vector.unknownReferences, ...[...nameIdShares.values()].flat()], out: outgoing, graph: nextGraph, entryPoint: name.info.id, exitPoints: (0, info_1.filterOutLoopExitPoints)(body.exitPoints), // if we can not be sure that the for-loop runs once, we have to merge back the original environment, as the body may never execute environment: (0, append_1.appendEnvironment)(origEnv, outEnvironment), hooks: variable.hooks.concat(vector.hooks, body.hooks), }; } //# sourceMappingURL=built-in-for-loop.js.map