Skip to content

Evaluator

The small-step reference evaluator.

evaluator

Small-step reference evaluator for the Quivers Indexed Effect Core.

The evaluator is deliberately an interpreter, not an optimized execution engine. It gives Return, Bind, Perform, and Handle one operational meaning against which lowerings and backend runtimes can be tested. Core terms remain serializable: host values and executable handler clauses live only in :class:RuntimeAttachments and are addressed by stable QIEC IDs.

Handlers are lexical and deep. A resumption reinstalls the matched handler and every inner continuation frame, whereas a handler clause is evaluated only in the outer context. This distinction is easiest to make explicit with the CEK machine below: handling an operation splits the continuation at its matching handler boundary.

RuntimeValidator

RuntimeValidator = Callable[[object], bool | None]

A predicate a host value must pass to inhabit a QIEC type.

It returns False to reject the value; True or None accepts it.

OperationClause

OperationClause = Callable[['RuntimeRequest', 'Resumption', 'ClauseContext'], object]

A host implementation of one handler operation clause.

It receives the request, the delimited continuation, and the clause's runtime services, and returns the clause's answer, a :class:Forward, or a :class:TailResume.

ReturnClause

ReturnClause = Callable[[object, 'ClauseContext'], object]

A host implementation of a handler's return clause.

It receives the handled computation's final value and the clause's runtime services, and returns the handler's answer.

ResponseHook

ResponseHook = Callable[[object], object]

A callback applied to the reply a forwarded request receives.

It returns the value the resumed computation receives in place of the reply.

EvaluationTraceHook

EvaluationTraceHook = Callable[[str, Mapping[str, object]], None]

A callback receiving each evaluator event's name and detail mapping.

EvaluationError

Bases: RuntimeError

Base class for failures at the typed-core/runtime boundary.

MissingAttachmentError

Bases: EvaluationError

A stable runtime reference has no value or handler attachment.

RuntimeTypeMismatch

Bases: EvaluationError

A host result failed the validator for its QIEC result type.

FuelExhaustedError

FuelExhaustedError(steps: int)

Bases: EvaluationError

The step budget ran out before the computation finished.

General recursion is allowed to diverge, so a budget is the only way a caller can bound a run. Exhaustion is reported as an ordinary evaluation failure rather than a host recursion error, which the machine's explicit stack never raises.

PARAMETER DESCRIPTION
steps

The budget that was exhausted; kept on the error as steps.

TYPE: int

Source code in src/quivers/qiec/evaluator.py
def __init__(self, steps: int) -> None:
    super().__init__(f"QIEC evaluation exceeded its budget of {steps} steps")
    self.steps = steps

UnknownComputationError

Bases: EvaluationError

A call names a computation the evaluator was not given a body for.

UnhandledEffectError

UnhandledEffectError(request: EffectRequest)

Bases: EvaluationError

No enclosing lexical handler accepts an effect request.

PARAMETER DESCRIPTION
request

The request nothing handled; kept on the error as request.

TYPE: EffectRequest

Source code in src/quivers/qiec/evaluator.py
def __init__(self, request: EffectRequest) -> None:
    super().__init__(
        "unhandled QIEC operation "
        f"{request.operation} on instance {request.instance}"
    )
    self.request = request

InvalidHandlerError

Bases: EvaluationError

A runtime handler contradicts its checked structural signature.

HandlerManifest dataclass

HandlerManifest(definitions: Mapping[HandlerId, HandlerDef])

Immutable checked handler definitions accepted by an evaluator.

Construct this from a :class:KernelRegistry after its declarations have passed kernel registration. Runtime clause objects are then accepted only when their complete structural definitions equal the manifest entry, not merely when their stable IDs collide.

PARAMETER DESCRIPTION
definitions

The checked handler definitions by identity.

TYPE: Mapping[HandlerId, HandlerDef]

__post_init__

__post_init__() -> None

Freeze the definitions behind a read-only view.

The manifest is what a runtime resolves a handler through, so it is copied and wrapped rather than aliased: a caller mutating the mapping it passed in would otherwise change which handler a running computation reaches.

Source code in src/quivers/qiec/evaluator.py
def __post_init__(self) -> None:
    """Freeze the definitions behind a read-only view.

    The manifest is what a runtime resolves a handler through, so it
    is copied and wrapped rather than aliased: a caller mutating the
    mapping it passed in would otherwise change which handler a
    running computation reaches.
    """
    object.__setattr__(
        self,
        "definitions",
        MappingProxyType(dict(self.definitions)),
    )

from_registry classmethod

from_registry(registry: KernelRegistry) -> HandlerManifest

Build a manifest from a checked registry.

