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