UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

249 lines (248 loc) 12 kB
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id'; import type { MergeableRecord } from '../util/objects'; import type { RFalse, RTrue } from '../r-bridge/lang-4.x/convert-values'; export declare enum CfgVertexType { /** Marks a break point in a construct (e.g., between the name and the value of an argument, or the formals and the body of a function) */ MidMarker = "mid", /** The explicit exit-nodes to ensure the hammock property */ EndMarker = "end", /** something like an if, assignment, ... even though in the classical sense of R they are still expressions */ Statement = "stm", /** something like an addition, ... */ Expression = "expr", /** a (as far as R allows this) 'basic' block */ Block = "blk" } export declare const enum CfgEdgeType { /** a flow dependency */ Fd = 0, /** a control dependency */ Cd = 1 } export declare function edgeTypeToString(type: CfgEdgeType): string; /** * A plain vertex in the {@link ControlFlowGraph}. * Please use {@link CfgSimpleVertex} to refer to all potential vertex types within the graph. */ interface CfgBaseVertex extends MergeableRecord { /** the type of the vertex */ type: CfgVertexType; /** the id of the vertex, for non-blocks this should directly relate to the AST node */ id: NodeId; /** child nodes attached to this one */ children?: NodeId[]; /** if the vertex calls a function, this links all targets of this call */ callTargets?: Set<NodeId>; } interface CfgWithMarker extends CfgBaseVertex { /** mid-markers linked to this statement */ mid?: NodeId[]; /** end-markers linked to this statement */ end?: NodeId[]; } export interface CfgStatementVertex extends CfgWithMarker { type: CfgVertexType.Statement; } export interface CfgExpressionVertex extends CfgWithMarker { type: CfgVertexType.Expression; } export interface CfgWithRoot extends CfgBaseVertex { /** the vertex for which this is a marker */ root: NodeId; } export interface CfgMidMarkerVertex extends CfgWithRoot { type: CfgVertexType.MidMarker; kind: string; } export interface CfgEndMarkerVertex extends CfgWithRoot { type: CfgVertexType.EndMarker; } export interface CfgBasicBlockVertex extends CfgBaseVertex { type: CfgVertexType.Block; /** The vertices that are part of this block, only connected by FDs, vertices should never occur in multiple bbs */ elems: readonly Exclude<CfgSimpleVertex, CfgBasicBlockVertex>[]; } /** * A vertex in the {@link ControlFlowGraph}. */ export type CfgSimpleVertex = CfgStatementVertex | CfgExpressionVertex | CfgBasicBlockVertex | CfgMidMarkerVertex | CfgEndMarkerVertex; export declare function equalVertex(a: CfgSimpleVertex, b: CfgSimpleVertex): boolean; interface CfgFlowDependencyEdge extends MergeableRecord { label: CfgEdgeType.Fd; } export interface CfgControlDependencyEdge extends MergeableRecord { label: CfgEdgeType.Cd; /** the id which caused the control dependency */ caused: NodeId; /** is the control dependency satisfied with a true condition or is it negated (e.g., else-branch)? */ when: typeof RTrue | typeof RFalse; } export type CfgEdge = CfgFlowDependencyEdge | CfgControlDependencyEdge; /** * A read-only view of the {@link ControlFlowGraph}. */ export interface ReadOnlyControlFlowGraph { /** * Get all ids of the root vertices &mdash; vertices that are not part of * any function definition or basic block and hence part of the "top-level" control flow. * * This is the pendant of {@link DataflowGraph#rootIds|rootIds()} on a {@link DataflowGraph}. * * @see {@link ReadOnlyControlFlowGraph#vertices|vertices()} - for a way to get all vertices in the graph. * @see {@link ReadOnlyControlFlowGraph#getVertex|getVertex()} - for a way to get a specific vertex by its id. * @see {@link ReadOnlyControlFlowGraph#edges|edges()} - for a way to get all edges in the graph. */ readonly rootIds: () => ReadonlySet<NodeId>; /** * Provide a view of all vertices in the graph. * * @param includeBasicBlockElements - if true, the elements of basic block elements are included in the result, otherwise this will only the basic blocks themselves * * @see {@link ReadOnlyControlFlowGraph#rootVertexIds|rootVertexIds()} - for a way to get the root vertices of the graph. * @see {@link ReadOnlyControlFlowGraph#getVertex|getVertex()} - for a way to get a specific vertex by its id. * @see {@link ReadOnlyControlFlowGraph#edges|edges()} - for a way to get all edges in the graph. */ readonly vertices: (includeBasicBlockElements: boolean) => ReadonlyMap<NodeId, CfgSimpleVertex>; /** * Get all edges in the graph, independent of their sources and targets. * If you are only interested in the edges of a specific node, please use {@link ReadOnlyControlFlowGraph#outgoingEdges|outgoingEdges()} or {@link ReadOnlyControlFlowGraph#ingoingEdges|ingoingEdges()}. * * This is the pendant of {@link DataflowGraph#edges|edges()} on a {@link DataflowGraph}. */ readonly edges: () => ReadonlyMap<NodeId, ReadonlyMap<NodeId, CfgEdge>>; /** * Receive all outgoing edges of a given vertex. * * This is the pendant of {@link DataflowGraph#ingoingEdges|ingoingEdges()} on a {@link DataflowGraph}. * * @see {@link ReadOnlyControlFlowGraph#ingoingEdges|ingoingEdges()} - for a way to get all ingoing edges of a vertex. */ readonly outgoingEdges: (id: NodeId) => ReadonlyMap<NodeId, CfgEdge> | undefined; /** * Receive all ingoing edges of a given vertex. * * This is the pendant of {@link DataflowGraph#outgoingEdges|outgoingEdges()} on a {@link DataflowGraph}. * * @see {@link ReadOnlyControlFlowGraph#outgoingEdges|outgoingEdges()} - for a way to get all outgoing edges of a vertex. */ readonly ingoingEdges: (id: NodeId) => ReadonlyMap<NodeId, CfgEdge> | undefined; /** * Retrieve a vertex by its id. * * @param id - the id of the vertex to retrieve * @param includeBlocks - if true, the elements of basic block elements are included in the result, otherwise this will only the basic blocks themselves * * This is the pendant of {@link DataflowGraph#getVertex|getVertex()} on a {@link DataflowGraph}. */ readonly getVertex: (id: NodeId, includeBlocks?: boolean) => CfgSimpleVertex | undefined; /** * Check if a vertex with the given id exists in the graph. * * @param id - the id of the vertex to check * @param includeBlocks - if true, the elements of basic block elements are included in the check, otherwise this will only check the basic blocks themselves * * This is the pendant of {@link DataflowGraph#hasVertex|hasVertex()} on a {@link DataflowGraph}. */ readonly hasVertex: (id: NodeId, includeBlocks?: boolean) => boolean; /** * Obtain the basic block associated with the given element id (i.e. if this is an element within a basic block, return the blockit belongs to). */ readonly getBasicBlock: (elemId: NodeId) => CfgBasicBlockVertex | undefined; /** * Returns true if the graph may contain basic blocks and false if we know that it does not. * This can be used for optimizations. */ readonly mayHaveBasicBlocks: () => boolean; } /** * This class represents the control flow graph of an R program. * The control flow may be hierarchical when confronted with function definitions (see {@link CfgSimpleVertex} and {@link CFG#rootVertexIds|rootVertexIds()}). * * There are two very simple visitors to traverse a CFG: * - {@link visitCfgInOrder} visits the graph in the order of the vertices * - {@link visitCfgInReverseOrder} visits the graph in reverse order * * If you want to prohibit modification, please refer to the {@link ReadOnlyControlFlowGraph} interface. */ export declare class ControlFlowGraph<Vertex extends CfgSimpleVertex = CfgSimpleVertex> implements ReadOnlyControlFlowGraph { private readonly rootVertices; /** Nesting-Independent vertex information, mapping the id to the vertex */ private readonly vertexInformation; /** the basic block children map contains a mapping of ids to all vertices that are nested in basic blocks, mapping them to the Id of the block they appear in */ private readonly bbChildren; /** basic block agnostic edges */ private readonly edgeInformation; /** used as an optimization to avoid unnecessary lookups */ private _mayHaveBasicBlocks; /** * Add a new vertex to the control flow graph. * * @see {@link ControlFlowGraph#addEdge|addEdge()} - to add an edge */ addVertex(vertex: Vertex, rootVertex?: boolean): this; /** * Add a new edge to the control flow graph. * * @see {@link ControlFlowGraph#addVertex|addVertex()} - to add vertices * @see {@link ControlFlowGraph#addEdges|addEdges()} - to add multiple edges at once */ addEdge(from: NodeId, to: NodeId, edge: CfgEdge): this; /** * Add multiple edges from a given source vertex to the control flow graph. */ addEdges(from: NodeId, to: Map<NodeId, CfgEdge>): this; outgoingEdges(node: NodeId): ReadonlyMap<NodeId, CfgEdge> | undefined; ingoingEdges(id: NodeId): ReadonlyMap<NodeId, CfgEdge> | undefined; rootIds(): ReadonlySet<NodeId>; vertices(includeBasicBlockElements?: boolean): ReadonlyMap<NodeId, CfgSimpleVertex>; getBasicBlock(elemId: NodeId): CfgBasicBlockVertex | undefined; edges(): ReadonlyMap<NodeId, ReadonlyMap<NodeId, CfgEdge>>; /** * Retrieve a vertex by its id. */ getVertex(id: NodeId, includeBlocks?: boolean): CfgSimpleVertex | undefined; hasVertex(id: NodeId, includeBlocks?: boolean): boolean; mayHaveBasicBlocks(): boolean; /** * This removes the vertex and all edges to and from it. * @param id - the id of the vertex to remove * * @see {@link ControlFlowGraph#addVertex|addVertex()} - to add a vertex * @see {@link ControlFlowGraph#removeEdge|removeEdge()} - to remove a specific edge */ removeVertex(id: NodeId): this; /** * Removes a all direct edges between `from` and `to` from the control flow graph. * * @see {@link ControlFlowGraph#addEdge|addEdge()} - to add an edge * @see {@link ControlFlowGraph#removeVertex|removeVertex()} - to remove a vertex and all its edges */ removeEdge(from: NodeId, to: NodeId): this; /** merges b into a */ mergeTwoBasicBlocks(a: NodeId, b: NodeId): this; /** * Merge another control flow graph into this one. * @param other - the other control flow graph to merge into this one * @param forceNested - should the other graph be assumed to be fully nested (e.g., within a function definition). * * This is the pendant of {@link DataflowGraph#mergeWith|mergeWith()} on a {@link DataflowGraph}. */ mergeWith(other: ControlFlowGraph<Vertex>, forceNested?: boolean): this; } /** Summarizes the control information of a program */ export interface ControlFlowInformation<Vertex extends CfgSimpleVertex = CfgSimpleVertex> extends MergeableRecord { /** all active 'return'(-like) unconditional jumps */ returns: NodeId[]; /** all active 'break'(-like) unconditional jumps */ breaks: NodeId[]; /** all active 'next'(-like) unconditional jumps */ nexts: NodeId[]; /** intended to construct a hammock graph, with 0 exit points representing a block that should not be part of the CFG (like a comment) */ entryPoints: NodeId[]; /** See {@link ControlFlowInformation#entryPoints|entryPoints} */ exitPoints: NodeId[]; /** the control flow graph summarizing the flow information */ graph: ControlFlowGraph<Vertex>; } export declare function emptyControlFlowInformation(): ControlFlowInformation; export {};