PARAMETER DESCRIPTION
registry

A registry whose handlers have already been checked.

TYPE: KernelRegistry

RETURNS DESCRIPTION
HandlerManifest

A manifest over those handlers.

Source code in src/quivers/qiec/evaluator.py
@classmethod
def from_registry(cls, registry: KernelRegistry) -> HandlerManifest:
    """Build a manifest from a checked registry.

    Parameters
    ----------
    registry : KernelRegistry
        A registry whose handlers have already been checked.

    Returns
    -------
    HandlerManifest
        A manifest over those handlers.
    """
    return cls(registry.handlers)

ResumptionUsageError

Bases: EvaluationError

A handler clause used its resumption outside the declared grade.

NonDuplicableContinuationError

Bases: ResumptionUsageError

An unrestricted clause captured state that cannot safely be copied.

RuntimeConstructor dataclass

RuntimeConstructor(constructor: object, static_arguments: tuple[object, ...], fields: tuple[object, ...], result_type: TypeExpr)

Erased runtime representation of a checked constructor value.

PARAMETER DESCRIPTION
constructor

The constructor's stable identity.

TYPE: object

static_arguments

The constructor's telescope instantiation, as evaluated static data.

TYPE: tuple[object, ...]

fields

The evaluated field values, in declaration order.

TYPE: tuple[object, ...]

result_type

The family type the value inhabits.

TYPE: TypeExpr

AttachmentBinding dataclass

AttachmentBinding(value: object, type: TypeExpr, validator: RuntimeValidator, duplicable: bool = False)

One host value attached to an otherwise serializable core term.

duplicable is a semantic assertion about the host value, not merely a promise that copy.copy happens to work. Multi-shot resumptions reject captured attachment values unless this bit was supplied explicitly.

PARAMETER DESCRIPTION
value

The host value.

TYPE: object

type

The type the value inhabits.

TYPE: TypeExpr

validator

The predicate that checks a host value against type.

TYPE: RuntimeValidator

duplicable

Whether an unrestricted resumption may capture the value.

TYPE: bool DEFAULT: False

RuntimeClause dataclass

RuntimeClause(invoke: OperationClause, result_validator: RuntimeValidator)

Executable operation clause and validator for the resumed value.

PARAMETER DESCRIPTION
invoke

The clause body, called with the request, its resumption, and a clause context.

TYPE: OperationClause

result_validator

The predicate every value resumed through this clause must pass.

TYPE: RuntimeValidator

RuntimeHandler dataclass

RuntimeHandler(definition: HandlerDef, clauses: Mapping[OperationId, RuntimeClause], return_clause: ReturnClause = _identity_return, input_validator: RuntimeValidator = _accept, output_validator: RuntimeValidator = _accept, duplicable_context: bool = False, mutable_context: bool = False, fork_context: Callable[['RuntimeHandler'], 'RuntimeHandler'] | None = None, context_factory: Callable[[], 'RuntimeHandler'] | None = None, on_enter: Callable[[], None] | None = None, on_exit: Callable[[], None] | None = None, on_drop: Callable[[], None] | None = None)

Executable attachment for a structural :class:HandlerDef.

The checked definition contains coverage, grades, input/output types, and introduced effects. This attachment contains only process-local code and state. It is never serialized as QIEC.

PARAMETER DESCRIPTION
definition

The checked declaration this attachment implements.

TYPE: HandlerDef

clauses

One runtime clause per covered operation, by identity.

TYPE: Mapping[OperationId, RuntimeClause]

return_clause

How the handler answers the computation's return; the identity return by default.

TYPE: ReturnClause DEFAULT: _identity_return

input_validator

The predicate the handled computation's result must pass.

TYPE: RuntimeValidator DEFAULT: _accept

output_validator

The predicate the handler's answer must pass.

TYPE: RuntimeValidator DEFAULT: _accept

duplicable_context

Whether an unrestricted resumption may capture an installation of this handler.

TYPE: bool DEFAULT: False

mutable_context

Whether an installation carries state; such a handler needs a context_factory so installations do not share it.

TYPE: bool DEFAULT: False

fork_context

Builds an independent copy of an installation for another shot; required when the context is both mutable and duplicable.

TYPE: Callable[['RuntimeHandler'], 'RuntimeHandler'] | None DEFAULT: None

context_factory

Builds a fresh installation each time the handler is installed.

TYPE: Callable[[], 'RuntimeHandler'] | None DEFAULT: None

on_enter

Called when an installation is entered.

TYPE: Callable[[], None] | None DEFAULT: None

on_exit

Called once when the handled computation completes.

TYPE: Callable[[], None] | None DEFAULT: None

on_drop

