UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

182 lines (181 loc) 9.94 kB
import { RType } from '../r-bridge/lang-4.x/ast/model/type'; import type { VertexType } from '../dataflow/graph/vertex'; import type { ParentInformation } from '../r-bridge/lang-4.x/ast/model/processing/decorate'; import type { FlowrSearchElement } from './flowr-search'; import type { Enrichment } from './search-executor/search-enrichers'; import type { DataflowInformation } from '../dataflow/info'; import type { BuiltInProcName } from '../dataflow/environments/built-in-proc-name'; import type { RoleInParent } from '../r-bridge/lang-4.x/ast/model/processing/role'; import type { CallProps } from '../dataflow/environments/built-in-props'; export type FlowrFilterName = keyof typeof FlowrFilters; interface FlowrFilterWithArgs<Filter extends FlowrFilterName, Args extends FlowrFilterArgs<Filter>> { name: Filter; args: Args; } export declare enum FlowrFilter { /** * Drops search elements that represent empty arguments. Specifically, all nodes that are arguments and have an undefined name are skipped. * This filter does not accept any arguments. */ DropEmptyArguments = "drop-empty-arguments", /** * Only returns search elements whose enrichments' JSON representations match a given test regular expression. * This filter accepts {@link MatchesEnrichmentArgs}, which includes the enrichment to match for, as well as the regular expression to test the enrichment's (non-pretty-printed) JSON representation for. * To test for included function names in an enrichment like {@link Enrichment.CallTargets}, the helper function {@link matchIdentifiers} can be used. */ MatchesEnrichment = "matches-enrichment", /** * Only returns search elements whose {@link FunctionOriginInformation} match a given pattern or value. * This filter accepts {@link OriginKindArgs}, which includes the {@link DataflowGraphVertexFunctionCall.origin} to match for, whether to match for every or some origins, and whether to include non-function-calls in the filtered query. */ OriginKind = "origin-kind", /** * Only returns search element whose {@link RoleInParent} matches a given {@link RoleInParent}. * This filter accepts an object containing a `roleInParent` argument of type {@link RoleInParent}. */ RoleInParent = "role-in-parent", /** * Only returns search elements whose file path matches the given regular expression. * This filter accepts {@link FilePathFilterArgs}, which includes the file path regex to test against. */ FilePathFilter = "file-path-filter", /** * Only returns function calls whose {@link CallProp} bits match the given mask, so that _every call that asks * the user_ or _every call that closes a device_ can be searched for without naming a single function. * This filter accepts {@link CallPropsArgs}. */ CallProps = "call-props" } export type FlowrFilterFunction<T> = (e: FlowrSearchElement<ParentInformation>, args: T, data: { dataflow: DataflowInformation; }) => boolean; export declare const ValidFlowrFilters: Set<string>; export declare const ValidFlowrFiltersReverse: { [k: string]: string; }; export declare const FlowrFilters: { readonly "drop-empty-arguments": (e: FlowrSearchElement<ParentInformation>, _args: never) => boolean; readonly "matches-enrichment": (e: FlowrSearchElement<ParentInformation>, args: MatchesEnrichmentArgs<Enrichment>) => never; readonly "origin-kind": (e: FlowrSearchElement<ParentInformation>, args: OriginKindArgs, data: { dataflow: DataflowInformation; }) => boolean; readonly "role-in-parent": (e: FlowrSearchElement<ParentInformation>, { roleInParent }: { roleInParent: RoleInParent; }) => boolean; readonly "file-path-filter": (e: FlowrSearchElement<ParentInformation>, args: FilePathFilterArgs) => boolean; readonly "call-props": (e: FlowrSearchElement<ParentInformation>, args: CallPropsArgs, data: { dataflow: DataflowInformation; }) => boolean; }; export type FlowrFilterArgs<F extends FlowrFilter> = typeof FlowrFilters[F] extends FlowrFilterFunction<infer Args> ? Args : never; export interface MatchesEnrichmentArgs<E extends Enrichment> { enrichment: E; /** * The object to test the enrichment value against, which should be a partial {@link EnrichmentElementContent} with each value to test for replaced by a {@link RegExp} or value to match against. The test will pass if the partial structure matches and the enrichment value at each {@link RegExp}, string or primitive location matches the corresponding regular expression. For array entries, {@link arrayMatch} determines whether every element in the array has to match the given expected value, or only some. */ test: Record<string, unknown>; /** * For array entries, the expected value in {@link test} is compared against each array entry in the real value. This property determines whether every element in the array has to match, or only some. If unset, this defaults to `some`. */ arrayMatch?: 'some' | 'every'; } export interface OriginKindArgs { origin: BuiltInProcName | RegExp; matchType?: 'some' | 'every'; keepNonFunctionCalls?: boolean; } export interface FilePathFilterArgs { filePathRegex: string | RegExp; } export interface CallPropsArgs { /** the {@link CallProp} bits to look for, e.g. `CallProp.User | CallProp.Closes` */ props: CallProps; /** whether a call has to carry every bit of {@link props} or just one of them (the default) */ matchType?: 'some' | 'every'; } type ValidFilterTypes<F extends FlowrFilter = FlowrFilter> = FlowrFilterName | FlowrFilterWithArgs<F, FlowrFilterArgs<F>> | RType | VertexType; /** * By default, we provide filter for every {@link RType} and {@link VertexType}. */ export type FlowrFilterExpression<F extends FlowrFilter = FlowrFilter> = FlowrFilterCombinator | ValidFilterTypes<F>; interface BooleanBinaryNode<Composite> { readonly type: 'and' | 'or' | 'xor'; readonly left: Composite; readonly right: Composite; } interface BooleanUnaryNode<Composite> { readonly type: 'not'; readonly operand: Composite; } type LeafRType = { readonly type: 'r-type'; readonly value: RType; }; type LeafVertexType = { readonly type: 'vertex-type'; readonly value: VertexType; }; type LeafSpecial<F extends FlowrFilter = FlowrFilter> = { readonly type: 'special'; readonly value: FlowrFilterName | FlowrFilterWithArgs<F, FlowrFilterArgs<F>>; }; type Leaf = LeafRType | LeafVertexType | LeafSpecial; type BooleanNode = BooleanBinaryNode<BooleanNode> | BooleanUnaryNode<BooleanNode> | Leaf; type BooleanNodeOrCombinator = BooleanNode | FlowrFilterCombinator; /** * @see {@link FlowrFilterCombinator.is} * @see {@link evalFilter} * @see {@link binaryTreeToString} */ export declare class FlowrFilterCombinator { private tree; protected constructor(init: BooleanNodeOrCombinator); static is<F extends FlowrFilter = FlowrFilter>(value: BooleanNodeOrCombinator | ValidFilterTypes<F>): FlowrFilterCombinator; static and<FLeft extends FlowrFilter = FlowrFilter, FRight extends FlowrFilter = FlowrFilter>(left: BooleanNodeOrCombinator | ValidFilterTypes<FLeft>, right: BooleanNodeOrCombinator | ValidFilterTypes<FRight>): FlowrFilterCombinator; static or<FLeft extends FlowrFilter = FlowrFilter, FRight extends FlowrFilter = FlowrFilter>(left: BooleanNodeOrCombinator | ValidFilterTypes<FLeft>, right: BooleanNodeOrCombinator | ValidFilterTypes<FRight>): FlowrFilterCombinator; static xor<FLeft extends FlowrFilter = FlowrFilter, FRight extends FlowrFilter = FlowrFilter>(left: BooleanNodeOrCombinator | ValidFilterTypes<FLeft>, right: BooleanNodeOrCombinator | ValidFilterTypes<FRight>): FlowrFilterCombinator; static not<F extends FlowrFilter = FlowrFilter>(value: BooleanNodeOrCombinator | ValidFilterTypes<F>): FlowrFilterCombinator; and<F extends FlowrFilter = FlowrFilter>(right: BooleanNodeOrCombinator | ValidFilterTypes<F>): this; or<F extends FlowrFilter = FlowrFilter>(right: BooleanNodeOrCombinator | ValidFilterTypes<F>): this; xor<F extends FlowrFilter = FlowrFilter>(right: BooleanNodeOrCombinator | ValidFilterTypes<F>): this; private binaryRight; not(): this; private unary; private unpack; get(): BooleanNode; } export declare const F: typeof FlowrFilterCombinator; /** * Converts the given binary tree to a string representation. */ export declare function binaryTreeToString(tree: BooleanNode): string; /** * Checks whether the given value is a binary tree combinator. * @see {@link FlowrFilterCombinator} */ export declare function isBinaryTree(tree: unknown): tree is { tree: BooleanNode; }; interface FilterData { readonly element: FlowrSearchElement<ParentInformation>; readonly data: { dataflow: DataflowInformation; }; } /** A filter expression resolved to the function testing one element. */ export type PreparedFilter = (element: FlowrSearchElement<ParentInformation>, data: { dataflow: DataflowInformation; }) => boolean; /** * Resolve a filter expression to the function that tests one element. * Nothing here depends on the element, so a search over `n` elements should do this once instead of `n` times: * a bare {@link VertexType}/{@link RType} filter otherwise builds a {@link FlowrFilterCombinator} per element. * @see {@link evalFilter} - the one-shot form, if you only test a single element */ export declare function prepareFilter<Filter extends FlowrFilter>(filter: FlowrFilterExpression<Filter>): PreparedFilter; /** * Evaluates the given filter expression against the provided data. * @see {@link prepareFilter} - resolve once when testing more than one element */ export declare function evalFilter<Filter extends FlowrFilter>(filter: FlowrFilterExpression<Filter>, data: FilterData): boolean; export {};