UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

99 lines 4.6 kB
"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