Called once when the handled computation is abandoned instead; exclusive with on_exit.

TYPE: Callable[[], None] | None DEFAULT: None

__post_init__

__post_init__() -> None

Check the executable clauses against the checked declaration.

RAISES DESCRIPTION
InvalidHandlerError

If the runtime implements an operation the declaration does not cover, or leaves a declared one unimplemented. Both directions matter: an extra clause would never be dispatched to, and a missing one would fail only when that operation was first performed, perhaps long after the handler was installed.

Source code in src/quivers/qiec/evaluator.py
def __post_init__(self) -> None:
    """Check the executable clauses against the checked declaration.

    Raises
    ------
    InvalidHandlerError
        If the runtime implements an operation the declaration does
        not cover, or leaves a declared one unimplemented. Both
        directions matter: an extra clause would never be dispatched
        to, and a missing one would fail only when that operation was
        first performed, perhaps long after the handler was
        installed.
    """
    structural = {clause.operation for clause in self.definition.clauses}
    executable = set(self.clauses)
    unknown = executable - structural
    if unknown:
        rendered = ", ".join(str(operation) for operation in sorted(unknown))
        raise InvalidHandlerError(
            f"runtime handler {self.definition.name!r} implements undeclared "
            f"clauses: {rendered}"
        )
    missing = structural - executable
    if missing:
        rendered = ", ".join(str(operation) for operation in sorted(missing))
        raise InvalidHandlerError(
            f"runtime handler {self.definition.name!r} has no attachment for "
            f"declared clauses: {rendered}"
        )
    if self.fork_context is not None and not self.duplicable_context:
        raise InvalidHandlerError(
            "a handler with fork_context must declare a duplicable context"
        )
    if (
        self.mutable_context
        and self.duplicable_context
        and self.fork_context is None
    ):
        raise InvalidHandlerError("a mutable duplicable handler needs fork_context")

RuntimeAttachments dataclass

RuntimeAttachments(values: dict[AttachmentId, AttachmentBinding] = dict(), handlers: dict[HandlerId, RuntimeHandler] = dict())

Process-local values and handlers keyed by stable core identifiers.

PARAMETER DESCRIPTION
values

Attached host values by attachment identity.

TYPE: dict[AttachmentId, AttachmentBinding] DEFAULT: dict()

handlers

Runtime handlers by handler identity.

TYPE: dict[HandlerId, RuntimeHandler] DEFAULT: dict()

bind_value

bind_value(attachment: AttachmentId, value: object, type: TypeExpr, *, validator: RuntimeValidator = _accept, duplicable: bool = False) -> AttachmentRef

Attach a host value and return its stable core reference.

PARAMETER DESCRIPTION
attachment

The identity the core term refers to the value by.

TYPE: AttachmentId

value

The host value.

TYPE: object

type

The type the core ascribes to it.

TYPE: TypeExpr

validator

Checks the value really inhabits that type. The default accepts anything, for a value the static check already settles.

TYPE: RuntimeValidator DEFAULT: _accept

duplicable

Whether the value may be copied. This is an assertion about the value, not a guess: a multi-shot resumption capturing a non-duplicable attachment is refused, because copying it would give two continuations a shared mutable thing.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
AttachmentRef

The core reference to use in a term.

RAISES DESCRIPTION
InvalidHandlerError

If the identity is already bound to a different value, type, validator, or duplicability. Rebinding is refused rather than overwriting, since a term already built would silently start meaning something else.

RuntimeValidationError

If the validator rejects the value.

Source code in src/quivers/qiec/evaluator.py
def bind_value(
    self,
    attachment: AttachmentId,
    value: object,
    type: TypeExpr,
    *,
    validator: RuntimeValidator = _accept,
    duplicable: bool = False,
) -> AttachmentRef:
    """Attach a host value and return its stable core reference.

    Parameters
    ----------
    attachment : AttachmentId
        The identity the core term refers to the value by.
    value : object
        The host value.
    type : TypeExpr
        The type the core ascribes to it.
    validator : RuntimeValidator
        Checks the value really inhabits that type. The default
        accepts anything, for a value the static check already
        settles.
    duplicable : bool
        Whether the value may be copied. This is an assertion about
        the value, not a guess: a multi-shot resumption capturing a
        non-duplicable attachment is refused, because copying it
        would give two continuations a shared mutable thing.

    Returns
    -------
    AttachmentRef
        The core reference to use in a term.

    Raises
    ------
    InvalidHandlerError
        If the identity is already bound to a different value, type,
        validator, or duplicability. Rebinding is refused rather than
        overwriting, since a term already built would silently start
        meaning something else.
    RuntimeValidationError
        If the validator rejects the value.
    """
    _validate(value, validator, type, f"attachment {attachment}")
    binding = AttachmentBinding(value, type, validator, duplicable)
    previous = self.values.get(attachment)
    if previous is not None:
        same_binding = (
            previous.value is value
            and previous.type == type
            and previous.validator is validator
            and previous.duplicable == duplicable
        )
        if not same_binding:
            raise InvalidHandlerError(
                f"runtime attachment {attachment} is already bound differently"
            )
    self.values[attachment] = binding
    return AttachmentRef(attachment, type)

