UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

184 lines (183 loc) 8.5 kB
/** * This module holds the definition of what a {@link Feature} that can be extracted from an R AST is. * * Furthermore, it contains the definition of all features that are known in {@link ALL_FEATURES}. * * @module */ import type { EvalOptions } from 'xpath-ts2/src/parse-api'; import type { MetaStatistics } from '../meta-statistics'; import type { StatisticsSummarizerConfiguration } from '../summarizer/summarizer'; import type { MergeableRecord } from '../../util/objects'; import type { DataflowInformation } from '../../dataflow/info'; import type { NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate'; import type { Document } from '@xmldom/xmldom'; /** * Maps each sub-feature name to the number of occurrences of that sub-feature. * Allows for one nesting level to denote hierarchical features. * <p> * Since we are writing to files {@link process}, we only count feature occurrences (some feature/parts are not written to file) */ export type FeatureInfo = Record<string, unknown> & MergeableRecord; /** * The information and context that a {@link FeatureProcessor} may operate in. */ export interface FeatureProcessorInput extends MergeableRecord { /** The XML Document representing the parsed (non-normalized) R AST */ readonly parsedRAst: Document; /** The R AST, after the normalization step */ readonly normalizedRAst: NormalizedAst; /** The dataflow information for the given input */ readonly dataflow: DataflowInformation; /** The filepath that the document originated from (if present, may be undefined if the input was provided as text). This can be relative to the common root directory of requests. */ readonly filepath: string | undefined; } /** * A function that processes the analysis results of a document and returns the feature information. */ export type FeatureProcessor<T extends FeatureInfo> = (existing: T, input: FeatureProcessorInput) => T; /** * A feature is something to be retrieved by the statistics. * * @typeParam T - The type of what should be collected for the feature * * @see ALL_FEATURES */ export interface Feature<T extends FeatureInfo> { /** A descriptive, yet unique name of the feature */ readonly name: string; /** A description of the feature */ readonly description: string; /** A function that retrieves the feature in the document appends it to the existing feature set (we could use a monoid :D), the filepath corresponds to the active file (if any) */ process: FeatureProcessor<T>; /** * If present, this feature allows to post-process the results of the feature extraction (for the summarizer). * <p> * The extraction can use the output path to write files to, and should return the final output. * * @param featureRoot - The root path to the feature directory which should contain all the files the feature can write to (already merged for every file processed) * @param info - The feature statistic maps each file name/context encountered to the feature information as well as the meta statistics for the file * @param outputPath - The path to write the output to (besides what is collected in the output and meta information) * @param config - The configuration for the summarizer (e.g., to obtain the number of folders to skip for the feature root) */ postProcess?: (featureRoot: string, info: Map<string, FeatureStatisticsWithMeta>, outputPath: string, config: StatisticsSummarizerConfiguration) => void; /** Values to start the existing track from */ initialValue: T; } /** * The source of truth for all features that are supported by the statistics. */ export declare const ALL_FEATURES: { readonly usedPackages: Feature<import("ts-essentials").Writable<{ library: number; require: number; loadNamespace: number; requireNamespace: number; attachNamespace: number; withinApply: number; '::': number; ':::': number; '<loadedByVariable>': number; }>>; readonly comments: Feature<import("ts-essentials").Writable<{ totalAmount: number; roxygenComments: number; import: number; importFrom: number; importMethodsFrom: number; importClassesFrom: number; useDynLib: number; export: number; exportClass: number; exportMethod: number; exportS3Method: number; exportPattern: number; }>>; readonly definedFunctions: Feature<import("ts-essentials").Writable<{ total: number; lambdasOnly: number; assignedFunctions: number; nestedFunctions: number; recursive: number; deepestNesting: number; }>>; readonly usedFunctions: Feature<import("ts-essentials").Writable<{ allFunctionCalls: number; args: Record<number, bigint | import("./common-syntax-probability").CommonSyntaxTypeCounts>; nestedFunctionCalls: number; deepestNesting: number; unnamedCalls: number; }>>; readonly values: Feature<import("ts-essentials").Writable<{ allNumerics: number; imaginaryNumbers: number; integers: number; floatHex: number; logical: number; specialConstants: number; strings: number; }>>; readonly assignments: Feature<import("ts-essentials").Writable<{ assignmentOperator: Record<string, bigint>; assigned: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; deepestNesting: number; nestedOperatorAssignment: number; }>>; readonly loops: Feature<import("ts-essentials").Writable<{ forLoops: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; forLoopVar: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; forBody: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; whileLoops: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; whileBody: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; repeatLoops: bigint; repeatBody: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; breakStatements: number; nextStatements: number; implicitLoops: number; nestedExplicitLoops: number; deepestExplicitNesting: number; }>>; readonly controlflow: Feature<import("ts-essentials").Writable<{ ifThen: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; thenBody: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; ifThenElse: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; elseBody: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; nestedIfThen: number; nestedIfThenElse: number; deepestNesting: number; switchCase: import("./common-syntax-probability").CommonSyntaxTypeCounts<bigint>; }>>; readonly dataAccess: Feature<import("ts-essentials").Writable<{ singleBracket: Record<number, bigint | import("./common-syntax-probability").CommonSyntaxTypeCounts>; doubleBracket: Record<number, bigint | import("./common-syntax-probability").CommonSyntaxTypeCounts>; chainedOrNestedAccess: number; longestChain: number; deepestNesting: number; byName: number; bySlot: number; }>>; readonly expressionList: Feature<import("ts-essentials").Writable<{ allExpressionLists: number; deepestNesting: number; }>>; readonly variables: Feature<import("ts-essentials").Writable<{ numberOfVariableUses: number; numberOfDefinitions: number; numberOfRedefinitions: number; unknownVariables: number; }>>; }; export type FeatureKey = keyof typeof ALL_FEATURES; export type FeatureValue<K extends FeatureKey> = ReturnType<typeof ALL_FEATURES[K]['process']>; /** If the user passes `all`, this should be every feature present in {@link ALL_FEATURES} (see {@link allFeatureNames})*/ export type FeatureSelection = Set<FeatureKey>; export declare const allFeatureNames: Set<FeatureKey>; export type FeatureStatistics = { [K in FeatureKey]: FeatureInfo; }; export type FeatureStatisticsWithMeta = FeatureStatistics & { stats: MetaStatistics; }; export interface Query { select(options?: EvalOptions): Node[]; }