@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
76 lines • 4.62 kB
JavaScript
;
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 environment_1 = require("../../../../../environments/environment");
const edge_1 = require("../../../../../graph/edge");
const identifier_1 = require("../../../../../environments/identifier");
function processForLoop(name, args, rootId, data) {
if (args.length !== 3) {
logger_1.dataflowLogger.warn(`For-Loop ${name.content} does not have three arguments, skipping`);
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
}
const [variableArg, vectorArg, bodyArg] = args.map(e => (0, unpack_argument_1.unpackArgument)(e));
(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.controlDependencies;
data = { ...data, controlDependencies: [...data.controlDependencies ?? [], { id: name.info.id, when: true }] };
let headEnvironments = (0, overwrite_1.overwriteEnvironment)(vector.environment, variable.environment);
const headGraph = variable.graph.mergeWith(vector.graph);
const writtenVariable = [...variable.unknownReferences, ...variable.in];
for (const write of writtenVariable) {
headEnvironments = (0, define_1.define)({ ...write, definedAt: name.info.id, type: identifier_1.ReferenceType.Variable }, false, headEnvironments);
}
data = { ...data, environment: headEnvironments };
const body = (0, processor_1.processDataflowFor)(bodyArg, data);
const nextGraph = headGraph.mergeWith(body.graph);
const outEnvironment = (0, append_1.appendEnvironment)(headEnvironments, body.environment);
// 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, writtenVariable));
for (const write of writtenVariable) {
nextGraph.addEdge(write.nodeId, vector.entryPoint, edge_1.EdgeType.DefinedBy);
nextGraph.setDefinitionOfVertex(write);
}
const outgoing = [...variable.out, ...writtenVariable, ...(0, environment_1.makeAllMaybe)(body.out, nextGraph, outEnvironment, true)];
(0, linker_1.linkCircularRedefinitionsWithinALoop)(nextGraph, nameIdShares, body.out);
(0, common_1.patchFunctionCall)({
nextGraph,
rootId,
name,
data: { ...data, controlDependencies: originalDependency },
argumentProcessResult: [variable, vector, body]
});
/* mark the last argument as nse */
nextGraph.addEdge(rootId, body.entryPoint, edge_1.EdgeType.NonStandardEvaluation);
// as the for-loop always evaluates its variable and condition
nextGraph.addEdge(name.info.id, variable.entryPoint, edge_1.EdgeType.Reads);
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, controlDependencies: 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),
environment: outEnvironment
};
}
//# sourceMappingURL=built-in-for-loop.js.map