bind_handler

bind_handler(handler: RuntimeHandler) -> HandlerId

Attach executable clauses to their structural handler identity.

PARAMETER DESCRIPTION
handler

The executable handler, already checked against its declaration.

TYPE: RuntimeHandler

RETURNS DESCRIPTION
HandlerId

The identity it was bound under.

RAISES DESCRIPTION
InvalidHandlerError

If a different handler is already bound to that identity.

Source code in src/quivers/qiec/evaluator.py
def bind_handler(self, handler: RuntimeHandler) -> HandlerId:
    """Attach executable clauses to their structural handler identity.

    Parameters
    ----------
    handler : RuntimeHandler
        The executable handler, already checked against its
        declaration.

    Returns
    -------
    HandlerId
        The identity it was bound under.

    Raises
    ------
    InvalidHandlerError
        If a different handler is already bound to that identity.
    """
    id = handler.definition.id
    previous = self.handlers.get(id)
    if previous is not None and previous is not handler:
        raise InvalidHandlerError(f"runtime handler {id} is already bound")
    self.handlers[id] = handler
    return id

RuntimeRequest dataclass

RuntimeRequest(core: EffectRequest, arguments: tuple[object, ...], resumption_path: tuple[int, ...], dynamic_path: tuple[DynamicAddressFrame, ...] = ())

An evaluated request supplied to a process-local handler clause.

PARAMETER DESCRIPTION
core

The stable request as written, before evaluation.

TYPE: EffectRequest

arguments

The evaluated value arguments, in order.

TYPE: tuple[object, ...]

resumption_path

The ordinal of each resumption taken to reach this request.

TYPE: tuple[int, ...]

dynamic_path

The call and local-instance frames live when the request was performed, outermost first, so one site reached through two recursive iterations yields two addresses.

TYPE: tuple[DynamicAddressFrame, ...] DEFAULT: ()

instance property

instance: EffectInstanceId

The lexical instance this request was performed on.

RETURNS DESCRIPTION
EffectInstanceId

The instance, which decides which handler answers.

operation property

operation: OperationId

The operation requested.

RETURNS DESCRIPTION
OperationId

The operation, which decides which clause answers.

address property

address: tuple[str, tuple[tuple[str, str | int], ...], tuple[int, ...]]

Return the static, dynamic, and multi-shot address components.

RETURNS DESCRIPTION
tuple[str, tuple[tuple[str, str | int], ...], tuple[int, ...]]

The source site, the dynamic address frames, and the resumption path. One request site reached twice, under a loop or under a resumed continuation, yields two addresses, which is what lets a trace name each occurrence separately.

ClauseComputation dataclass

ClauseComputation(computation: Computation, bindings: tuple[tuple[Local, object], ...] = ())

Ask the evaluator to run a structural clause body outside the handler.

Host values introduced by a handler must first be installed through :meth:ClauseContext.attach; arbitrary callback closures do not enter the computation tree.

PARAMETER DESCRIPTION
computation

The stable computation to run.

TYPE: Computation

bindings

Locals the computation refers to, each with its evaluated value.

TYPE: tuple[tuple[Local, object], ...] DEFAULT: ()

Forward dataclass

Forward(on_response: ResponseHook | None = None)

Forward a request to an outer handler, optionally observing its reply.

PARAMETER DESCRIPTION
on_response

Called with the outer handler's answer before it reaches the resumed computation, or None to forward blindly.

TYPE: ResponseHook | None DEFAULT: None

TailResume dataclass

TailResume(value: object)

Resume a clause's continuation in place, on the machine's own stack.

A foreign clause that answers with this resumes once, exactly as an authored resume(value) in tail position does: the captured frames return to the machine's stack and the handler's return clause applies when the computation completes. Unlike calling the resumption from the clause, which drives the continuation in a nested host call that stays pending until it returns, this leaves no host frame behind, so a multi-shot resumption captured later inside the same handler may run the continuation any number of times.

PARAMETER DESCRIPTION
value

What the resumed operation supplies.

TYPE: object

ContinuationFrame

One frame of the reference evaluator's explicit continuation stack.

