@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
61 lines • 3.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.linkReadsForArgument = linkReadsForArgument;
exports.processFunctionArgument = processFunctionArgument;
const processor_1 = require("../../../processor");
const model_1 = require("../../../../r-bridge/lang-4.x/ast/model/model");
const graph_1 = require("../../../graph/graph");
const type_1 = require("../../../../r-bridge/lang-4.x/ast/model/type");
const edge_1 = require("../../../graph/edge");
const vertex_1 = require("../../../graph/vertex");
/**
* Links all reads that occur before the argument to the argument root node.
*/
function linkReadsForArgument(root, ingoingRefs, graph) {
const rid = root.info.id;
const allIdsBeforeArguments = new Set(model_1.RNode.collectAllIdsWithStop(root, n => n.type === type_1.RType.Argument && n.info.id !== rid));
const ingoingBeforeArgs = ingoingRefs.filter(r => allIdsBeforeArguments.has(r.nodeId));
for (const ref of ingoingBeforeArgs) {
// link against the root reference currently I do not know how to deal with nested function calls otherwise
graph.addEdge(rid, ref.nodeId, edge_1.EdgeType.Reads);
}
}
/**
* Processes the dataflow information for a function argument.
*/
function processFunctionArgument(argument, data) {
const name = argument.name === undefined ? undefined : (0, processor_1.processDataflowFor)(argument.name, data);
const value = argument.value === undefined ? undefined : (0, processor_1.processDataflowFor)(argument.value, data);
// we do not keep the graph of the name, as this is no node that should ever exist
const graph = value?.graph ?? new graph_1.DataflowGraph(data.completeAst.idMap);
const argumentName = argument.name?.content;
let entryPoint = value?.entryPoint;
if (argumentName) {
graph.addVertex({
tag: vertex_1.VertexType.Use,
id: argument.info.id,
cds: data.cds
}, data.ctx.env.makeCleanEnv());
entryPoint = argument.info.id;
}
const ingoingRefs = value ? value.unknownReferences.concat(value.in, name?.in ?? []) : name?.in;
if (entryPoint && argument.value?.type === type_1.RType.FunctionDefinition) {
graph.addEdge(entryPoint, argument.value.info.id, edge_1.EdgeType.Reads);
}
else if (argumentName && ingoingRefs) {
// we only need to link against those which are not already bound to another function call argument
linkReadsForArgument(argument, value ? ingoingRefs.concat(value.out /* value may perform definitions */) : ingoingRefs, graph);
}
return {
unknownReferences: [],
// active nodes of the name will be lost as they are only used to reference the corresponding parameter
in: ingoingRefs?.filter(r => r.name !== undefined) ?? [],
out: [...value?.out ?? [], ...(name?.out ?? [])],
graph: graph,
environment: value?.environment ?? data.environment,
entryPoint: entryPoint ?? argument.info.id,
exitPoints: value?.exitPoints ?? name?.exitPoints ?? [{ nodeId: argument.info.id, type: 0 /* ExitPointType.Default */, cds: data.cds }],
hooks: []
};
}
//# sourceMappingURL=process-argument.js.map