The merged π_flat/π_reord: both are the same kind of operation β a single left-to-right
walk over a block's statements β so this file goes straight from ComputablePlusCal.Block to
List GuardedPlusCal.AtomicBranch, with no intermediate AST (no separate π_flat-output/
π_reord-input staging type). Runs after π_cflow/π_par (Computable2Guarded/CFlow.lean/
Par.lean), so no if/while survives anywhere in the tree (π_cflow already rewrote every
one into either/await), and every assign carries exactly one (Ref, Expr) pair (π_par
already reduced every parallel assignment) β both are runtime facts checked defensively
(GuardedError.internalInvariantViolated), not type-level ones, same precedent CFlow.lean
itself already uses for while-must-be-block-front.
walkBlock threads two accumulators in original encounter order β guards
(with/await/receive) and actions (everything else). Neither is reordered within itself;
only guards jump actions they were originally sequenced after, and a floated guard is rewritten
as it goes:
π_reord(r β e ; await e') = await e'[e\r] ; r β e
π_flat(B ; either{Bβ}orβ¦or{Bβ} ; B') = either{B;Bβ;B'}orβ¦or{B;Bβ;B'}
A guard is only ever appended to guards, so guards keep their relative order and one reading a
variable a preceding receive writes stays after it. A goto ends a branch, packaging
(guards, actions, label) into one AtomicBranch.
The entry point: walkBlock [] [] block for a top-level labelled AtomicBlock's own body.
One non-terminal statement s, given rest β everything else in s's own containing
block, continuing after it.
The block's own final statement β no rest exists beyond it (any dangling non-goto end
gets absorbed into a begin-position walkStep call instead, by Block.append's own
splicing, before ever reaching here β see the module doc).