UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

117 lines 5.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processQuote = processQuote; const known_call_handling_1 = require("../known-call-handling"); const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call"); const node_id_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id"); const vertex_1 = require("../../../../../graph/vertex"); const logger_1 = require("../../../../../logger"); const df_helper_1 = require("../../../../../graph/df-helper"); const edge_1 = require("../../../../../graph/edge"); const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name"); const graph_1 = require("../../../../../graph/graph"); const nse_1 = require("../nse"); const linker_1 = require("../../../../linker"); /** * Process a call to `quote` or similar nse/substitution functions. */ function processQuote(name, args, rootId, data, config) { const startEnv = data.environment; let lastEnv = startEnv; const { information, processedArguments, fnRef } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs, origin: built_in_proc_name_1.BuiltInProcName.Quote, patchData(data, index) { if (index === config.quoteArgumentsWithIndex) { lastEnv = data.environment; return { ...data, environment: data.ctx.env.makeCleanEnv() }; } else { return { ...data, environment: lastEnv }; } } }); const inRefs = [fnRef]; const outRefs = []; const unknownRefs = []; const quotedArg = args[config.quoteArgumentsWithIndex]; const evaluated = nse_1.Nse.unquoted(quotedArg === r_function_call_1.EmptyArgument ? undefined : quotedArg?.value, config.unquote ?? nse_1.Unquote.None); for (let i = 0; i < args.length; i++) { const processedArg = processedArguments[i]; if (processedArg && i !== config.quoteArgumentsWithIndex) { inRefs.push(...processedArg.in); outRefs.push(...processedArg.out); unknownRefs.push(...processedArg.unknownReferences); } } const quotedProcessed = processedArguments[config.quoteArgumentsWithIndex]; if (quotedProcessed) { (0, known_call_handling_1.markArgumentsAsNonStandardEvaluation)(information.graph, rootId, processedArguments, [config.quoteArgumentsWithIndex], { evaluated }); if (evaluated) { /* the argument was processed in a clean env, so the escaped reads need linking by hand */ const escaped = [...quotedProcessed.in, ...quotedProcessed.unknownReferences].filter(r => evaluated.has(r.nodeId)); (0, linker_1.linkInputs)(escaped, lastEnv, inRefs, information.graph, false); } } if (config.envArgIndex !== undefined) { const envProcessed = processedArguments[config.envArgIndex]; const exprProcessed = processedArguments[config.quoteArgumentsWithIndex]; if (envProcessed && exprProcessed) { applyEnvListReplacement(information, envProcessed, exprProcessed); } } return { ...information, environment: startEnv, in: inRefs, out: outRefs, unknownReferences: unknownRefs }; } /** The uses within `expr`, by name, to match a `substitute` env list against. */ function usesByName(expr) { const useMap = new Map(); for (const vType of [vertex_1.VertexType.Use, vertex_1.VertexType.FunctionCall]) { for (const [useId] of expr.graph.verticesOfType(vType)) { const rn = (0, node_id_1.recoverName)(useId, expr.graph.idMap); if (rn) { const arr = useMap.get(rn); if (arr) { arr.push(useId); } else { useMap.set(rn, [useId]); } } } } return useMap; } /** `substitute(expr, list(a = 1))` replaces the listed names within `expr`. */ function applyEnvListReplacement(information, env, expr) { let useMap = undefined; try { /* traverse the env processed DFG to find list calls (prefix-aware handling) */ df_helper_1.Dataflow.visitDfg(env.graph, env.entryPoint, (vtx) => { if (!vertex_1.FunctionCallVertex.is(vtx)) { return; } if (!vtx.origin.includes(built_in_proc_name_1.BuiltInProcName.List)) { return true; } useMap ??= usesByName(expr); if (useMap.size === 0) { return true; } for (const field of vtx.args.filter(graph_1.FunctionArgument.isNamed)) { for (const useId of useMap.get(field.name) ?? []) { information.graph.addEdge(useId, field.nodeId, edge_1.EdgeType.Reads); } } return true; }); } catch (e) { logger_1.dataflowLogger.warn('Failed to apply substitute-style env list replacement in quote-like call', { error: e }); } } //# sourceMappingURL=built-in-quote.js.map