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.
Constructors
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.