UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

185 lines (184 loc) 9.8 kB
import type { BuiltInMemory } from './built-in'; import type { IdentifierDefinition } from './identifier'; import { Identifier } from './identifier'; import type { ControlDependency } from '../info'; import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id'; /** A single entry/scope within an {@link REnvironmentInformation} */ export interface IEnvironment { /** Unique internally generated identifier, used for debugging not comparison */ readonly id: number; /** Lexical parent of the environment, if any (can be manipulated by R code) */ parent: IEnvironment; /** Maps to exactly one definition of an identifier if the source is known, otherwise to a list of all possible definitions */ memory: BuiltInMemory; /** Built-in environment that must not change; only for the top-most envs. */ builtInEnv?: true | undefined; } export declare enum EnvType { Namespace = "ns", Imports = "imp", /** `requireNamespace("pkg")`: `pkg::fn` resolves, bare `fn` does not */ LoadedNamespace = "lns" } interface Jsonified { id: NodeId; parent: Jsonified | undefined; builtInEnv?: true; memory: BuiltInMemory; n?: string; t?: EnvType; globalEnv?: true; } /** * Use only if you do not know the object type; otherwise rely on {@link IEnvironment#builtInEnv}. */ export declare function isDefaultBuiltInEnvironment(obj: unknown): boolean; /** @see REnvironmentInformation */ export declare class Environment implements IEnvironment { readonly id: number; /** Optional name for namespaced/non-anonymous environments, please only set if you know what you are doing */ n?: string; /** which search-path layer this env is (package/namespace/imports), if any */ t?: EnvType; /** if created by a closure, the node id of that closure */ private c?; parent: Environment; memory: BuiltInMemory; cache?: Map<Identifier, IdentifierDefinition[]>; builtInEnv?: true; /** {@link memory} is shared with a clone; writing needs {@link writableMemory} to unshare it first */ private sharedMemory?; /** marks the global environment (`.GlobalEnv`); attached packages (see {@link EnvType}) live below it */ globalEnv?: true; constructor(parent: Environment, isBuiltInDefault?: true | undefined); /** Marks this as an attached-package layer (see {@link EnvType}) for package `name`. */ asLibrary(name: string, type: EnvType): this; /** Marks this as the global environment (`.GlobalEnv`); see {@link globalEnv}. */ asGlobal(): this; /** please only use if you know what you are doing */ setClosureNodeId(nodeId: NodeId): void; /** Provides the closure linked to this environment. */ get closure(): NodeId | undefined; /** * This environment's {@link memory}, ready to be written to. Every in-place write must go through this * rather than through {@link memory} directly, as {@link clone} hands the map itself to the clone and only * the first writer of either side copies it (copy-on-write). */ get writableMemory(): BuiltInMemory; /** * Create a clone of this environment. * * The clone shares this environment's {@link memory} until either side writes to it (see * {@link writableMemory}); cloning a frame is therefore independent of how many definitions it holds, which * matters because attached packages contribute frames with thousands of them. * @param recurseParents - Whether to also clone parent environments */ clone(recurseParents: boolean): Environment; /** * Define a new identifier definition within this environment. * @param definition - The definition to add. */ define(definition: IdentifierDefinition & { name: Identifier; }): Environment; /** * Define several identifiers at once in a more performant fashion. * @param definitions - The definitions to add. */ defineAll(definitions: Iterable<IdentifierDefinition & { name: Identifier; }>): Environment; /** Only sound on an environment nobody else holds yet. */ private apply; private defineInNamespace; defineSuper(definition: IdentifierDefinition & { name: Identifier; }): Environment; /** * Definitions within `other` replace those here by name; if all of `other`'s are maybe, they are appended instead (turning existing ones maybe too), like {@link appendEnvironment}. Always recurses parents. */ overwrite(other: Environment | undefined, applyCds?: readonly ControlDependency[]): Environment; /** * Adds all writes of `other` to this environment (`other`'s operations *might* happen). Always recurses parents. */ append(other: Environment | undefined): Environment; /** * The environment a merge with `other` settles on without touching either memory, `undefined` if the * memories have to be merged. Package blocks are always unioned, never overwritten or appended to. */ private mergeShortcut; /** * Unions two attached-package blocks, keeping every package once (memory merged for a package in both). */ private mergePackageBlocks; remove(id: Identifier): this; removeAll(names: readonly { name: Identifier; }[]): Environment; toJSON(): Jsonified; } /** Walks up to the global environment (see {@link Environment#globalEnv}), falling back to the last non-builtin env. */ declare function findGlobalEnvironment(this: void, env: Environment): Environment; /** Walks up to the built-in environment. */ declare function findBuiltInEnvironment(this: void, env: Environment): Environment; /** The `search()` position directly below the global environment; where R attaches by default. */ export declare const DefaultAttachPosition = 2; /** Prefix of a package's entry in R's `search()` list. */ export declare const SearchPathPackagePrefix = "package:"; /** Name of the global environment in R's `search()` list. */ export declare const GlobalEnvEntryName = ".GlobalEnv"; /** * Splices a package block (`blockTop`..`blockBottom`) into the search path at the 1-based `search()` position `pos` * ({@link DefaultAttachPosition|2} being directly below the global environment, the default). A position past the end * of the search path attaches directly above the built-in environment, mirroring R's clamping. Returns a fresh * `current`, cloning only the path down to the insertion point. */ declare function attachPackageAt(this: void, current: Environment, blockTop: Environment, blockBottom: Environment, pos?: number): Environment; /** * The 1-based `search()` position of the entry called `name` (`.GlobalEnv`, `package:x`, or a bare package name), * or `undefined` if no such entry is on the search path. `package:base` resolves to the built-in environment at the * very bottom if base R is not attached as its own layer. */ declare function searchPositionOf(this: void, env: Environment, name: string): number | undefined; /** * The packages attached below the global environment, i.e. those whose exports R resolves without a namespace. * Base is always among them, as it backs the built-in environment even when it is no layer of its own. */ declare function attachedPackagesOf(this: void, env: Environment): Set<string>; /** * Helpers for navigating and manipulating {@link REnvironmentInformation|environments} around the global environment and attached-package search path. */ export declare const REnvironment: { readonly name: "REnvironment"; /** Walks up to the global environment (`.GlobalEnv`); see {@link findGlobalEnvironment}. */ readonly findGlobal: typeof findGlobalEnvironment; /** Walks up to the built-in environment; see {@link findBuiltInEnvironment}. */ readonly findBuiltIn: typeof findBuiltInEnvironment; /** Attaches a package block at a `search()` position, below the global by default; see {@link attachPackageAt}. */ readonly attachAt: typeof attachPackageAt; /** The `search()` position of a named entry; see {@link searchPositionOf}. */ readonly searchPosition: typeof searchPositionOf; /** The packages on the search path; see {@link attachedPackagesOf}. */ readonly attachedPackages: typeof attachedPackagesOf; }; /** * An environment describes a ({@link IEnvironment#parent|scoped}) mapping of names to their definitions ({@link BuiltIns}). * * The {@link BuiltIns|BuiltInEnvironment} holds R's built-in functions and constants; during serialization use {@link builtInEnvJsonReplacer} to avoid inlining it. * @see {@link define} - to define a new {@link IdentifierDefinition|identifier definition} within an environment * @see {@link Resolve.byNameAndType} - to resolve an {@link Identifier|identifier/name} to its {@link IdentifierDefinition|definitions} within an environment * @see {@link makeReferenceMaybe} - to attach control dependencies to a reference * @see {@link pushLocalEnvironment} - to create a new local scope * @see {@link popLocalEnvironment} - to remove the current local scope * @see {@link appendEnvironment} - to append an environment to the current one * @see {@link overwriteEnvironment} - to overwrite the definitions in the current environment with those of another one */ export interface REnvironmentInformation { /** The currently active environment (the stack is represented by the {@link IEnvironment#parent} chain). */ readonly current: Environment; /** nesting level of the environment, will be `0` for the global/root environment */ readonly level: number; } /** Serializes an environment, replacing the built-in environment with a placeholder. */ export declare function builtInEnvJsonReplacer(k: unknown, v: unknown): unknown; export {};