Laurel User Guide

4.14. Expressions and Statements🔗

Laurel uses a unified StmtExpr type that contains both expression-like and statement-like constructs. This avoids duplication of shared concepts such as conditionals and variable declarations.

4.14.1. Operations🔗

🔗inductive type

Primitive operations available in Laurel expressions (each constructor is documented individually below).

Equality on composite types uses reference equality for impure types and structural equality for pure ones.

Strata.Laurel.Operation.Eq : Strata.Laurel.Operation

Equality test. Uses reference equality for impure composite types, structural equality for pure ones.

Strata.Laurel.Operation.And : Strata.Laurel.Operation

Logical conjunction (eager).

Strata.Laurel.Operation.Or : Strata.Laurel.Operation

Logical disjunction (eager).

Strata.Laurel.Operation.Implies : Strata.Laurel.Operation

Logical implication (short-circuit).

Strata.Laurel.Operation.AndThen : Strata.Laurel.Operation

Short-circuit logical conjunction. Only evaluates the second argument if the first is true.

Strata.Laurel.Operation.OrElse : Strata.Laurel.Operation

Short-circuit logical disjunction. Only evaluates the second argument if the first is false.

Strata.Laurel.Operation.Neg : Strata.Laurel.Operation

Arithmetic negation. Works on Int and Float64.

Strata.Laurel.Operation.Add : Strata.Laurel.Operation

Addition. Works on Int and Float64.

Strata.Laurel.Operation.Sub : Strata.Laurel.Operation

Subtraction. Works on Int and Float64.

Strata.Laurel.Operation.Mul : Strata.Laurel.Operation

Multiplication. Works on Int and Float64.

Strata.Laurel.Operation.Div : Strata.Laurel.Operation

Euclidean division. Works on Int and Float64.

Strata.Laurel.Operation.Mod : Strata.Laurel.Operation

Euclidean modulus. Works on Int and Float64.

Strata.Laurel.Operation.Lt : Strata.Laurel.Operation

Less than. Works on Int and Real.

Strata.Laurel.Operation.Leq : Strata.Laurel.Operation

Less than or equal. Works on Int and Real.

Strata.Laurel.Operation.Gt : Strata.Laurel.Operation

Greater than. Works on Int and Real.

Strata.Laurel.Operation.Geq : Strata.Laurel.Operation

Greater than or equal. Works on Int and Real.

4.14.2. The StmtExpr Type🔗

🔗inductive type

The unified statement-expression type for Laurel programs.

StmtExpr contains both statement-like constructs (conditionals, loops, assignments, returns) and expression-like constructs (literals, identifiers, operations, calls). Using a single type avoids duplication of shared concepts such as conditionals and variable declarations.

