import type { DataflowProcessorInformation } from './processor';
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
import type { BrandedIdentifier, IdentifierReference } from './environments/identifier';
import type { REnvironmentInformation } from './environments/environment';
import { DataflowGraph } from './graph/graph';
import type { GenericDifferenceInformation, WriteableDifferenceReport } from '../util/diff';
import type { HookInformation } from './hooks';
import type { AstIdMap } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
/**
 * A control dependency links a vertex to the control flow element which
 * may have an influence on its execution.
 * Within `if(p) a else b`, `a` and `b` have a control dependency on the `if` (which in turn decides based on `p`).
 * @see {@link happensInEveryBranch} - to check whether a list of control dependencies is exhaustive
 * @see {@link negateControlDependency} - to easily negate a control dependency
 */
export interface ControlDependency {
    /** The id of the node that causes the control dependency to be active (e.g., the condition of an if) */
    readonly id: NodeId;
    /** when does this control dependency trigger (if the condition is true or false)? */
    readonly when?: boolean;
    /** whether this control dependency was created due to iteration (e.g., a loop) */
    readonly byIteration?: boolean;
    /**
     * any file-exist assumptions made
     */
    readonly file?: string;
}
/** Whether the two control dependencies trigger on the same condition and branch. */
declare function sameControlDependency(a: ControlDependency, b: ControlDependency): boolean;
/**
 * Utility functions to work with {@link ControlDependency|control dependencies}.
 */
export declare const ControlDependency: {
    readonly name: "ControlDependency";
    /** Whether the two trigger on the same condition and branch. */
    readonly same: typeof sameControlDependency;
    /** @see {@link appendCds} */
    readonly append: typeof appendCds;
    /** @see {@link withCds} */
    readonly with: typeof withCds;
    /** @see {@link negateControlDependency} */
    readonly negate: typeof negateControlDependency;
    /** @see {@link happensInEveryBranch} */
    readonly happensInEveryBranch: typeof happensInEveryBranch;
    /** @see {@link happensInEveryBranchSet} */
    readonly happensInEveryBranchSet: typeof happensInEveryBranchSet;
    /** Whether the dependency stems from a loop, so what it guards may happen more than once. */
    readonly isIterated: (this: void, cd: ControlDependency, idMap: AstIdMap | undefined) => boolean;
    /** The dependencies of `a` that `b` is not subject to as well. */
    readonly minus: (this: void, a: readonly ControlDependency[], b: readonly ControlDependency[]) => ControlDependency[];
};
/** Appends the given control dependencies to `target`, skipping the ones that are already in there. */
export declare function appendCds(target: ControlDependency[], toAdd: readonly ControlDependency[] | undefined): void;
/** A copy of `base` with `toAdd` appended, skipping the control dependencies that are already in there. */
export declare function withCds(base: readonly ControlDependency[] | undefined, toAdd: readonly ControlDependency[] | undefined): ControlDependency[];
/**
 * Negates the given control dependency (i.e., flips the `when` flag).
 * This keeps undefined `when` values intact as undefined.
 */
export declare function negateControlDependency(cd: ControlDependency): ControlDependency;
/**
 * Classifies the type of exit point encountered.
 * @see {@link ExitPoint}
 */
export declare const enum ExitPointType {
    /** The exit point is the implicit (last executed expression of a function/block) */
    Default = 0,
    /** The exit point is an explicit `return` call (or an alias of it) */
    Return = 1,
    /** The exit point is an explicit `break` call (or an alias of it) */
    Break = 2,
    /** The exit point is an explicit `next` call (or an alias of it) */
    Next = 3,
    /** The exit point is caused by an error being thrown, e.g., by `stop` or `stopifnot` */
    Error = 4
}
/**
 * Checks whether the given exit point type propagates calls (i.e., whether it aborts the current function execution).
 */
export declare function doesExitPointPropagateCalls(type: ExitPointType): boolean;
/**
 * An exit point describes the position which ends the current control flow structure.
 * This may be as innocent as the last expression or explicit with a `return`/`break`/`next`.
 * @see {@link ExitPointType} - for the different types of exit points
 * @see {@link addNonDefaultExitPoints} - to easily modify lists of exit points
 * @see {@link alwaysExits} - to check whether a list of control dependencies always triggers an exit
 * @see {@link filterOutLoopExitPoints} - to remove loop exit points from a list
 */
export interface ExitPoint {
    /** What kind of exit point is this one? May be used to filter for exit points of specific causes. */
    readonly type: ExitPointType;
    /** The id of the node which causes the exit point! */
    readonly nodeId: NodeId;
    /**
     * Control dependencies which influence if the exit point triggers
     * (e.g., if the `return` is contained within an `if` statement).
     * @see {@link happensInEveryBranch} - to check whether control dependencies are exhaustive
     */
    readonly cds?: ControlDependency[];
}
/**
 * Adds all non-default exit points to the existing list and updates the `invertExitCds` accordingly.
 */
export declare function addNonDefaultExitPoints(existing: ExitPoint[], invertExitCds: ControlDependency[], activeCds: ControlDependency[] | undefined, add: readonly ExitPoint[]): void;
/**
 * Overwrites the existing exit points with the given ones, taking care of cds.
 */