The evaluator creates and consumes every frame. A handler clause sees frames only through the :class:ClauseContext and :class:Resumption the evaluator hands it, and never inspects or builds one itself; the class exists so those two constructors can name the stack they capture.

ClauseContext

ClauseContext(evaluator: Evaluator, environment: Mapping[Local, object], outer_stack: tuple[ContinuationFrame, ...], resumption_path: tuple[int, ...], request: RuntimeRequest | None)

Disciplined runtime services available to an attached handler clause.

PARAMETER DESCRIPTION
evaluator

The evaluator running the clause.

TYPE: Evaluator

environment

The bindings in scope at the handler.

TYPE: Mapping[Local, object]

outer_stack

The continuation frames outside the handler.

TYPE: tuple[ContinuationFrame, ...]

resumption_path

The ordinal of each resumption taken to reach the clause.

TYPE: tuple[int, ...]

request

The request the clause answers, or None in a return clause.

TYPE: RuntimeRequest | None

Source code in src/quivers/qiec/evaluator.py
def __init__(
    self,
    evaluator: Evaluator,
    environment: Mapping[Local, object],
    outer_stack: tuple[ContinuationFrame, ...],
    resumption_path: tuple[int, ...],
    request: RuntimeRequest | None,
) -> None:
    self._evaluator = evaluator
    self._environment = environment
    self._outer_stack = _frames(outer_stack)
    self._resumption_path = resumption_path
    self._request = request

request property

request: RuntimeRequest | None

The request this clause is answering.

RETURNS DESCRIPTION
RuntimeRequest or None

The request, or None in a return clause, which answers a completed computation rather than an operation.

attachments property

attachments: RuntimeAttachments

The host values available to this clause.

RETURNS DESCRIPTION
RuntimeAttachments

The evaluator's attachment table.

evaluate

evaluate(computation: Computation) -> object

Evaluate a clause body in the outer handler context.

A delimiter prevents the clause body from consuming the continuation outside the handled expression. Effects performed here can reach only handlers outside the matched handler, which is the chosen deep-handler semantics.

PARAMETER DESCRIPTION
computation

The clause body to run.

TYPE: Computation

RETURNS DESCRIPTION
object

What the body produced.

Source code in src/quivers/qiec/evaluator.py
def evaluate(self, computation: Computation) -> object:
    """Evaluate a clause body in the outer handler context.

    A delimiter prevents the clause body from consuming the continuation
    outside the handled expression.  Effects performed here can reach only
    handlers outside the matched handler, which is the chosen deep-handler
    semantics.

    Parameters
    ----------
    computation : Computation
        The clause body to run.

    Returns
    -------
    object
        What the body produced.
    """
    delimiter = _DelimiterFrame()
    stack = [*self._outer_stack, delimiter]
    return self._evaluator._evaluate_delimited(
        computation,
        dict(self._environment),
        stack,
        self._outer_stack,
        self._resumption_path,
        delimiter,
    )

attach

attach(value: object, type: TypeExpr, *, role: str, validator: RuntimeValidator = _accept, duplicable: bool = False) -> AttachmentRef

Install a generated host value under a deterministic runtime ID.

PARAMETER DESCRIPTION
value

The host value to attach.

TYPE: object

type

The type the core ascribes to it.

TYPE: TypeExpr

role

What the value is for, which enters its derived identity.

TYPE: str

validator

Checks the value inhabits the type.

TYPE: RuntimeValidator DEFAULT: _accept

duplicable

Whether the value may be copied by a multi-shot resumption.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
AttachmentRef

A reference usable in a core term. The identity derives from the run, the request, and the role rather than being generated, so a trace can name the same attachment twice.

Source code in src/quivers/qiec/evaluator.py
def attach(
    self,
    value: object,
    type: TypeExpr,
    *,
    role: str,
    validator: RuntimeValidator = _accept,
    duplicable: bool = False,
) -> AttachmentRef:
    """Install a generated host value under a deterministic runtime ID.

    Parameters
    ----------
    value : object
        The host value to attach.
    type : TypeExpr
        The type the core ascribes to it.
    role : str
        What the value is for, which enters its derived identity.
    validator : RuntimeValidator
        Checks the value inhabits the type.
    duplicable : bool
        Whether the value may be copied by a multi-shot resumption.

    Returns
    -------
    AttachmentRef
        A reference usable in a core term. The identity derives from
        the run, the request, and the role rather than being
        generated, so a trace can name the same attachment twice.
    """
    if self._request is None:
        seed: tuple[object, ...] = (
            self._evaluator._run_serial,
            "return-clause",
            self._resumption_path,
            role,
        )
    else:
        seed = (
            self._evaluator._run_serial,
            self._request.address,
            str(self._request.operation),
            role,
        )
    id = AttachmentId.derive("runtime-generated", *seed)
    return self.attachments.bind_value(
        id,
        value,
        type,
        validator=validator,
        duplicable=duplicable,
    )

