import { types as t } from "@marko/compiler";
import { ReservedId } from "../../common/types";
import * as BindingType from "./constants/binding-type";
import { type Opt, type SortedMany, type SortedOpt, Sorted } from "./optional";
import { type AssignedBindingExtra, type Read, type ReferencedExtra } from "./references";
import { type Section } from "./sections";
import { type Sources } from "./sources";
type BindingType = BindingType.Value;
export { BindingType };
export interface Binding {
    /** Its scope accessor id, allocated per section once references finalize. */
    id: number;
    /** Creation order, never renumbered: the order `bindingUtil` sorts by. */
    uid: number;
    name: string;
    originalName: string | undefined;
    type: BindingType;
    loc: t.SourceLocation | null;
    section: Section;
    closureSections: SortedOpt<Section>;
    /** The id its closure accessors take, past its section's and ancestors' ids. */
    closureId: number | undefined;
    /** The identifier of each emitted assignment to it (set in finalize). */
    assignments: Opt<AssignedBindingExtra>;
    sources: undefined | Sources;
    /** The intersection whose work computes it, or the nearest one it derives
     * from. Set on alias roots only. */
    intersection: Intersection | undefined;
    /** The expressions its value is computed from, `false` for none; unset when
     * analysis cannot see them, which makes it its own source. */
    derivedFrom: Opt<t.NodeExtra> | false;
    /** Its reads by expression, complete once `finalizeReferences` runs: pruning
     * hands an expression's reads to the nearest ancestor it also reads. */
    reads: Map<ReferencedExtra, Opt<Read>>;
    aliases: Set<Binding>;
    /** The sections reading it through a hoist: its own or its ancestors, so
     * the first is the outermost. */
    hoists: SortedOpt<Section>;
    getters: Map<Getter["hoisted"], boolean>;
    property: string | undefined;
    propertyAliases: Map<string, Binding>;
    excludeProperties: SortedOpt<string>;
    /** Its properties code assigns in place (`obj.x = 1`), all of them for a
     * computed one. */
    assignedProperties: SortedOpt<string> | true;
    aliasOf: Binding | undefined;
    /** The value these `<for>` params iterate, by `of` or `in`. */
    iterates: {
        expr: t.NodeExtra;
        type: "of" | "in";
    } | undefined;
    /** For an array rest, the source index it starts at: `rest[0]` of
     * `[a, ...rest]` is the source's `[1]`. */
    restOffset: number | undefined;
    /** For a tag variable a child's `<return>` writes, the node binding of the
     * tag rendering that child. */
    returnedBy: Binding | undefined;
    /** Scope ids it holds right after its own, up to its highest `ReservedId`:
     * a controllable `<let>`'s change handler, or a tag's scope offset. */
    reserveSize: number;
    scopeAccessor: string | undefined;
    /** A name declared for this value, or all of it but its `excludeProperties`
     * (a rest element), even once pruned. */
    declaredAlias: Binding | undefined;
    /** The attribute tag `<for>` param a local closure holds in its section. */
    localOf: Binding | undefined;
    /** An attribute tag `<for>` param's local closure in each content the loop
     * creates that reads it. */
    localClosures: Map<Section, Binding> | undefined;
    /** Declared by its own name in its own section; an alias only in a pattern
     * holding a rest or where what it reads from is hidden from a read of it. */
    declared: boolean;
    nullable: boolean;
    /** Settled only once `finalizeReferences` runs at program analyze exit. */
    pruned: boolean | undefined;
    /** In a template's or `<define>`'s params tree, which known call sites set
     * directly. */
    exposed: boolean;
    /** Read on invocation from its own scope slot, so its signal stores it. */
    hasLazyReads: boolean;
}
/** A param of a template or of a tag body, which its caller supplies. */
export interface ParamBinding extends Binding {
    type: typeof BindingType.param;
}
export type ReferencedBindings = SortedOpt<Binding>;
export type Intersection = SortedMany<Binding>;
/** Every member computed from one local source in the same pass, or the
 * intersection's own render id and the tag whose scope offset it renders after. */
export type IntersectionMeta = {
    source: Binding;
    id?: undefined;
    returnedBy?: undefined;
} | {
    source: undefined;
    id: number;
    returnedBy: Binding | undefined;
};
export interface Getter {
    hoisted: Section | false;
    invoked: boolean;
}
export declare const getBindings: () => Set<Binding>;
export declare function createBinding(name: string, type: Binding["type"], refSection: Section, aliased?: Binding["aliasOf"], property?: string, excludeProperties?: SortedOpt<string>, loc?: t.SourceLocation | null, refDeclared?: boolean, restOffset?: number): Binding;
export declare function reserveId(binding: Binding, offset: ReservedId): void;
export declare function ensurePropertyAlias(binding: Binding, property: string): Binding;
export declare function addAssignedProperty(binding: Binding, property: string | undefined): void;
export declare function getAssignedObject(binding: Binding): Binding | undefined;
export declare function getPropertyAlias(binding: Binding, properties: Opt<string>): Binding | undefined;
export declare function getDeepestPropertyAlias(binding: Binding, properties: Opt<string>): Binding;
export declare function compareReferences(a: ReferencedBindings, b: ReferencedBindings): number;
/**
 * reference group priority is sorted by number of references,
 * then if needed by reference order.
 */
export declare function compareIntersections(a: Intersection, b: Intersection): number;
export declare function getAliasRoot(binding: Binding): Binding;
export declare const bindingUtil: Sorted<Binding>;
export declare const propsUtil: Sorted<string>;
export declare function getCanonicalBinding(binding: Binding): Binding;
export declare function someAlias<A>(binding: Binding, test: (binding: Binding, arg: A) => boolean, arg: A, directOnly?: boolean): boolean;
export declare function someUpToAliasRoot<A>(binding: Binding | undefined, test: (binding: Binding, arg: A) => boolean, arg: A): boolean;
export declare function getNearestDeclared(binding: Binding): Binding | undefined;
export declare function getDeclaredAlias(binding: Binding): false | Binding | undefined;
export declare function isDirectAlias(binding: Binding): boolean;
export declare function isRest(binding: Binding): boolean;
export declare function getDebugAccess(binding: Binding, toParam: boolean, formatProperty: (property: string) => string): {
    root: Binding;
    access: string;
};
export declare function isTemplateParam(binding: Binding): boolean;
export declare function getDebugName(binding: Binding): string;
export declare function getDebugNames(refs: ReferencedBindings): string;
export declare function getDebugNamesAsIdentifier(refs: ReferencedBindings): string;
export declare function isInvokeOnlyBinding(binding: Binding): boolean;
export declare function isOwnBinding(binding: Binding): boolean;
export declare function hasNonConstantPropertyAlias(ref: Binding): boolean;
export declare function getPropertyPath(binding: Binding, ancestor: Binding): Opt<string>;
export declare function isIndexProperty(property: string): boolean;