export declare function overwriteExitPoints(existing: readonly ExitPoint[], replace: ExitPoint[]): ExitPoint[];
/**
 * A reference removed from scope within the current subtree (e.g., via `rm`). Like {@link DataflowInformation#out|out}
 * references, kills bubble up so the enclosing scope can apply the removal at the right location.
 * @see {@link applyKills}
 */
export type KillReference = 
/** a statically known name (carries {@link IdentifierReference#cds|cds} for conditional removals) */
{
    readonly kind: 'named';
    readonly reference: IdentifierReference;
}
/** the whole current scope is cleared, e.g., `rm(list = ls())` */
 | {
    readonly kind: 'all';
    readonly cds?: readonly ControlDependency[];
    readonly except?: ReadonlySet<BrandedIdentifier>;
}
/** a not statically resolvable set of names, e.g., `rm(list = someVector)` */
 | {
    readonly kind: 'unknown';
    readonly cds?: readonly ControlDependency[];
    readonly except?: ReadonlySet<BrandedIdentifier>;
};
/** The control flow information for the current DataflowInformation. */
export interface DataflowCfgInformation {
    /** The entry node into the subgraph */
    entryPoint: NodeId;
    /**
     * All already identified exit points (active 'return'/'break'/'next'-likes) of the respective structure.
     * This also tracks (local knowledge of) exceptions thrown within the structure.
     * See the {@link ExitPointType#Error|Error} type for more information.
     */
    exitPoints: readonly ExitPoint[];
    /** Registered hooks within the current subtree */
    hooks: HookInformation[];
}
/**
 * The dataflow information is one of the fundamental structures we have in the dataflow analysis.
 * It is continuously updated during the dataflow analysis
 * and holds its current state for the respective subtree processed.
 * Each processor during the dataflow analysis may use the information from its children
 * to produce a new state of the dataflow information.
 *
 * You may initialize a new dataflow information with {@link DataflowInformation.initialize}.
 * @see {@link DataflowCfgInformation} - the control flow aspects
 */
export interface DataflowInformation extends DataflowCfgInformation {
    /**
     * References that have not been identified as read or write and will be so on higher processors.
     *
     * For example, when we analyze the `x` vertex in `x <- 3`, we will first create an unknown reference for `x`
     * as we have not yet seen the assignment!
     * @see {@link IdentifierReference} - a reference on a variable, parameter, function call, ...
     */
    unknownReferences: readonly IdentifierReference[];
    /**
     * References which are read within the current subtree.
     * @see {@link IdentifierReference} - a reference on a variable, parameter, function call, ...
     */
    in: readonly IdentifierReference[];
    /**
     * References which are written to within the current subtree
     * @see {@link IdentifierReference} - a reference on a variable, parameter, function call, ...
     */
    out: readonly IdentifierReference[];
    /** Current environments used for name resolution, probably updated on the next expression-list processing */
    environment: REnvironmentInformation;
    /** The current constructed dataflow graph */
    graph: DataflowGraph;
    /**
     * References removed from scope within the current subtree (e.g., via `rm`); `undefined` unless an `rm` occurred.
     * @see {@link KillReference}
     */
    kill?: readonly KillReference[];
}
/**
 * Helper object for {@link DataflowInformation}
 */
export declare const DataflowInformation: {
    readonly name: "DataflowInformation";
    /**
     * Initializes an empty {@link DataflowInformation} object with the given entry point and data.
     * This is to be used as a "starting point" when processing leaf nodes during the dataflow extraction.
     * @see {@link DataflowInformation}
     */
    readonly initialize: <T>(this: void, entryPoint: NodeId, data: Pick<DataflowProcessorInformation<T>, "environment" | "completeAst">) => DataflowInformation;
    /**
     * Type guard to check whether the given information is a {@link DataflowInformation}.
     */
    readonly is: (info: unknown) => info is DataflowInformation;
};
/**
 * Checks whether the given control dependencies are exhaustive (i.e. if for every control dependency on a boolean,
 * the list contains a dependency on the `true` and on the `false` case).
 * @see {@link happensInEveryBranchSet} - for the set-based version
 */
export declare function happensInEveryBranch(cds: readonly ControlDependency[] | undefined): boolean;
/**
 * Checks whether the given control dependencies are exhaustive (i.e. if for every control dependency on a boolean,
 * the list contains a dependency on the `true` and on the `false` case).
 * @see {@link happensInEveryBranch} - for the array-based version
 */
export declare function happensInEveryBranchSet(cds: ReadonlySet<ControlDependency> | undefined): boolean;
/**
 * Checks whether the given dataflow information always exits (i.e., if there is a non-default exit point in every branch).
 * @see {@link ExitPoint} - for the different types of exit points
 */
export declare function alwaysExits(data: DataflowInformation): boolean;
/**
 * Filters out exit points which end their cascade within a loop.
 */
export declare function filterOutLoopExitPoints(exitPoints: readonly ExitPoint[]): readonly ExitPoint[];
/**
 * Calculates the difference between two control dependencies.
 */
export declare function diffControlDependency<Report extends WriteableDifferenceReport>(a: ControlDependency | undefined, b: ControlDependency | undefined, info: GenericDifferenceInformation<Report>): void;
/**
 * Calculates the difference between two lists of control dependencies.
 */
export declare function diffControlDependencies<Report extends WriteableDifferenceReport>(a: ControlDependency[] | undefined, b: ControlDependency[] | undefined, info: GenericDifferenceInformation<Report>): void;
export {};