Resumption

Resumption(evaluator: Evaluator, request: RuntimeRequest, grade: ResumptionGrade, captured_environment: Mapping[Local, object], captured_stack: tuple[ContinuationFrame, ...], outer_stack: tuple[ContinuationFrame, ...], validator: RuntimeValidator, path: tuple[int, ...])

Dynamically checked, delimited continuation supplied to one clause.

PARAMETER DESCRIPTION
evaluator

The evaluator that captured the continuation.

TYPE: Evaluator

request

The request whose result the continuation awaits.

TYPE: RuntimeRequest

grade

How often the clause may invoke the continuation.

TYPE: ResumptionGrade

captured_environment

The bindings in scope at the request.

TYPE: Mapping[Local, object]

captured_stack

The continuation frames between the request and the handler.

TYPE: tuple[ContinuationFrame, ...]

outer_stack

The continuation frames outside the handler.

TYPE: tuple[ContinuationFrame, ...]

validator

The predicate every resumed value must pass.

TYPE: RuntimeValidator

path

The ordinal of each resumption taken to reach the clause.

TYPE: tuple[int, ...]

Source code in src/quivers/qiec/evaluator.py
def __init__(
    self,
    evaluator: Evaluator,
    request: RuntimeRequest,
    grade: ResumptionGrade,
    captured_environment: Mapping[Local, object],
    captured_stack: tuple[ContinuationFrame, ...],
    outer_stack: tuple[ContinuationFrame, ...],
    validator: RuntimeValidator,
    path: tuple[int, ...],
) -> None:
    self._evaluator = evaluator
    self._request = request
    self._grade = grade
    self._captured_environment = captured_environment
    self._captured_stack = _frames(captured_stack)
    self._outer_stack = _frames(outer_stack)
    self._validator = validator
    self._path = path
    self._calls = 0
    self._closed = False
    delimiters = tuple(
        index
        for index, frame in enumerate(self._captured_stack)
        if isinstance(frame, _DelimiterFrame)
    )
    self._owned_start = delimiters[-1] + 1 if delimiters else 0
    if grade is ResumptionGrade.UNRESTRICTED:
        evaluator._validate_duplicable_capture(
            captured_environment,
            self._captured_stack[self._owned_start :],
        )
        # Snapshot before the clause body runs. Every shot, including the
        # first, forks from this untouched seed rather than a previous
        # branch or the live handler context.
        self._seed_stack = self._fork_owned(self._captured_stack)
    else:
        self._seed_stack = self._captured_stack

grade property

The grade this resumption is held to.

RETURNS DESCRIPTION
ResumptionGrade

The declared grade, checked statically and again here.

calls property

calls: int

How many times this resumption has been invoked so far.

RETURNS DESCRIPTION
int

The count, which the grade bounds.

__call__

__call__(value: object) -> object

Resume the suspended computation with a value.

The static analysis already rejects a clause that can exceed its grade. This guard stays because it protects against a foreign handler, whose body the analysis never saw, and against a compiler bug: a grade is what lets a runtime discard a continuation, so exceeding it is not recoverable.

PARAMETER DESCRIPTION
value

What the resumed operation supplies.

TYPE: object

RETURNS DESCRIPTION
object

What the resumed computation produced.

RAISES DESCRIPTION
ResumptionUsageError

If the grade is zero, or an affine or linear resumption is invoked more than once.

NonDuplicableContinuationError

If an unrestricted resumption would have to copy a captured value that is not duplicable.

RuntimeValidationError

If the value does not inhabit the operation's result type.

Source code in src/quivers/qiec/evaluator.py
def __call__(self, value: object) -> object:
    """Resume the suspended computation with a value.

    The static analysis already rejects a clause that can exceed its
    grade. This guard stays because it protects against a foreign
    handler, whose body the analysis never saw, and against a
    compiler bug: a grade is what lets a runtime discard a
    continuation, so exceeding it is not recoverable.

    Parameters
    ----------
    value : object
        What the resumed operation supplies.

    Returns
    -------
    object
        What the resumed computation produced.

    Raises
    ------
    ResumptionUsageError
        If the grade is zero, or an affine or linear resumption is
        invoked more than once.
    NonDuplicableContinuationError
        If an unrestricted resumption would have to copy a captured
        value that is not duplicable.
    RuntimeValidationError
        If the value does not inhabit the operation's result type.
    """
    captured, path = self._begin_shot(value)
    # Outer handlers remain visible to effects performed by the resumed
    # continuation, but the delimiter prevents normal completion from
    # consuming the continuation outside the handled expression.
    delimiter = _DelimiterFrame()
    stack = [*self._outer_stack, delimiter, *captured]
    protected = (
        *self._outer_stack,
        *captured[: self._owned_start],
    )
    try:
        return self._evaluator._drive_value(
            value,
            dict(self._captured_environment),
            stack,
            path,
            delimiter,
        )
    except _HostUnwind as unwind:
        if unwind.delimiter is not delimiter:
            raise
        return unwind.value
    finally:
        # A normally returned shot has already exited every copied frame.
        # Exceptional or delimited exits leave some frames live.  Lifecycle
        # guards make this final sweep exact-once in either case.
        self._evaluator._drop_local_handlers(
            (*captured[self._owned_start :], *stack),
            protected,
        )

