Skip to content

Draw arguments

The reading adapter over the DrawArg AST.

Internal module

This module is an implementation detail of the compiler and its tooling. Its __all__ is empty, so none of the names below are part of the public API, and they may change without notice.

draw_args

Reading adapter over the DSL DrawArg AST for the transpile.

The DSL models a draw-step argument with a recursive DrawArg tagged union: an atom is a DrawArgScalar (number), a DrawArgName (identifier), or a DrawArgIndex (bracket-indexed reference); a vector literal [a, b] is a DrawArgList whose items are atoms; a matrix literal [[a, b], [c, d]] is a DrawArgList whose items are themselves DrawArgLists.

The transpile pipeline reads those arguments as flat forms: atoms (numbers, identifiers, bracket-encoded references), vectors of atoms, and matrices of atoms. This module is the single boundary that translates the recursive AST shape into those flat forms, so the lowering pass, the resolver, and the backend renderers never match DrawArg variants or reach into items themselves. They call atom_value, list_items, list_atoms, is_matrix, and matrix_rows instead.

A bracket-indexed reference re-serialises to the repeated-bracket surface form theta[i] / w[i][j] that the backends' own index regex consumes, via encode_index.

argument_parameter

argument_parameter(arg: DrawArg) -> str | None

Return the keyword carried by a structural named argument.

Source code in src/quivers/dsl/draw_args.py
def argument_parameter(arg: DrawArg) -> str | None:
    """Return the keyword carried by a structural named argument."""
    return arg.parameter if isinstance(arg, DrawArgNamed) else None

argument_value

argument_value(arg: DrawArg) -> DrawArg

Return a named argument's value, or arg when it is positional.

Source code in src/quivers/dsl/draw_args.py
def argument_value(arg: DrawArg) -> DrawArg:
    """Return a named argument's value, or ``arg`` when it is positional."""
    return arg.value if isinstance(arg, DrawArgNamed) else arg

bind_family_arguments

bind_family_arguments(family: str, args: tuple[DrawArg, ...], canonical: tuple[str, ...] = ()) -> tuple[tuple[str, DrawArg], ...]

Validate and order one keyword-only family construction.

The AST retains the names authors wrote. This boundary matches those names against one complete schema and returns values in that schema's canonical order, so positional target APIs never depend on source order.

Source code in src/quivers/dsl/draw_args.py
def bind_family_arguments(
    family: str,
    args: tuple[DrawArg, ...],
    canonical: tuple[str, ...] = (),
) -> tuple[tuple[str, DrawArg], ...]:
    """Validate and order one keyword-only family construction.

    The AST retains the names authors wrote. This boundary matches those
    names against one complete schema and returns values in that schema's
    canonical order, so positional target APIs never depend on source order.
    """
    if not args:
        return ()
    schemas = family_parameterizations(family, canonical)
    rendered = render_parameterizations(schemas)
    if not schemas:
        raise TypeError(f"family {family!r} does not take named arguments")
    bound: dict[str, DrawArg] = {}
    for argument in args:
        if not isinstance(argument, DrawArgNamed):
            raise TypeError(
                f"family {family!r} arguments are keyword-only; "
                f"use one complete schema: {rendered}"
            )
        if argument.parameter in bound:
            raise TypeError(
                f"family {family!r} is given parameter {argument.parameter!r} twice"
            )
        bound[argument.parameter] = argument.value
    selected = next((schema for schema in schemas if set(schema) == set(bound)), None)
    if selected is None:
        raise TypeError(
            f"family {family!r} requires exactly one complete parameter schema "
            f"{rendered}; got ({', '.join(bound)})"
        )
    return tuple((name, bound[name]) for name in selected)

encode_index

encode_index(arg: DrawArgIndex) -> str

Serialise a bracket-indexed reference to its repeated-bracket surface form: theta[i] for a single index, w[i][j] for several. This is the wire form the backends' index parser reads.

Source code in src/quivers/dsl/draw_args.py
def encode_index(arg: DrawArgIndex) -> str:
    """Serialise a bracket-indexed reference to its repeated-bracket
    surface form: ``theta[i]`` for a single index, ``w[i][j]`` for
    several. This is the wire form the backends' index parser reads.
    """
    return arg.name + "".join(f"[{index}]" for index in arg.indices)

