UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

120 lines 4.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getOriginInDfg = getOriginInDfg; const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id"); const vertex_1 = require("../graph/vertex"); const edge_1 = require("../graph/edge"); const linker_1 = require("../internal/linker"); const assert_1 = require("../../util/assert"); const vertex_2 = require("../graph/vertex"); const graph_1 = require("../graph/graph"); /** * Obtain the (dataflow) origin of a given node in the dfg. * @example consider the following code: * ```r * x <- 2 * if(u) { * x <- 3 * } * print(x) * ``` * Requesting the origin of `x` in the `print(x)` node yields two {@link SimpleOrigin|variable origins} for both * definitions of `x`. * Similarly, requesting the origin of `print` returns a {@link BuiltInFunctionOrigin|`BuiltInFunctionOrigin`}. * * This returns undefined only if there is no dataflow correspondence (e.g. in case of unevaluated non-standard eval). * @useInstead {@link Dataflow.origin} */ function getOriginInDfg(dfg, id) { const vtx = dfg.getVertex(id); switch (vtx?.tag) { case undefined: return undefined; case vertex_1.VertexType.Value: return [{ type: 4 /* OriginType.ConstantOrigin */, id }]; case vertex_1.VertexType.FunctionDefinition: return [{ type: 4 /* OriginType.ConstantOrigin */, id }]; case vertex_1.VertexType.VariableDefinition: return getVariableDefinitionOrigin(dfg, vtx); case vertex_1.VertexType.Use: return getVariableUseOrigin(dfg, vtx); case vertex_1.VertexType.FunctionCall: return getCallTarget(dfg, vtx); } } const WantedVariableTypes = edge_1.EdgeType.Reads | edge_1.EdgeType.DefinedByOnCall; const UnwantedVariableTypes = edge_1.EdgeType.NonStandardEvaluation; function getVariableUseOrigin(dfg, use) { // to identify the origins we have to track read edges and definitions on function calls const origins = []; for (const [target, e] of dfg.outgoingEdges(use.id) ?? graph_1.NoEdges) { if (edge_1.DfEdge.doesNotIncludeType(e, WantedVariableTypes) || edge_1.DfEdge.includesType(e, UnwantedVariableTypes)) { continue; } const targetVtx = dfg.getVertex(target); if (!targetVtx) { continue; } if (vertex_2.VariableDefinitionVertex.is(targetVtx)) { origins.push({ type: 0 /* OriginType.ReadVariableOrigin */, id: target }); } } return origins.length > 0 ? origins : undefined; } function getVariableDefinitionOrigin(dfg, vtx) { const pool = [{ type: 1 /* OriginType.WriteVariableOrigin */, id: vtx.id }]; const outgoingReads = dfg.outgoingEdges(vtx.id) ?? graph_1.NoEdges; for (const [target, e] of outgoingReads) { if (edge_1.DfEdge.includesType(e, edge_1.EdgeType.Reads)) { const targetVtx = dfg.getVertex(target); if (!targetVtx) { continue; } if (vertex_2.VariableDefinitionVertex.is(targetVtx)) { pool.push({ type: 0 /* OriginType.ReadVariableOrigin */, id: target }); } } } return pool; } function getCallTarget(dfg, call) { // check for built-ins: const builtInTarget = call.origin !== 'unnamed' && call.origin.filter(o => o.startsWith('builtin:')); let origins = builtInTarget ? builtInTarget.map(o => ({ type: 3 /* OriginType.BuiltInFunctionOrigin */, fn: { name: call.name }, id: call.id, proc: o })) : undefined; const targets = new Set((0, linker_1.getAllFunctionCallTargets)(call.id, dfg)); if (targets.size === 0) { // resolve via variable use origin return origins?.length === 0 ? getVariableUseOrigin(dfg, call) : origins; } origins = (origins ?? []).concat([...targets].map(target => { if (node_id_1.NodeId.isBuiltIn(target)) { return { type: 3 /* OriginType.BuiltInFunctionOrigin */, fn: { name: call.name }, id: call.id, proc: target }; } const get = dfg.getVertex(target); if (!vertex_2.FunctionDefinitionVertex.is(get) && !vertex_2.VariableDefinitionVertex.is(get)) { return undefined; } return { type: vertex_2.FunctionDefinitionVertex.is(get) ? 2 /* OriginType.FunctionCallOrigin */ : 0 /* OriginType.ReadVariableOrigin */, id: target }; }).filter(assert_1.isNotUndefined)); return origins; } //# sourceMappingURL=dfg-get-origin.js.map