Evaluator

Evaluator(attachments: RuntimeAttachments | None = None, *, handler_manifest: HandlerManifest | None = None, trace_hook: EvaluationTraceHook | None = None, module: QiecModule | None = None, fuel: int | None = None, type_validator: Callable[[TypeExpr], RuntimeValidator | None] | None = None)

Execute QIEC computations with explicit runtime attachments.

PARAMETER DESCRIPTION
attachments

The host values and handlers available; empty by default.

TYPE: RuntimeAttachments | None DEFAULT: None

handler_manifest

Checked handler definitions every attached handler must match exactly on each :meth:evaluate, or None to skip that check there; :meth:evaluate_checked always derives a manifest from its registry.

TYPE: HandlerManifest | None DEFAULT: None

trace_hook

Called with each execution event's name and payload, or None for no tracing.

TYPE: EvaluationTraceHook | None DEFAULT: None

module

The module whose named computations calls resolve to and whose authored handlers handle may install without an attachment, or None when the computation calls nothing and installs only attached handlers.

TYPE: QiecModule | None DEFAULT: None

fuel

The number of machine steps a run may take before failing with :class:FuelExhaustedError, or None for no bound.

TYPE: int | None DEFAULT: None

type_validator

Supplies the host validator for a type at an authored handler's boundaries: the values it is resumed with, the handled computation's result, and its answer. None accepts every host value there, which is sound for values that only ever flowed through checked terms.

TYPE: Callable[[TypeExpr], RuntimeValidator | None] | None DEFAULT: None

Source code in src/quivers/qiec/evaluator.py
def __init__(
    self,
    attachments: RuntimeAttachments | None = None,
    *,
    handler_manifest: HandlerManifest | None = None,
    trace_hook: EvaluationTraceHook | None = None,
    module: QiecModule | None = None,
    fuel: int | None = None,
    type_validator: Callable[[TypeExpr], RuntimeValidator | None] | None = None,
) -> None:
    self.attachments = attachments or RuntimeAttachments()
    self.handler_manifest = handler_manifest
    self.trace_hook = trace_hook
    self.fuel = fuel
    self._type_validator = type_validator
    self._computations: dict[ComputationId, NamedComputation] = {}
    self._handler_definitions: dict[HandlerId, HandlerDef] = {}
    if module is not None:
        self._computations = {item.id: item for item in module.computations}
        self._handler_definitions = {item.id: item for item in module.handlers}
    self._run_serial = 0
    self._steps = 0
    self._call_serial = 0
    self._instance_serial = 0

evaluate

evaluate(computation: Computation, environment: Mapping[Local, object] | None = None) -> object

Evaluate a closed or explicitly supplied computation.

PARAMETER DESCRIPTION
computation

The computation to run.

TYPE: Computation

environment

Values for the computation's free locals. None means it is closed.

TYPE: Mapping[Local, object] or None DEFAULT: None

RETURNS DESCRIPTION
object

What the computation produced.

RAISES DESCRIPTION
EvaluationError

If a request reaches no handler, a handler is missing from the manifest, a resumption exceeds its grade, or a host value fails validation.

Source code in src/quivers/qiec/evaluator.py
def evaluate(
    self,
    computation: Computation,
    environment: Mapping[Local, object] | None = None,
) -> object:
    """Evaluate a closed or explicitly supplied computation.

    Parameters
    ----------
    computation : Computation
        The computation to run.
    environment : Mapping[Local, object] or None
        Values for the computation's free locals. None means it is
        closed.

    Returns
    -------
    object
        What the computation produced.

    Raises
    ------
    EvaluationError
        If a request reaches no handler, a handler is missing from
        the manifest, a resumption exceeds its grade, or a host value
        fails validation.
    """
    if self.handler_manifest is not None:
        self._validate_handler_manifest(self.handler_manifest)
    self._begin_run()
    stack: list[_Frame] = []
    try:
        return self._drive_computation(
            computation,
            dict(environment or {}),
            stack,
            (),
        )
    except _HostUnwind as unwind:
        self._drop_stack(tuple(stack))
        raise EvaluationError(
            "a value reached a host delimiter no resumption was waiting on"
        ) from unwind
    except BaseException:
        self._drop_stack(tuple(stack))
        raise

