@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
99 lines • 4.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.markNonStandardEvaluationEdges = markNonStandardEvaluationEdges;
exports.processKnownFunctionCall = processKnownFunctionCall;
const processor_1 = require("../../../../processor");
const common_1 = require("./common");
const identifier_1 = require("../../../../environments/identifier");
const graph_1 = require("../../../../graph/graph");
const edge_1 = require("../../../../graph/edge");
const logger_1 = require("../../../../logger");
const vertex_1 = require("../../../../graph/vertex");
const unknown_side_effect_1 = require("../../../../graph/unknown-side-effect");
const built_in_proc_name_1 = require("../../../../environments/built-in-proc-name");
/**
* Marks the given arguments as being involved in R's non-standard evaluation.
*/
function markNonStandardEvaluationEdges(markAsNSE, callArgs, finalGraph, rootId) {
for (const nse of markAsNSE) {
if (nse < callArgs.length) {
const arg = callArgs[nse];
if (arg !== undefined) {
finalGraph.addEdge(rootId, arg.entryPoint, edge_1.EdgeType.NonStandardEvaluation);
}
}
else {
logger_1.dataflowLogger.warn(`Trying to mark argument ${nse} as non-standard-evaluation, but only ${callArgs.length} arguments are available`);
}
}
}
/**
* The main processor for function calls for which we know the target but need not
* add any specific handling.
*/
function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect, origin }) {
const functionName = (0, processor_1.processDataflowFor)(name, data);
const finalGraph = new graph_1.DataflowGraph(data.completeAst.idMap);
const functionCallName = name.content;
const processArgs = reverseOrder ? args.toReversed() : args;
const { finalEnv, callArgs, remainingReadInArgs, processedArguments } = (0, common_1.processAllArguments)({ functionName, args: processArgs, data, finalGraph, functionRootId: rootId, patchData, forceArgs });
if (markAsNSE) {
markNonStandardEvaluationEdges(markAsNSE, processedArguments, finalGraph, rootId);
}
finalGraph.addVertex({
tag: vertex_1.VertexType.FunctionCall,
id: rootId,
environment: data.environment,
name: functionCallName,
/* will be overwritten accordingly */
onlyBuiltin: false,
cds: data.cds,
args: reverseOrder ? callArgs.toReversed() : callArgs,
origin: origin === 'default' ? [built_in_proc_name_1.BuiltInProcName.Function] : [origin]
}, data.ctx.env.makeCleanEnv());
if (hasUnknownSideEffect) {
(0, unknown_side_effect_1.handleUnknownSideEffect)(finalGraph, data.environment, rootId);
}
const inIds = remainingReadInArgs;
const fnRef = { nodeId: rootId, name: functionCallName, cds: data.cds, type: identifier_1.ReferenceType.Function };
inIds.push(fnRef);
// if force args is not none, we need to collect all non-default exit points from our arguments!
let exitPoints = undefined;
if (forceArgs === 'all') {
const nonDefaults = processedArguments.flatMap(p => p ? p.exitPoints.filter(ep => ep.type !== 0 /* ExitPointType.Default */) : []);
if (nonDefaults.length > 0) {
exitPoints = nonDefaults;
}
}
else if (forceArgs) {
for (let i = 0; i < forceArgs.length; i++) {
if (forceArgs[i]) {
const p = processedArguments[i];
if (p) {
const nonDefaults = p.exitPoints.filter(ep => ep.type !== 0 /* ExitPointType.Default */);
if (nonDefaults.length > 0) {
exitPoints ??= [];
exitPoints.push(...nonDefaults);
}
}
}
}
}
return {
information: {
unknownReferences: [],
in: inIds,
/* we do not keep the argument out as it has been linked by the function */
out: functionName.out,
graph: finalGraph,
environment: finalEnv,
entryPoint: rootId,
exitPoints: exitPoints ?? [{ nodeId: rootId, type: 0 /* ExitPointType.Default */, cds: data.cds }],
hooks: functionName.hooks
},
callArgs,
processedArguments: reverseOrder ? processedArguments.toReversed() : processedArguments,
fnRef
};
}
//# sourceMappingURL=known-call-handling.js.map