@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
249 lines (248 loc) • 12 kB
TypeScript
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 — 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 {};