evaluation

syside.evaluation – evaluate asserted constraints against concrete instances.

This package checks whether the assert constraint { ... } constraints in a model actually hold for the instances that should satisfy them. It is built on syside.Compiler.evaluate(), which defines exactly the fragment of constraints that can be checked; anything outside that fragment is reported Verdict.UNDECIDABLE rather than silently passed.

The public surface is small:

Index

Classes

ConstraintResult

One (instance, assertion) pair and the verdict for it.

UnsupportedInstanceError

Raised for an instance whose value this module cannot yet evaluate soundly.

Functions

check_instance

Check every constraint that applies to a single concrete instance.

check_model

Check every constraint assertion against every concrete instance in model.

evaluate_assertion

Evaluate one assert constraint against scope and classify the result.

Enumerations

Verdict

The outcome of evaluating one asserted constraint against one instance.


Functions

check_instance(instance: syside.Usage, *, compiler: syside.Compiler | None = None) list[syside.evaluation.ConstraintResult]

Check every constraint that applies to a single concrete instance.

The evaluation scope is chosen so the instance’s bindings are native:

  • if instance is written new Def(...) (its feature value is a syside.ConstructorExpression), the constructor is evaluated to its constructed object and that object’s scope is used;

  • otherwise the instance’s own scope is used, where declarative bindings (redefinitions, feature values) already resolve.

Returns one ConstraintResult per applicable assertion. An instance with no applicable assertions yields an empty list. If a new Def(...) value cannot itself be evaluated, each of the definition’s assertions is reported Verdict.UNDECIDABLE rather than skipped.

Raises:

UnsupportedInstanceError – if instance both constructs a value and overrides it with declarative bindings in its body – a shape whose merged effective value this module cannot yet evaluate soundly (see UnsupportedInstanceError). Raising, rather than returning a verdict, prevents a silently wrong result.

Cost is linear in the instance’s feature count to find the applicable assertions, plus one syside.Compiler.evaluate() per assertion (and one more to evaluate the constructor, if any); the evaluate calls dominate.

check_model(model: syside.Model, *, compiler: syside.Compiler | None = None) list[syside.evaluation.ConstraintResult]

Check every constraint assertion against every concrete instance in model.

Iterates the model’s non-library usages and, for each, evaluates the assertions that apply to it via check_instance(). Usages that carry no applicable assertion contribute nothing. The result is flat, in model-traversal order; callers typically filter for Verdict.VIOLATED to report problems and Verdict.UNDECIDABLE to report what could not be checked.

Unlike check_instance(), this never raises UnsupportedInstanceError: an instance with an unsupported shape is recorded as Verdict.UNSUPPORTED (one result per applicable assertion) so a single such instance does not abort the scan or discard the verdicts already collected.

Note

This scans all usages, so cost is linear in model size times the per- instance evaluation cost. It is intended for whole-file checking (e.g. an on-save lint), not for hot loops.

evaluate_assertion(assertion: syside.AssertConstraintUsage, scope: syside.Type, *, compiler: syside.Compiler, instance: syside.Usage | None = None) syside.evaluation.ConstraintResult

Evaluate one assert constraint against scope and classify the result.

scope must be a type in which the constraint’s feature references resolve to concrete values – typically a constructed object (see check_instance()) or an instance carrying declarative bindings.

instance is the usage recorded on the result as the subject being checked. It is distinct from scope because the scope of a new Def(...) instance is the ephemeral constructed object, not the usage the modeller wrote; pass the original usage so the result points back at the source. When omitted it defaults to scope (correct for the declarative path, where the instance is its own scope).

The result is three-valued. A body the compiler cannot reduce, or one that reduces to anything other than a single bool (for example a collection, a number, or None), is Verdict.UNDECIDABLE – never reported as holding. assert not negation is applied to a concrete boolean only.

Cost is one syside.Compiler.evaluate() call, which dominates; the surrounding classification is O(1).

Enumerations

class Verdict

The outcome of evaluating one asserted constraint against one instance.

The outcome of evaluating one asserted constraint against one instance.

The outcome of evaluating one asserted constraint against one instance.

The outcome of evaluating one asserted constraint against one instance.

The outcome of evaluating one asserted constraint against one instance.