@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
301 lines (300 loc) • 16.2 kB
TypeScript
import type { SourceRange } from '../../../../util/range';
import { SourceLocation } from '../../../../util/range';
import { RType } from './type';
import type { MergeableRecord } from '../../../../util/objects';
import type { RNumber } from './nodes/r-number';
import type { RString } from './nodes/r-string';
import type { RLogical } from './nodes/r-logical';
import type { RSymbol } from './nodes/r-symbol';
import type { RComment } from './nodes/r-comment';
import type { RBreak } from './nodes/r-break';
import type { RNext } from './nodes/r-next';
import type { RLineDirective } from './nodes/r-line-directive';
import type { RForLoop } from './nodes/r-for-loop';
import type { RRepeatLoop } from './nodes/r-repeat-loop';
import type { RWhileLoop } from './nodes/r-while-loop';
import type { RIfThenElse } from './nodes/r-if-then-else';
import type { RFunctionDefinition } from './nodes/r-function-definition';
import type { EmptyArgument, RFunctionCall } from './nodes/r-function-call';
import type { RParameter } from './nodes/r-parameter';
import type { RArgument } from './nodes/r-argument';
import type { RExpressionList } from './nodes/r-expression-list';
import type { RIndexAccess, RNamedAccess } from './nodes/r-access';
import type { RUnaryOp } from './nodes/r-unary-op';
import type { RBinaryOp } from './nodes/r-binary-op';
import type { RPipe } from './nodes/r-pipe';
import type { RDelimiter } from './nodes/info/r-delimiter';
import type { ParentInformation } from './processing/decorate';
import type { NodeId } from './processing/node-id';
import type { OnEnter, OnExit } from './processing/visitor';
import type { SingleOrArrayOrNothing } from '../../../../abstract-interpretation/normalized-ast-fold';
import { getDocumentationOf } from '../../../roxygen2/documentation-provider';
/** Simply an empty type constraint used to say that there are additional decorations (see {@link RAstNodeBase}). */
export type NoInfo = object;
/**
* Will be used to reconstruct the source of the given element in the R-ast.
* This will not be part of most comparisons as it is mainly of interest to the reconstruction of R code.
*/
export interface Source {
/**
* The range is different from the assigned {@link Location} as it refers to the complete source range covered by the given
* element.
* <p>
* As an example for the difference, consider a for loop, the location of `for` will be just the three characters,
* but the *range* will be everything including the loop body.
*/
fullRange?: SourceRange;
/**
* Similar to {@link Source.fullRange} this contains the complete R lexeme of the given element.
*/
fullLexeme?: string;
/**
* This may contain additional elements that were part of the original R code, but are not part of the normalized R-ast.
* This allows inline-comments!
*/
adToks?: OtherInfoNode[];
/**
* The file in which the respective node is located
*/
file?: string;
}
/**
* Provides the common base of all {@link RNode|RNodes}.
* @typeParam Info - can be used to store additional information about the node
* @typeParam LexemeType - the type of the lexeme, probably always a `string` or `string | undefined`
*/
export interface RAstNodeBase<Info, LexemeType = string> extends MergeableRecord {
type: RType;
/** the original string retrieved from R, can be used for further identification */
lexeme: LexemeType;
/** allows to attach additional information to the node */
info: Info & Source;
}
export interface WithChildren<Info, Children extends RAstNodeBase<Info, string | undefined>> {
children: readonly Children[];
}
/**
* A helper interface we use to "mark" leaf nodes.
* <p>
* Please be aware, that this is not marking from a language perspective,
* as it is equivalent to the {@link RAstNodeBase} interface.
* It is intended to help humans understand the code.
*/
export interface Leaf<Info = NoInfo, LexemeType = string> extends RAstNodeBase<Info, LexemeType> {
}
/**
* Indicates, that the respective {@link RAstNodeBase} node has known source code
* location information.
*/
export interface Location {
/**
* The location may differ from what is stated in {@link Source#fullRange} as it
* represents the location identified by the R parser.
* @see Source#fullRange
*/
location: SourceRange;
}
/**
* Represents the type of namespaces in the R programming language.
* At the moment, this is only the name of the namespace.
*/
export type NamespaceIdentifier = string;
/**
* This subtype of {@link RNode} represents all types of constants
* represented in the normalized AST.
*/
export type RConstant<Info> = RNumber<Info> | RString<Info> | RLogical<Info>;
/**
* Helper object to provide helper functions for {@link RConstant|RConstants}.
* @see {@link RNode} - for more general helper functions for all nodes
*/
export declare const RConstant: {
readonly name: "RConstant";
/**
* Type guard for {@link RConstant} nodes, i.e. checks whether a node is a number, string or logical constant.
* If you need the specific type, please either use the respective type guards (e.g., {@link RNumber.is}) or check the `type` node directly.
*/
readonly is: <Info = object>(this: void, node: RNode<Info> | undefined) => node is RConstant<Info>;
/**
* A set of all types of constants in the normalized AST, i.e. number, string and logical constants.
*/
readonly constantTypes: ReadonlySet<RType>;
};
/**
* This subtype of {@link RNode} represents all types of {@link Leaf} nodes in the
* normalized AST.
*/
export type RSingleNode<Info> = RComment<Info> | RSymbol<Info> | RConstant<Info> | RBreak<Info> | RNext<Info> | RLineDirective<Info>;
/**
* Represents a leaf node in the normalized AST, i.e. a node that does not have any children. This includes comment, symbol, constant, break, next and line directive nodes.
*/
export declare const RSingleNode: {
readonly name: "RSingleNode";
/**
* Type guard for {@link RSingleNode} nodes, i.e. checks whether a node is a comment, symbol, constant, break, next or line directive.
* If you need the specific type, please either use the respective type guards (e.g., {@link RComment.is}) or check the `type` node directly.
*/
readonly is: <Info = object>(this: void, node: RNode<Info> | undefined) => node is RSingleNode<Info>;
/**
* A set of all types of single nodes in the normalized AST, i.e. comment, symbol, constant, break, next and line directive nodes.
*/
readonly singleNodeTypes: ReadonlySet<RType>;
};
/**
* This subtype of {@link RNode} represents all looping constructs in the normalized AST.
*/
export type RLoopConstructs<Info> = RForLoop<Info> | RRepeatLoop<Info> | RWhileLoop<Info>;
export declare const RLoopConstructs: {
readonly name: "RLoopConstructs";
/**
* Type guard for {@link RLoopConstructs} nodes, i.e. checks whether a node is a for, repeat or while loop.
* If you need the specific type, please either use the respective type guards (e.g., {@link RForLoop.is}) or check the `type` node directly.
*/
readonly is: <Info = object>(this: void, node: RNode<Info> | undefined) => node is RLoopConstructs<Info>;
/**
* A set of all types of loop constructs in the normalized AST, i.e. for, repeat and while loops.
*/
readonly loopConstructTypes: ReadonlySet<RType>;
};
/**
* As an extension to {@link RLoopConstructs}, this subtype of {@link RNode} includes
* the {@link RIfThenElse} construct as well.
*/
export type RConstructs<Info> = RLoopConstructs<Info> | RIfThenElse<Info>;
export declare const RConstructs: {
readonly name: "RConstructs";
/**
* Type guard for {@link RConstructs} nodes, i.e. checks whether a node is a for, repeat or while loop or an if-then-else construct.
* If you need the specific type, please either use the respective type guards (e.g., {@link RForLoop.is}) or check the `type` node directly.
*/
readonly is: <Info = object>(this: void, node: RNode<Info> | undefined) => node is RConstructs<Info>;
/**
* A set of all types of constructs in the normalized AST, i.e. for, repeat and while loops and if-then-else constructs.
*/
readonly constructTypes: ReadonlySet<RType>;
};
/**
* This subtype of {@link RNode} represents all types related to functions
* (calls and definitions) in the normalized AST.
*/
export type RFunctions<Info> = RFunctionDefinition<Info> | RFunctionCall<Info> | RParameter<Info> | RArgument<Info>;
export declare const RFunctions: {
readonly name: "RFunctions";
/**
* Type guard for {@link RFunctions} nodes, i.e. checks whether a node is a function definition, function call, parameter or argument.
* If you need the specific type, please either use the respective type guards (e.g., {@link RFunctionDefinition.is}) or check the `type` node directly.
*/
readonly is: <Info = object>(this: void, node: RNode<Info> | undefined) => node is RFunctions<Info>;
/**
* A set of all types of function-related nodes in the normalized AST, i.e. function definitions, function calls, parameters and arguments.
*/
readonly functionTypes: ReadonlySet<RType>;
};
/**
* This subtype of {@link RNode} represents all types of otherwise hard to categorize
* nodes in the normalized AST. At the moment these are the comment-like nodes.
*/
export type ROther<Info> = RComment<Info> | RLineDirective<Info>;
export declare const ROther: {
readonly name: "ROther";
/**
* Type guard for {@link ROther} nodes, i.e. checks whether a node is a comment or line directive.
* If you need the specific type, please either use the respective type guards (e.g., {@link RComment.is}) or check the `type` node directly.
*/
readonly is: <Info = object>(this: void, node: RNode<Info> | undefined) => node is ROther<Info>;
};
/**
* The `RNode` type is the union of all possible nodes in the R-ast.
* It should be used whenever you either not care what kind of
* node you are dealing with or if you want to handle all possible nodes.
* <p>
*
* All other subtypes (like {@link RLoopConstructs}) listed above
* can be used to restrict the kind of node. They do not have to be
* exclusive, some nodes can appear in multiple subtypes.
* @see {@link recoverName} - to receive the name/lexeme from such a node
* @see {@link recoverContent} - for a more rigorous approach to get the content of a node within a {@link DataflowGraph|dataflow graph}
* @see {@link RNode.getLocation} - to get the location of a node and other helpful functions provided by the {@link RNode} helper object
*/
export type RNode<Info = NoInfo> = RExpressionList<Info> | RFunctions<Info> | ROther<Info> | RConstructs<Info> | RNamedAccess<Info> | RIndexAccess<Info> | RUnaryOp<Info> | RBinaryOp<Info> | RSingleNode<Info> | RPipe<Info>;
/**
* Helper object to provide helper functions for {@link RNode|RNodes}.
* For the individual type checks, please consult the individual vertices, e.g. {@link RPipe.is}.
* Some vertices also have a {@link RPipe.availableFromRVersion} property that indicates from which R version they are available,
* so you can check for that as well if needed.
* @see {@link DefaultNormalizedAstFold} - for a more powerful way to traverse the normalized AST
*/
export declare const RNode: {
readonly name: "RNode";
/**
* A helper function to retrieve the location of a given node, if available.
* @see SourceLocation.fromNode
*/
readonly getLocation: (this: void, node: RNode) => SourceLocation | undefined;
/**
* A helper function to retrieve the id of a given node, if available.
*/
readonly getId: (this: void, node: RNode<ParentInformation>) => NodeId;
/**
* A helper function to retrieve the type of a given node.
*/
readonly getType: (this: void, node: RNode) => RType;
/**
* Visits all node ids within a tree given by a respective root node using a depth-first search with prefix order.
* @param nodes - The root id nodes to start collecting from
* @param onVisit - Called before visiting the subtree of each node. Can be used to stop visiting the subtree starting with this node (return `true` stop)
* @param onExit - Called after the subtree of a node has been visited, called for leafs too (even though their subtree is empty)
* @see {@link RProject.visitAst} - to visit all nodes in a project
*/
readonly visitAst: <OtherInfo = object>(this: void, nodes: SingleOrArrayOrNothing<RNode<OtherInfo>>, onVisit?: OnEnter<OtherInfo>, onExit?: OnExit<OtherInfo>) => void;
/**
* Collects all node ids within a tree given by a respective root node
* @param nodes - The root id nodes to start collecting from
* @see {@link collectAllIdsWithStop} - to stop collecting at certain nodes
* @see {@link RProject.collectAllIds} - to collect all ids within a project
*/
readonly collectAllIds: <OtherInfo>(this: void, nodes: SingleOrArrayOrNothing<RNode<OtherInfo & ParentInformation>>) => Set<NodeId>;
/**
* Collects all direct children of a given node, i.e. all nodes that are directly reachable via a property of the given node.
*/
readonly directChildren: <OtherInfo>(this: void, node: RNode<OtherInfo>) => readonly (RNode<OtherInfo> | typeof EmptyArgument)[];
/**
* Returns the direct parent of a node.
* Usually, only root nodes do not have a parent, and you can assume that there is a
* linear chain of parents leading to the root node.
* @see {@link iterateParents} - to get all parents of a node
*/
readonly directParent: <OtherInfo>(this: void, node: RNode<OtherInfo & ParentInformation>, idMap: Map<NodeId, RNode<OtherInfo & ParentInformation>>) => RNode<OtherInfo & ParentInformation> | undefined;
/**
* Returns an iterable of all parents of a node, starting with the direct parent and ending with the root node.
*/
readonly iterateParents: <OtherInfo>(this: void, node: RNode<OtherInfo & ParentInformation> | undefined, idMap: Map<NodeId, RNode<OtherInfo & ParentInformation>>) => Generator<RNode<OtherInfo & ParentInformation>>;
/**
* In contrast to the nesting stored in the {@link RNode} structure,
* this function calculates the depth of a node by counting the number of parents until the root node is reached.
*/
readonly depth: (this: void, node: RNode<ParentInformation>, idMap: Map<NodeId, RNode<ParentInformation>>) => number;
/**
* Collects all node ids within a tree given by a respective root node, but stops collecting at nodes where the given `stop` function returns `true`.
* <p>
* This can be used to exclude certain subtrees from the collection, for example to exclude function bodies when collecting ids on the root level.
* @param nodes - The root id nodes to start collecting from
* @param stop - A function that determines whether to stop collecting at a given node, does not stop by default
* @see {@link collectAllIds} - to collect all ids without stopping
* @see {@link RProject.collectAllIdsWithStop} - to collect all ids within a project with stopping
*/
readonly collectAllIdsWithStop: <OtherInfo>(this: void, nodes: SingleOrArrayOrNothing<RNode<OtherInfo & ParentInformation>>, stop: (node: RNode<OtherInfo & ParentInformation>) => boolean) => Set<NodeId>;
/**
* A helper function to retrieve the lexeme of a given node, if available.
* If the `fullLexeme` is available, it will be returned, otherwise the `lexeme` will be returned.
*/
readonly lexeme: <R extends RNode<ParentInformation>>(this: void, node: R | undefined) => R extends {
lexeme: string;
} ? string : string | undefined;
/**
* Return the (roxygen) documentation associated with the given node, if available.
* @see {@link getDocumentationOf}
*/
readonly documentation: typeof getDocumentationOf;
};
export type OtherInfoNode = RNode | RDelimiter;