Strata.Laurel.StmtExpr.IfThenElse
  (cond thenBranch :
    Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (elseBranch :
    Option (Strata.Laurel.AstNode Strata.Laurel.StmtExpr)) :
  Strata.Laurel.StmtExpr

Conditional with a then-branch and optional else-branch.

Strata.Laurel.StmtExpr.Block
  (statements :
    List (Strata.Laurel.AstNode Strata.Laurel.StmtExpr))
  (label : Option String)
  (invariants :
    List (Strata.Laurel.AstNode Strata.Laurel.StmtExpr))
  (decreases :
    Option (Strata.Laurel.AstNode Strata.Laurel.StmtExpr)) :
  Strata.Laurel.StmtExpr

A sequence of statements with an optional label, the target of a Goto.

invariants and decreases matter when the block is the target of a backward Goto (destination = .blockStart), which makes the block a loop: the invariants are checked on entry and on every jump back to the start, and the measure must decrease from one jump back to the next. A block that no backward Goto targets checks its invariants once, on entry. RestructureGotos lowers these blocks to while loops.

Strata.Laurel.StmtExpr.While
  (cond : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (invariants :
    List (Strata.Laurel.AstNode Strata.Laurel.StmtExpr))
  (decreases :
    Option (Strata.Laurel.AstNode Strata.Laurel.StmtExpr))
  (body : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (postTest : Bool) : Strata.Laurel.StmtExpr

A while loop with a condition, invariants, optional termination measure, and body. Only allowed in impure contexts.

postTest selects when the condition is tested relative to the body:

  • false (default) — a pre-test loop (while): the condition is checked before the body, so the body may run zero times.

  • true — a post-test loop (do … while): the body runs once before the condition is first checked, so it always runs at least once.

Invariants are checked at the loop head (before each body) in both cases. A post-test loop is lowered to the pre-test form by the EliminateDoWhile pass.

Strata.Laurel.StmtExpr.Goto (target : String)
  (destination : Strata.Laurel.GotoDestination) :
  Strata.Laurel.StmtExpr

Jump to the start or past the end of an enclosing labelled block. Models break and continue statements, and the reducible control flow of a bytecode method.

Strata.Laurel.StmtExpr.Return
  (values :
    List (Strata.Laurel.AstNode Strata.Laurel.StmtExpr)) :
  Strata.Laurel.StmtExpr

Return from the enclosing procedure with one value per declared output; a bare return is []. The arity is checked by Check.return.

Strata.Laurel.StmtExpr.LiteralInt (value : Int) :
  Strata.Laurel.StmtExpr

An integer literal.

Strata.Laurel.StmtExpr.LiteralBool (value : Bool) :
  Strata.Laurel.StmtExpr

A boolean literal.

Strata.Laurel.StmtExpr.LiteralString (value : String) :
  Strata.Laurel.StmtExpr

A string literal.

Strata.Laurel.StmtExpr.LiteralDecimal
  (value : StrataDDM.Decimal) : Strata.Laurel.StmtExpr

A decimal literal.

Strata.Laurel.StmtExpr.LiteralBv (value width : Nat) :
  Strata.Laurel.StmtExpr

A bitvector literal with value and width.

Strata.Laurel.StmtExpr.Var (var : Strata.Laurel.Variable) :
  Strata.Laurel.StmtExpr

A variable reference or declaration. When var is Variable.Local, this is a reference that evaluates to the variable's value. When var is Variable.Declare, this is a declaration without an initializer (used as a standalone statement in a block).

Strata.Laurel.StmtExpr.Assign
  (targets :
    List (Strata.Laurel.AstNode Strata.Laurel.Variable))
  (value : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Assignment to one or more targets. Multiple targets are only supported with identifier targets and a call as the RHS.

Strata.Laurel.StmtExpr.IncrDecr
  (mode : Strata.Laurel.IncrDecrMode)
  (op : Strata.Laurel.IncrDecrOp)
  (target : Strata.Laurel.AstNode Strata.Laurel.Variable) :
  Strata.Laurel.StmtExpr

Java-style increment/decrement operator. The target must be a Local or Field Variable. As an expression, prefix form yields the new value (after the update) and postfix form yields the old value (before the update). As a statement the yielded value is discarded. Eliminated by the EliminateIncrDecrAndCompoundAssign pass before lifting imperative expressions.

Strata.Laurel.StmtExpr.CompoundAssign
  (op : Strata.Laurel.Operation)
  (target : Strata.Laurel.AstNode Strata.Laurel.Variable)
  (rhs : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

C-style compound assignment (x += e, x -= e, x *= e, x /= e, x %= e), plus x ^= e for string concatenation (Laurel uses ^ for concat, OCaml-style, not bitwise XOR). Lowers to target := target op rhs and yields the new value. The target must be a Local or Field Variable. Invariant: op is one of Add/Sub/Mul/Div/Mod/StrConcat — the only operators the concrete-to-abstract translator ever constructs here. Downstream sites may treat any other Operation as a StrataBug. Eliminated by the EliminateIncrDecrAndCompoundAssign pass before lifting imperative expressions.

Strata.Laurel.StmtExpr.PureFieldUpdate
  (target : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (fieldName : Strata.Laurel.Identifier)
  (newValue :
    Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Update a field on a pure (value) type, producing a new value.

Strata.Laurel.StmtExpr.Call
  (receiver? :
    Option (Strata.Laurel.AstNode Strata.Laurel.StmtExpr))
  (callee : Strata.Laurel.Identifier)
  (arguments :
    List (Strata.Laurel.AstNode Strata.Laurel.StmtExpr))
  (typeArgs :
    List (Strata.Laurel.AstNode Strata.Laurel.HighType)) :
  Strata.Laurel.StmtExpr

Call a procedure by name with the given arguments.

receiver? is none for a static call and some target for an instance call target#callee(args), whose callee is resolved in the target's composite type. LiftInstanceProcedures rewrites every instance call into a static one that passes the receiver as the first argument.

Primitive operators are calls too: x + y is a static call to the built-in wrapper $add. See Operation.procName.

typeArgs carries the call's INFERRED type arguments, in the callee's declaration order, for a generic callee — Resolution stamps them once it has determined every one (and reports the call when it cannot); a generic destructor carries its receiver's, in its datatype's order; an instance call carries those inferred for the method's own type parameters. Empty for a monomorphic callee, and empty on a freshly parsed tree: there is no surface syntax for type arguments at a call, so this is a resolution output, not something the user writes. Deliberately NOT defaulted: a defaulted field is matched against its default in a PATTERN, so .Call none f args would silently narrow to "no recorded instantiation" and any call carrying one would fall through a non-exhaustive match with no compile error. Recorded rather than re-derived because a downstream pass cannot recover it — computeExprType reports the callee's DECLARED return type, without the call-site substitution, so the instantiation of an external generic primitive (mapConst, setEmpty) would otherwise be lost between resolution and Core translation. Mirrors New's typeArgs in purpose.

Strata.Laurel.StmtExpr.New (ref : Strata.Laurel.Identifier)
  (typeArgs :
    List (Strata.Laurel.AstNode Strata.Laurel.HighType) :=
    []) :
  Strata.Laurel.StmtExpr

Create new object (new). typeArgs carries explicit instantiation arguments for a generic composite, e.g. new Box<int> → ref = Box, typeArgs = [int]. Empty for a non-generic new C (the common case and the pre-existing surface syntax), so the monomorphizer can read the concrete instantiation directly off the allocation site rather than recovering it from surrounding context.

Strata.Laurel.StmtExpr.This : Strata.Laurel.StmtExpr

Reference to the current object (this/self).

Strata.Laurel.StmtExpr.IsType
  (target : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (type : Strata.Laurel.AstNode Strata.Laurel.HighType) :
  Strata.Laurel.StmtExpr

Type test: check whether the target is an instance of the given type.

Strata.Laurel.StmtExpr.Quantifier
  (mode : Strata.Laurel.QuantifierMode)
  (param : Strata.Laurel.Parameter)
  (trigger :
    Option (Strata.Laurel.AstNode Strata.Laurel.StmtExpr))
  (body : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Quantification (universal or existential) over a typed parameter with an optional trigger.

Strata.Laurel.StmtExpr.Old
  (value : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (label? : Option Strata.Laurel.Identifier := none) :
  Strata.Laurel.StmtExpr

Refer to the value of value at an earlier program point.

label? names which earlier state:

  • none — the procedure's native pre-state (Core's two-state old). This is the only form on the regular path; surface old(e) produces it.

  • some h — a named earlier state h, so old reads that state rather than the procedure entry state. h is bound either by a Snapshot h earlier in the body or by a threaded Heap parameter.

Strata.Laurel.StmtExpr.OldGuarantee
  (value : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Coroutine-only: refer to the value of value at the start of the current coroutine step. Surface form: oldGuarantee(value).

Outside a coroutine body it is a resolution error. The lowering depends on the path:

  • Body path — the start-of-step heap is the previous yield's post-havoc snapshot (or procedure entry for the first yield), so it lowers to a labeled Old value (some $old_heap) reading the start-of-step Snapshot — the same lowering as an implicit old(...) inside a guarantees clause.

  • Caller path — the start-of-step heap is resume's native entry state (H2), so it lowers to a plain Old value (no label) that push-old distributes onto the inout $heap.

The user uses this in body asserts and loop invariants where the framework needs to relate the current heap to the previous yield's resume point.

Strata.Laurel.StmtExpr.OldRelies
  (value : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Coroutine-only: the old state of a two-state relies R(old, now) — the heap at the coroutine's most recent suspension (H1). Surface form: oldRelies(value). Unlike OldGuarantee (whose old heap is resume's native entry state), H1 is tracked by the caller per instance and threaded in as an explicit $h_rely_old : Heap parameter, so on the caller path oldRelies(e) lowers to Old e (some $h_rely_old) (no Core old, since relies become resume preconditions). Seeded to the current heap on the first resume, so R(H1, now) becomes R(H0, H0) there.

Strata.Laurel.StmtExpr.Fresh
  (value : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Check whether a reference is freshly allocated. May only target impure composite types.

Strata.Laurel.StmtExpr.Assert
  (condition : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (summary : Option String) : Strata.Laurel.StmtExpr

Assert a condition, generating a proof obligation. The optional summary is a human-readable description of the property being checked.

Strata.Laurel.StmtExpr.Assume
  (condition :
    Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Assume a condition, restricting the state space.

Strata.Laurel.StmtExpr.Throw
  (value : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Throw a value on the exceptional channel. The operand is unconstrained at the throw site; the thrown types are reconciled at each enclosing catch (typed at their least common ancestor) and against the procedure's declared throwsType. See the Exceptions section of the Laurel User Guide.

Strata.Laurel.StmtExpr.Try
  (body : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (catches : List Strata.Laurel.CatchClause)
  (finally? :
    Option (Strata.Laurel.AstNode Strata.Laurel.StmtExpr)) :
  Strata.Laurel.StmtExpr

Structured exception handler: a body, an ordered list of catch clauses (tried first-match-wins), and an optional finally arm that runs on every exit path. See the Exceptions section of the Laurel User Guide.

Strata.Laurel.StmtExpr.ProveBy
  (value proof :
    Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Attach a proof hint to a value. The semantics are those of value, but proof helps discharge assertions in value.

Strata.Laurel.StmtExpr.ContractOf
  (type : Strata.Laurel.ContractType)
  (function :
    Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Extract the contract (reads, modifies, precondition, or postcondition) of a function.

Strata.Laurel.StmtExpr.Abstract : Strata.Laurel.StmtExpr

Marker for abstract contracts. Makes the containing type abstract.

Strata.Laurel.StmtExpr.All : Strata.Laurel.StmtExpr

Refers to all objects in the heap. Used in reads or modifies clauses.

Strata.Laurel.StmtExpr.Hole (deterministic : Bool := true)
  (type :
    Option (Strata.Laurel.AstNode Strata.Laurel.HighType) :=
    none) :
  Strata.Laurel.StmtExpr

A hole represents an unknown expression. This can be used to represent programs that are still under development, for example the program 3 + The defining property of a hole is that interaction with it and other code should not produce any errors. Besides representing partial user programs, holes can also be used to handle under development parts of compilers that target Laurel.

  • deterministic: if true, the hole represents a deterministic unknown (translated as an uninterpreted function); if false, a nondeterministic unknown (translated as a havoced variable). Nondeterministic holes are not allowed in functions.

  • type: this property is used internally by Laurel and can be left to its default value. Internal usage: inferred by the hole type inference pass; none means not yet inferred.

Strata.Laurel.StmtExpr.Yield : Strata.Laurel.StmtExpr

Yield expression used inside coroutines.

Statement position: suspends the coroutine; the resumed value is dropped. Expression position (z := yield): suspends; evaluates to the value the next resume(co, v) sends in (type matches the coroutine's resumes binding).

To yield a value outward, the user assigns it to the coroutine's yields binding before the suspension: x := e; yield.

Strata.Laurel.StmtExpr.Resume
  (target : Strata.Laurel.AstNode Strata.Laurel.StmtExpr)
  (value :
    Option (Strata.Laurel.AstNode Strata.Laurel.StmtExpr)) :
  Strata.Laurel.StmtExpr

Resume a coroutine instance, optionally sending it a value. target evaluates to the coroutine instance to resume. value is the value sent into the coroutine (the binding for the yield expression that suspended it); none for a unit-valued resume. As a statement, the resumed value (the next yield's payload) is dropped; in expression position (x := resume(g, v)) it is bound to x.

Strata.Laurel.StmtExpr.HasNext
  (target : Strata.Laurel.AstNode Strata.Laurel.StmtExpr) :
  Strata.Laurel.StmtExpr

Has-next test on a coroutine instance: has_next(co) evaluates to true iff co has not yet run to completion (its internal $pc has not reached the END state).

Strata.Laurel.StmtExpr.Snapshot
  (label : Strata.Laurel.Identifier) :
  Strata.Laurel.StmtExpr

Lowering artifact (no surface syntax): capture the current state at this program point under the opaque label label, so a later Old e (some label) reads e against it.