UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

113 lines 6.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processStackEnv = processStackEnv; exports.resolveNodeToStackEnv = resolveNodeToStackEnv; exports.stackEnvStateFromSource = stackEnvStateFromSource; exports.stackEnvInheritsFields = stackEnvInheritsFields; const known_call_handling_1 = require("../known-call-handling"); const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name"); const environment_1 = require("../../../../../environments/environment"); const vertex_1 = require("../../../../../graph/vertex"); const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type"); const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call"); const default_builtin_config_1 = require("../../../../../environments/default-builtin-config"); /** The rlang pronoun for the scope surrounding a data mask. */ const EnvPronoun = '.env'; /** The stack env kind a builtin/constant `name` denotes, or `undefined`. */ function stackEnvKind(name) { return default_builtin_config_1.StackEnvBuiltins[name]; } /** * Processes the env-returning builtins (`globalenv`/`baseenv`/`emptyenv`), tagging the call with the * {@link BuiltInProcName.StackEnv} origin so an assignment (`e <- globalenv()`) attaches the stack env as the * variable's `envState`. Direct forms (`globalenv()$x`, `.GlobalEnv`) go through {@link resolveNodeToStackEnv}. */ function processStackEnv(name, args, rootId, data) { return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.StackEnv }).information; } /** The fixed stack environment for a `Global`/`Base`/`Empty` kind; `undefined` for kinds that need the call's arguments. */ function fixedStackEnv(kind, data) { switch (kind) { case default_builtin_config_1.StackEnvKind.Global: return { current: environment_1.REnvironment.findGlobal(data.environment.current), level: 0 }; case default_builtin_config_1.StackEnvKind.Base: return { current: data.ctx.env.builtInEnvironment, level: 0 }; case default_builtin_config_1.StackEnvKind.Empty: return data.ctx.env.makeEmptyEnv(); default: return undefined; } } /** * The stack environment an AST `node` denotes directly: a `.GlobalEnv`/`.BaseEnv` symbol, a * `globalenv()`/`baseenv()`/`emptyenv()` call, the current env via `environment()`, the parent via `parent.env(e)`, * or a named search-path entry via `as.environment("package:x")`. Returns `undefined` otherwise. */ function resolveNodeToStackEnv(node, data) { if (node === undefined) { return undefined; } const name = node.type === type_1.RType.Symbol ? String(node.content) : r_function_call_1.RFunctionCall.isNamed(node) && node.functionName.type === type_1.RType.Symbol ? String(node.functionName.content) : undefined; const kind = name !== undefined ? stackEnvKind(name) : undefined; if (kind === undefined) { return undefined; } const firstArg = node.type === type_1.RType.FunctionCall && node.arguments.length > 0 && node.arguments[0] !== r_function_call_1.EmptyArgument ? node.arguments[0].value : undefined; switch (kind) { case default_builtin_config_1.StackEnvKind.Global: case default_builtin_config_1.StackEnvKind.Base: case default_builtin_config_1.StackEnvKind.Empty: return fixedStackEnv(kind, data); case default_builtin_config_1.StackEnvKind.CallerFrame: // parent.frame(): the caller's frame, over-approximated to global (exact at a top-level call) return fixedStackEnv(default_builtin_config_1.StackEnvKind.Global, data); case default_builtin_config_1.StackEnvKind.Current: // environment() with no argument is the current environment return firstArg === undefined ? { current: data.environment.current, level: data.environment.level } : undefined; case default_builtin_config_1.StackEnvKind.Parent: { const inner = resolveNodeToStackEnv(firstArg, data); return inner !== undefined && !inner.current.builtInEnv ? { current: inner.current.parent, level: inner.level } : undefined; } case default_builtin_config_1.StackEnvKind.Named: return firstArg?.type === type_1.RType.String ? asSearchPathEnv(firstArg.content.str, data) : undefined; } } /** Resolves a named search-path entry: a `.GlobalEnv`/`.BaseEnv` name, or `package:<name>` to that package's namespace layer. */ function asSearchPathEnv(name, data) { const fixed = fixedStackEnv(stackEnvKind(name), data); if (fixed !== undefined) { return fixed; } if (name.startsWith(environment_1.SearchPathPackagePrefix)) { const pkg = name.slice(environment_1.SearchPathPackagePrefix.length); for (let env = environment_1.REnvironment.findGlobal(data.environment.current).parent; env !== undefined && !env.builtInEnv; env = env.parent) { if (env.n === pkg && env.t === environment_1.EnvType.Namespace) { return { current: env, level: 0 }; } } } return undefined; } /** The stack environment `sourceInfo`'s entry call refers to (`e <- globalenv()`, `e <- environment()`), or `undefined`. */ function stackEnvStateFromSource(sourceInfo, data) { const vertex = sourceInfo.graph.getVertex(sourceInfo.entryPoint); if (!vertex_1.FunctionCallVertex.is(vertex) || vertex.name === undefined) { return undefined; } const kind = stackEnvKind(String(vertex.name)); if (vertex.origin.includes(built_in_proc_name_1.BuiltInProcName.StackEnv)) { return fixedStackEnv(kind, data); } /* `environment()` goes through the default processor; with an argument it denotes a closure's env instead */ return kind === default_builtin_config_1.StackEnvKind.Current && vertex.args.length === 0 && vertex.origin.includes(built_in_proc_name_1.BuiltInProcName.Default) ? { current: data.environment.current, level: data.environment.level } : undefined; } /** * Whether a `$`/`[[` on the stack env `node` denotes reads through the enclosing scopes. * Only the rlang pronoun `.env` does: it names the surrounding scope, while `$` on a real environment stays in its frame. */ function stackEnvInheritsFields(node) { return node?.type === type_1.RType.Symbol && String(node.content) === EnvPronoun; } //# sourceMappingURL=built-in-stack-env.js.map