evaluate_checked

evaluate_checked(computation: Computation, registry: KernelRegistry, environment: Mapping[Local, object] | None = None) -> object

Kernel-check a computation and fail closed on handler attachments.

PARAMETER DESCRIPTION
computation

The computation to run.

TYPE: Computation

registry

Declarations to check it against.

TYPE: KernelRegistry

environment

Values for its free locals.

TYPE: Mapping[Local, object] or None DEFAULT: None

RETURNS DESCRIPTION
object

What the computation produced.

RAISES DESCRIPTION
KernelError

If the computation does not check.

EvaluationError

If execution fails, as in evaluate.

Source code in src/quivers/qiec/evaluator.py
def evaluate_checked(
    self,
    computation: Computation,
    registry: KernelRegistry,
    environment: Mapping[Local, object] | None = None,
) -> object:
    """Kernel-check a computation and fail closed on handler attachments.
    Parameters
    ----------
    computation : Computation
        The computation to run.
    registry : KernelRegistry
        Declarations to check it against.
    environment : Mapping[Local, object] or None
        Values for its free locals.

    Returns
    -------
    object
        What the computation produced.

    Raises
    ------
    KernelError
        If the computation does not check.
    EvaluationError
        If execution fails, as in `evaluate`.
    """
    runtime_environment = dict(environment or {})
    context = CheckContext()
    for local in runtime_environment:
        context = context.extend(local)
    infer_computation(
        computation,
        registry,
        context,
    )
    return self.evaluate_validated(computation, registry, runtime_environment)

evaluate_validated

evaluate_validated(computation: Computation, registry: KernelRegistry, environment: Mapping[Local, object] | None = None) -> object

Run a computation a module validation has already checked.

validate_module checks every body of a module against its registry; a caller holding that registry runs such a body without checking it again. The handler manifest is still held against the attachments.

PARAMETER DESCRIPTION
computation

The computation to run, a body of the validated module.

TYPE: Computation

registry

The registry the module validated against.

TYPE: KernelRegistry

environment

Values for its free locals.

TYPE: Mapping[Local, object] or None DEFAULT: None

RETURNS DESCRIPTION
object

What the computation produced.

RAISES DESCRIPTION
EvaluationError

If execution fails, as in evaluate.

Source code in src/quivers/qiec/evaluator.py
def evaluate_validated(
    self,
    computation: Computation,
    registry: KernelRegistry,
    environment: Mapping[Local, object] | None = None,
) -> object:
    """Run a computation a module validation has already checked.

    `validate_module` checks every body of a module against its
    registry; a caller holding that registry runs such a body
    without checking it again. The handler manifest is still held
    against the attachments.

    Parameters
    ----------
    computation : Computation
        The computation to run, a body of the validated module.
    registry : KernelRegistry
        The registry the module validated against.
    environment : Mapping[Local, object] or None
        Values for its free locals.

    Returns
    -------
    object
        What the computation produced.

    Raises
    ------
    EvaluationError
        If execution fails, as in `evaluate`.
    """
    runtime_environment = dict(environment or {})
    manifest = HandlerManifest.from_registry(registry)
    self._validate_handler_manifest(manifest)
    self._begin_run()
    stack: list[_Frame] = []
    try:
        return self._drive_computation(
            computation,
            runtime_environment,
            stack,
            (),
        )
    except BaseException:
        self._drop_stack(tuple(stack))
        raise

evaluate_value

evaluate_value(value: Value, environment: Mapping[Local, object] | None = None) -> object

Erase and evaluate a checked QIEC value.

PARAMETER DESCRIPTION
value

The value to evaluate.

TYPE: Value

environment

Values for its free locals.

TYPE: Mapping[Local, object] or None DEFAULT: None

RETURNS DESCRIPTION
object

The host representation of the value.

Source code in src/quivers/qiec/evaluator.py
def evaluate_value(
    self,
    value: Value,
    environment: Mapping[Local, object] | None = None,
) -> object:
    """Erase and evaluate a checked QIEC value.
    Parameters
    ----------
    value : Value
        The value to evaluate.
    environment : Mapping[Local, object] or None
        Values for its free locals.

    Returns
    -------
    object
        The host representation of the value.
    """
    return self._value(value, environment or {})