(* Unlike unfold_Ssequence in veric/SeparationLogic.v, unfold_seq preserves Sfor and Swhile. In fact, it folds them even if they were not explicitly written in the input. Note that we don't treat Sdowhile, because there are no floyd tactics for it, and because it would result in 2198 cases when unfold_seq is printed. *)
Fixpoint unfold_seq c : list statement :=
match c with
| Sloop (Ssequence (Sifthenelse e Sskip Sbreak) s) Sskip =>
[Swhile e s]
| Ssequence s1 (Sloop (Ssequence (Sifthenelse e2 Sskip Sbreak) s3) s4) =>
(* TODO check if this matches cases we don't want it to match and if so, check that the loop iteration variable of s1 is the same as in the increment in s4, but then we'll exclude multi-statement for loop initialisations *)
[Sfor s1 e2 s3 s4]
| Ssequence c1 c2 => unfold_seq c1 ++ unfold_seq c2
| _ => [c]
end.
Fixpoint fold_seq lc : statement :=
match lc with
| nil => Sskip
| [c1] => c1
| c :: lc0 => Ssequence c (fold_seq lc0)
end.

Lemma flat_map_app: forall {A B: Type} (f: A -> list B) l1 l2,
flat_map f l1 ++ flat_map f l2 = flat_map f (l1 ++ l2).