is_atom

is_atom(arg: DrawArg) -> bool

True when arg is an atomic variant: a scalar, a bare name, or a bracket-indexed reference.

Source code in src/quivers/dsl/draw_args.py
def is_atom(arg: DrawArg) -> bool:
    """True when `arg` is an atomic variant: a scalar, a bare name,
    or a bracket-indexed reference."""
    return isinstance(arg, (DrawArgScalar, DrawArgName, DrawArgIndex))

atom_value

atom_value(arg: DrawArg) -> Atom

Return the flat wire value of an atomic DrawArg.

A DrawArgScalar yields its float, a DrawArgName its identifier text, and a DrawArgIndex its bracket-encoded surface string. Raises for compound variants (DrawArgList, DrawArgDist), which carry no single atomic value.

Source code in src/quivers/dsl/draw_args.py
def atom_value(arg: DrawArg) -> Atom:
    """Return the flat wire value of an atomic `DrawArg`.

    A `DrawArgScalar` yields its float, a `DrawArgName` its
    identifier text, and a `DrawArgIndex` its bracket-encoded
    surface string. Raises for compound variants (`DrawArgList`,
    `DrawArgDist`), which carry no single atomic value.
    """
    if isinstance(arg, DrawArgScalar):
        return arg.value
    if isinstance(arg, DrawArgName):
        return arg.text
    if isinstance(arg, DrawArgIndex):
        return encode_index(arg)
    raise TypeError(f"atom_value: not an atomic DrawArg: {type(arg).__name__}")

list_items

list_items(arg: DrawArgList) -> tuple[DrawArg, ...]

Return the recursive child DrawArgs of a list literal.

Use this when the children may themselves be compound (a matrix row, a nested distribution); use list_atoms when every child is known to be atomic.

Source code in src/quivers/dsl/draw_args.py
def list_items(arg: DrawArgList) -> tuple[DrawArg, ...]:
    """Return the recursive child `DrawArg`s of a list literal.

    Use this when the children may themselves be compound (a matrix
    row, a nested distribution); use `list_atoms` when every child
    is known to be atomic.
    """
    return arg.items

list_atoms

list_atoms(arg: DrawArgList) -> tuple[Atom, ...]

Return the atomic wire values of a vector-literal DrawArgList. Raises when any child is compound (guard matrix inputs with is_matrix).

Source code in src/quivers/dsl/draw_args.py
def list_atoms(arg: DrawArgList) -> tuple[Atom, ...]:
    """Return the atomic wire values of a vector-literal
    `DrawArgList`. Raises when any child is compound (guard matrix
    inputs with `is_matrix`)."""
    return tuple(atom_value(item) for item in arg.items)

is_matrix

is_matrix(arg: DrawArg) -> bool

True when arg is a matrix literal: a non-empty DrawArgList whose every item is itself a DrawArgList.

Source code in src/quivers/dsl/draw_args.py
def is_matrix(arg: DrawArg) -> bool:
    """True when `arg` is a matrix literal: a non-empty `DrawArgList`
    whose every item is itself a `DrawArgList`."""
    return (
        isinstance(arg, DrawArgList)
        and len(arg.items) > 0
        and all(isinstance(item, DrawArgList) for item in arg.items)
    )

matrix_rows

matrix_rows(arg: DrawArgList) -> tuple[tuple[Atom, ...], ...]

Return the row-major atom values of a matrix-literal DrawArgList (each item is a DrawArgList of atoms).

Callers should gate this with is_matrix.

Source code in src/quivers/dsl/draw_args.py
def matrix_rows(arg: DrawArgList) -> tuple[tuple[Atom, ...], ...]:
    """Return the row-major atom values of a matrix-literal
    `DrawArgList` (each item is a `DrawArgList` of atoms).

    Callers should gate this with `is_matrix`.
    """
    rows: list[tuple[Atom, ...]] = []
    for item in arg.items:
        if not isinstance(item, DrawArgList):
            raise TypeError(
                f"matrix_rows: row is not a DrawArgList: {type(item).__name__}"
            )
        rows.append(list_atoms(item))
    return tuple(rows)