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