UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

97 lines 4.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processNewEnv = processNewEnv; exports.createFreshEnvState = createFreshEnvState; 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 built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name"); const scoping_1 = require("../../../../../environments/scoping"); const environment_1 = require("../../../../../environments/environment"); const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type"); const unpack_argument_1 = require("../argument/unpack-argument"); const vertex_1 = require("../../../../../graph/vertex"); const convert_values_1 = require("../../../../../../r-bridge/lang-4.x/convert-values"); const built_in_envir_utils_1 = require("./built-in-envir-utils"); const EmptyParentEnvFunctions = new Set(['emptyenv', 'baseenv']); /** * Processes `new.env()` and `rlang::new_environment()`. * * The resulting function-call vertex carries the {@link BuiltInProcName.NewEnv} origin so that * `processAssignment` can detect it and attach an `envState` to the assigned variable. * * When the `parent` argument can be statically resolved (a tracked env variable or an * `emptyenv()`-family call), the resolved parent is stored in the vertex's `newEnvParent` * field so that {@link createFreshEnvState} can use it. */ function processNewEnv(name, args, rootId, data) { const result = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.NewEnv }).information; if (data.ctx.config.solver.trackEnvironments) { const parentState = resolveNewEnvParentArg(args, data); const vertex = result.graph.getVertex(rootId); if (parentState !== undefined && (0, vertex_1.isFunctionCallVertex)(vertex)) { vertex.newEnvParent = parentState; } } return result; } /** * Scans `args` for the `parent` argument and returns the {@link REnvironmentInformation} * to use as the parent of the newly-created environment, or `undefined` to fall through * to the default (current execution environment). * * Recognised patterns: * - `parent = <tracked-env-var>` - returns that variable's `envState` * - `parent = emptyenv()` / `parent = baseenv()` - returns an isolated env (no user scope) * - everything else - `undefined` (fall through) */ function resolveNewEnvParentArg(args, data) { for (const arg of args) { if (arg === r_function_call_1.EmptyArgument || arg.name?.content !== 'parent') { continue; } const node = (0, unpack_argument_1.unpackArg)(arg); if (!node) { return undefined; } if (node.type === type_1.RType.Symbol) { if (node.content === convert_values_1.RNull) { return undefined; } return (0, built_in_envir_utils_1.resolveSymbolToEnvir)(node.content, node.info.id, data)?.envDef.envState; } if (r_function_call_1.RFunctionCall.isNamed(node) && node.functionName.type === type_1.RType.Symbol && EmptyParentEnvFunctions.has(node.functionName.content)) { return createIsolatedEnvState(data); } return undefined; } return undefined; } function createIsolatedEnvState(data) { let root = data.environment.current; while (!root.builtInEnv) { root = root.parent; } return { current: new environment_1.Environment(root), level: 0 }; } /** * Creates the initial (empty) environment state for a freshly created `new.env()`. * * When called from `processAssignmentToSymbol`, pass `sourceInfo` so that a * statically-resolved `parent` argument (stored in the vertex's `newEnvParent` field) * is honoured. Without `sourceInfo` (or when no `newEnvParent` is present), falls back * to the current execution environment as parent. */ function createFreshEnvState(data, sourceInfo) { if (sourceInfo !== undefined) { const vertex = sourceInfo.graph.getVertex(sourceInfo.entryPoint); if ((0, vertex_1.isFunctionCallVertex)(vertex) && vertex.newEnvParent !== undefined) { return { current: new environment_1.Environment(vertex.newEnvParent.current), level: vertex.newEnvParent.level + 1 }; } } return (0, scoping_1.pushLocalEnvironment)(data.environment); } //# sourceMappingURL=built-in-new-env.js.map