UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

286 lines (285 loc) 12.7 kB
import { type MergeableRecord } from './util/objects'; import Joi from 'joi'; import type { BuiltInDefinitions } from './dataflow/environments/built-in-config'; import type { KnownParser } from './r-bridge/parser'; import type { DeepWritable, Paths, PathValue } from 'ts-essentials'; import type { DataflowProcessors } from './dataflow/processor'; import type { ParentInformation } from './r-bridge/lang-4.x/ast/model/processing/decorate'; import type { FlowrAnalyzerContext } from './project/context/flowr-analyzer-context'; export declare enum VariableResolve { /** Don't resolve constants at all */ Disabled = "disabled", /** Use alias tracking to resolve */ Alias = "alias", /** Only resolve directly assigned builtin constants */ Builtin = "builtin" } /** * How to infer the working directory from a script */ export declare enum InferWorkingDirectory { /** Don't infer the working directory */ No = "no", /** Infer the working directory from the main script */ MainScript = "main-script", /** Infer the working directory from the active script */ ActiveScript = "active-script", /** Infer the working directory from any script */ AnyScript = "any-script" } /** * How to handle fixed strings in a source path */ export declare enum DropPathsOption { /** Don't drop any parts of the sourced path */ No = "no", /** try to drop everything but the filename */ Once = "once", /** try to drop every folder of the path */ All = "all" } export interface FlowrLaxSourcingOptions extends MergeableRecord { /** * search for filenames matching in the lowercase */ readonly ignoreCapitalization: boolean; /** * try to infer the working directory from the main or any script to analyze. */ readonly inferWorkingDirectory: InferWorkingDirectory; /** * Additionally search in these paths */ readonly searchPath: string[]; /** * Allow to drop the first or all parts of the sourced path, * if it is relative. */ readonly dropPaths: DropPathsOption; /** * How often the same file can be sourced within a single run? * Please be aware: in case of cyclic sources this may not reach a fixpoint so give this a sensible limit. */ readonly repeatedSourceLimit?: number; /** * sometimes files may have a different name in the source call (e.g., due to later replacements), * with this setting you can provide a list of replacements to apply for each sourced file. * Every replacement consists of a record that maps a regex to a replacement string. * @example * ```ts * [ * { }, // no replacement -> still try the original name/path * { '.*\\.R$': 'main.R' }, // replace all .R files with main.R * { '\s' : '_' }, // replace all spaces with underscores * { '\s' : '-', 'oo': 'aa' }, // replace all spaces with dashes and oo with aa * ] * ``` * * Given a `source("foo bar.R")` this configuration will search for (in this order): * - `foo bar.R` (original name) * - `main.R` (replaced with main.R) * - `foo_bar.R` (replaced spaces) * - `faa-bar.R` (replaced spaces and oo) */ readonly applyReplacements?: Record<string, string>[]; } /** * The configuration file format for flowR. * @see {@link FlowrConfig.default} for the default configuration. * @see {@link FlowrConfig.Schema} for the Joi schema for validation. */ export interface FlowrConfig extends MergeableRecord { /** * Whether source calls should be ignored, causing {@link processSourceCall}'s behavior to be skipped */ readonly ignoreSourceCalls: boolean; /** Configure language semantics and how flowR handles them */ readonly semantics: { /** Semantics regarding the handling of the environment */ readonly environment: { /** Do you want to overwrite (parts) of the builtin definition? */ readonly overwriteBuiltIns: { /** Should the default configuration still be loaded? */ readonly loadDefaults?: boolean; /** The definitions to load */ readonly definitions: BuiltInDefinitions; }; }; }; /** Configuration options for the REPL */ readonly repl: { /** Whether to show quick stats in the REPL after each evaluation */ quickStats: boolean; /** This instruments the dataflow processors to count how often each processor is called */ dfProcessorHeat: boolean; }; readonly project: { /** Whether to resolve unknown paths loaded by the r project disk when trying to source/analyze files */ resolveUnknownPathsOnDisk: boolean; }; /** * The engines to use for interacting with R code. Currently, supports {@link TreeSitterEngineConfig} and {@link RShellEngineConfig}. * An empty array means all available engines will be used. */ readonly engines: EngineConfig[]; /** * The default engine to use for interacting with R code. If this is undefined, an arbitrary engine from {@link engines} will be used. */ readonly defaultEngine?: EngineConfig['type']; /** How to resolve constants, constraints, cells, … */ readonly solver: { /** * How to resolve variables and their values */ readonly variables: VariableResolve; /** * Should we include eval(parse(text="...")) calls in the dataflow graph? */ readonly evalStrings: boolean; /** These keys are only intended for use within code, allowing to instrument the dataflow analyzer! */ readonly instrument: { /** * Modify the dataflow processors used during dataflow analysis. * Make sure that all processors required for correct analysis are still present! * This may have arbitrary consequences on the analysis precision and performance, consider focusing on decorating existing processors instead of replacing them. */ dataflowExtractors?: (extractor: DataflowProcessors<ParentInformation>, ctx: FlowrAnalyzerContext) => DataflowProcessors<ParentInformation>; }; /** * If lax source calls are active, flowR searches for sourced files much more freely, * based on the configurations you give it. * This option is only in effect if {@link ignoreSourceCalls} is set to false. */ readonly resolveSource?: FlowrLaxSourcingOptions; /** * The configuration for flowR's slicer */ slicer?: { /** * The maximum number of iterations to perform on a single function call during slicing */ readonly threshold?: number; /** * If set, the slicer will gain an additional post-pass */ readonly autoExtend?: boolean; }; }; /** * Configuration options for abstract interpretation */ readonly abstractInterpretation: { /** * The threshold for the number of visitations of a node at which widening should be performed to ensure the termination of the fixpoint iteration */ readonly wideningThreshold: number; /** * The configuration of the shape inference for data frames */ readonly dataFrame: { /** * The maximum number of columns names to infer for data frames before over-approximating the column names to top */ readonly maxColNames: number; /** * Configuration options for reading data frame shapes from loaded external data files, such as CSV files */ readonly readLoadedData: { /** * Whether data frame shapes should be extracted from loaded external data files, such as CSV files */ readonly readExternalFiles: boolean; /** * The maximum number of lines to read when extracting data frame shapes from loaded files, such as CSV files */ readonly maxReadLines: number; }; }; }; } export type ValidFlowrConfigPaths = Paths<FlowrConfig, { depth: 9; }>; export interface TreeSitterEngineConfig extends MergeableRecord { readonly type: 'tree-sitter'; /** * The path to the tree-sitter-r WASM binary to use. If this is undefined, {@link DEFAULT_TREE_SITTER_R_WASM_PATH} will be used. */ readonly wasmPath?: string; /** * The path to the tree-sitter WASM binary to use. If this is undefined, the path specified by the tree-sitter package will be used. */ readonly treeSitterWasmPath?: string; /** * Whether to use the lax parser for parsing R code (allowing for syntax errors). If this is undefined, the strict parser will be used. */ readonly lax?: boolean; } export interface RShellEngineConfig extends MergeableRecord { readonly type: 'r-shell'; /** * The path to the R executable to use. If this is undefined, {@link DEFAULT_R_PATH} will be used. */ readonly rPath?: string; } export type EngineConfig = TreeSitterEngineConfig | RShellEngineConfig; export type KnownEngines = { [T in EngineConfig['type']]?: KnownParser; }; /** * Helper Object to work with {@link FlowrConfig}, provides the default config and the Joi schema for validation. */ export declare const FlowrConfig: { readonly name: "FlowrConfig"; /** * The default configuration for flowR, used when no config file is found or when a config file is missing some options. * You can use this as a base for your own config and only specify the options you want to change. */ readonly default: (this: void) => FlowrConfig; /** * The Joi schema for validating a config file, use this to validate your config file before using it. You can also use this to generate documentation for the config file format. */ readonly Schema: Joi.ObjectSchema<any>; /** * Parses the given JSON string as a flowR config file, returning the resulting config object if the parsing and validation were successful, or `undefined` if there was an error. */ readonly parse: (this: void, jsonString: string) => FlowrConfig | undefined; /** * Creates a new flowr config that has the updated values. */ readonly amend: (this: void, config: FlowrConfig, amendmentFunc: (config: DeepWritable<FlowrConfig>) => FlowrConfig | void) => FlowrConfig; /** * Clones the given flowr config object. */ readonly clone: (this: void, config: FlowrConfig) => FlowrConfig; /** * Loads the flowr config from the given file or the default locations. * Please note that you can also use this without a path parameter to * infer the config from flowR's default locations. * This is mostly useful for user-facing features. */ readonly fromFile: (this: void, configFile?: string, configWorkingDirectory?: string) => FlowrConfig; /** * Gets the configuration for the given engine type from the config. */ readonly getForEngine: <T extends EngineConfig["type"]>(this: void, config: FlowrConfig, engine: T) => (EngineConfig & { type: T; }) | undefined; /** * Returns a new config object with the given value set at the given key, where the key is a dot-separated path to the value in the config object. * @see {@link setInConfigInPlace} for a version that modifies the config object in place instead of returning a new one. * @example * ```ts * const config = FlowrConfig.default(); * const newConfig = FlowrConfig.setInConfig(config, 'solver.variables', VariableResolve.Builtin); * console.log(config.solver.variables); // Output: "alias" * console.log(newConfig.solver.variables); // Output: "builtin" * ``` */ readonly setInConfig: <Path extends ValidFlowrConfigPaths>(this: void, config: FlowrConfig, key: Path, value: PathValue<FlowrConfig, Path>) => FlowrConfig; /** * Modifies the given config object in place by setting the given value at the given key, where the key is a dot-separated path to the value in the config object. * @see {@link setInConfig} for a version that returns a new config object instead of modifying the given one in place. */ readonly setInConfigInPlace: <Path extends ValidFlowrConfigPaths>(this: void, config: FlowrConfig, key: Path, value: PathValue<FlowrConfig, Path>) => void; };