@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
120 lines • 4.79 kB
JavaScript
"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