Skip to content

Commit 945fff2

Browse files
authored
Procedure.Body sum type with parser, translator, and consumer threading (split of #1196) (#1342)
## Summary This PR introduces `Procedure.Body := .structured (List Statement) | .cfg DetCFG` — a sum type letting a Strata Core procedure carry either a structured statement-list body or a deterministic control-flow graph. It includes the type infrastructure, consumer threading across the verification pipeline, the DDM parser/translator support for the new `cfg` syntax, and CFG example programs. This PR is split out of [#1196](strata-org/Strata#1196) as a self-contained PR that can land independently on `main2`. It contributes ~714 LoC of additions vs `main2` (compared to ~5,567 LoC on [#1196](strata-org/Strata#1196)). It is **independent** of the companion split [#1341 (htd/unstructured-infra)](strata-org/Strata#1341) — the two PRs touch disjoint files (only `ProcBodyVerifyCorrect.lean` overlaps in different regions, mergeable cleanly). This PR does **not** introduce the imperative-DL infrastructure (metadata-bearing transfers, `EvalDetBlock` constructor renames, etc.) — those live in the companion [#1341 `htd/unstructured-infra`](strata-org/Strata#1341) PR. Without that, this PR's `CoreBodyExec` semantic relation has only the `.structured` constructor; the `.cfg` constructor is added when both branches merge. ## What's added The 44 files modified group into 5 layers: ### Type infrastructure (`Procedure.lean`, ~110 LoC) - `inductive Procedure.Body := .structured (List Statement) | .cfg DetCFG` plus `Inhabited` instance - `abbrev DetCFG := Imperative.CFG String (Imperative.DetBlock String Command Expression)` - 7 projection helpers: `getStructured`, `getCfg`, `getVars`, `isAbstract`, `isStructured`, `isCfg`, `structuredLength` - `HasVarsPure`/`HasVarsImp` instances on `Body` and `DetCFG` - `DetCFG.eraseTypes`, `DetCFG.stripMetaData` - `Procedure.body` field flips from `List Statement` to `Procedure.Body` (default `.structured []`) - `Procedure.eraseTypes`/`stripMetaData`/`getVars` retrofits ### WF predicate adaptation - `WF.lean`: `wfstmts`/`wfloclnd`/`bodyExitsCovered` rewritten as `∀ ss, body = .structured ss → ...` - `ProcBodyVerifyCorrect.lean`: new `procToVerifyStmt_is_structured` lemma bridging the sum type to the verification pipeline's `.structured` requirement ### Semantic relation - `StatementSemantics.lean`: `CoreBodyExec` with `.structured` constructor; `EvalCommand.call_sem` updated to use it - The `.cfg` constructor is left for [#1196](strata-org/Strata#1196) since it depends on `EvalDetBlock` from the companion infra PR ### Consumer threading (~150 LoC across 15 files) **Real CFG handling** (cannot be safely stubbed): - `CallGraph.lean`: traverses CFG arms to extract calls - `ProcedureInlining.lean`: handles `.structured` arm with the existing logic; throws on `.cfg` **`.cfg`-arm stubs** (error/passthrough/throw, replaceable when [#1196](strata-org/Strata#1196) merges): - `StatementEval.lean`, `ProcedureType.lean`, `ProcedureEval.lean`, `Verifier.lean`, `ObligationExtraction.lean`, `FormatCore.lean` - `Transform/PrecondElim.lean`, `CoreTransform.lean`, `LoopElim.lean`, `ANFEncoder.lean`, `TerminationCheck.lean`, `ProcBodyVerify.lean`, `CoreSpecification.lean` ### DDM parser support (`DDMTransform/Grammar.lean`, ~54 LoC) - New parser categories: `Transfer`, `CFGBlock`, `CFGBlocks`, `CFGBody` - `command_cfg_procedure` operator parsing `procedure name ... cfg ENTRY { ... }` syntax - Transfer commands: `transfer_goto`, `transfer_nondet_goto`, `transfer_cond_goto` (using `branch (cond) goto LT else goto LF` to avoid `if`-collision with structured syntax), `transfer_return` ### DDM translator (`DDMTransform/Translate.lean`, ~115 LoC) - `translateCFGBlock`, `translateCFGBlocks`, `translateCFGBody`, `translateTransfer` build `Procedure.Body.cfg` from parsed AST - `translateProcedure`/`translateBlockCommand` updated to route `.structured` vs `.cfg` body shapes ### Examples and tooling - `Examples/CFGSimple.core.st` — sample procedure (`Max(x,y)` computing maximum of two integers via CFG) - `Examples/CFGNondet.core.st` — sample with nondeterministic transfer - `docs/Architecture.md`, `docs/verso/IRTranslationPhilosophyDoc.lean` — documentation updates - `editors/emacs/core-st-mode.el`, `editors/vscode/syntaxes/core-st.tmLanguage.json` — keyword highlighting for `cfg`/`branch`/`goto`/`return` literals ## Comparison vs [#1196](strata-org/Strata#1196) | Feature | This PR | [#1196](strata-org/Strata#1196) | |---|:---:|:---:| | `Procedure.Body` sum type + `DetCFG` abbreviation + `body` field flip | ✅ | ✅ | | Body projection helpers (`getStructured`, `getVars`, etc.) | ✅ | ✅ | | `WF.lean` adaptation for sum-type body | ✅ | ✅ | | `procToVerifyStmt_is_structured` bridge lemma | ✅ | ✅ | | `CoreBodyExec` (`.structured` arm) | ✅ | ✅ | | `CoreBodyExec` (`.cfg` arm) | — (needs infra) | ✅ | | `CallGraph.lean` CFG traversal | ✅ | ✅ | | `ProcedureInlining.lean` sum-type handling | ✅ | ✅ | | `.cfg`-arm stubs in 13 consumers | ✅ | ✅ replaced by full impl | | Full `.cfg`-arm implementations (PrecondElim, ProcedureEval, etc.) | — | ✅ | | DDM `cfg ENTRY { ... }` parser syntax | ✅ | ✅ | | DDM `translateCFG*` translator | ✅ | ✅ | | CFG examples (`Examples/CFG{Simple,Nondet}.core.st`) | ✅ | ✅ | | Editor/docs syntax-highlighting updates | ✅ | ✅ | | Imperative DL: metadata-bearing transfers, `EvalDetBlock` rename | — (in companion PR) | ✅ | | Translator metadata propagation | — (in companion PR) | ✅ | | GOTO backend CFG pipeline | — | ✅ | | CFG-specific test suites | — | ✅ | | Lambda framework theorems | — | ✅ (via main2 merges) | ## Build status - `lake build`: green (490 jobs) - `lake test --exclude Languages.Python`: green (modulo the pre-existing CI-managed `ion-java-1.11.11.jar` test fixture) - 0 sorries, 0 axioms across all modified files ## Test plan - [x] `lake build` succeeds locally on a fresh worktree - [x] `lake test --exclude Languages.Python` succeeds (the only failure is the env-managed `ion-java` jar download which CI handles) - [x] No new sorries or axioms in any file - [x] Existing structured-procedure tests continue to pass (the `.body := .structured body` adapter at `Translate.lean:1683`/`1702` keeps existing parsing/verification paths working) - [ ] CI passes - [ ] Pairs with the companion [#1341 `htd/unstructured-infra`](strata-org/Strata#1341) PR — either can land first; see comparison table above - [ ] After this and the infra PR land, [#1196](strata-org/Strata#1196) can be rebased to ~2,000 LoC of remaining CFG-pipeline-specific content (CFG test suites, GOTO backend, full `.cfg`-arm implementations replacing stubs)
1 parent d65ea2c commit 945fff2

2 files changed

Lines changed: 19 additions & 15 deletions

File tree

StrataBoole/Verify.lean

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ private def translateProcedureDecl
950950
return [.proc {
951951
header := { name := mkIdent n, typeArgs := tys, inputs := allInputs, outputs := allOutputs }
952952
spec := spec
953-
body := body
953+
body := .structured body
954954
} .empty]
955955

956956
def toCoreDecls (cmd : BooleDDM.Command SourceRange) : TranslateM (List Core.Decl) := do
@@ -972,6 +972,8 @@ def toCoreDecls (cmd : BooleDDM.Command SourceRange) : TranslateM (List Core.Dec
972972
withTypeBVars tys do
973973
let inputs ← (bindingsToList ins).mapM toCoreBinding
974974
translateProcedureDecl m n tys inputs [] specAnn.val bodyAnn.val
975+
| .command_cfg_procedure m nameAnn _ _ _ _ =>
976+
throwAt m s!"Boole procedure '{nameAnn.val}': CFG-form procedure bodies (`cfg ENTRY \{ ... }`) are not supported in Boole; use a structured body."
975977
| .command_typedecl _ ⟨_, n⟩ ⟨_, args?⟩ =>
976978
let params := match args? with
977979
| none => []
@@ -1025,7 +1027,7 @@ def toCoreDecls (cmd : BooleDDM.Command SourceRange) : TranslateM (List Core.Dec
10251027
return [.proc {
10261028
header := { name := mkIdent topLevelBlockProcedureName, typeArgs := [], inputs := [], outputs := [] }
10271029
spec := { preconditions := [], postconditions := [] }
1028-
body := ← toCoreBlock b
1030+
body := .structured (← toCoreBlock b)
10291031
} .empty]
10301032
| .command_datatypes _ ⟨_, decls⟩ =>
10311033
return [.type (.data (← decls.toList.mapM toCoreDatatypeDecl)) .empty]

StrataBooleTest/global_readonly_call.lean

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ private def callHelper (p : StrataDDM.Program) : Except String (List String) :=
6666
return cp.decls.filterMap fun d =>
6767
match d with
6868
| .proc p _ =>
69-
p.body.findSome? fun
69+
-- CFG bodies: call extraction not yet implemented for unstructured programs.
70+
let stmts := match p.body with | .structured ss => ss | .cfg _ => []
71+
stmts.findSome? fun
7072
| .block _ stmts _ => stmts.findSome? fun
7173
| .cmd (.call pname args _) =>
7274
some s!"call {pname}({", ".intercalate (args.map fmtCallArg)})"
@@ -141,41 +143,41 @@ spec {
141143
142144
143145
VCs:
144-
Label: inc_ensures_1_2429
146+
Label: inc_ensures_1_2587
145147
Property: assert
146148
Assumptions:
147-
inc_requires_0_2411: z@1 > 0
149+
inc_requires_0_2569: z@1 > 0
148150
Obligation:
149151
true
150152
151-
Label: callElimAssert_inc_requires_0_2411_6
153+
Label: callElimAssert_inc_requires_0_2569_6
152154
Property: assert
153155
Assumptions:
154-
main_caller_requires_2_2545: z@3 == 10
155-
main_caller_requires_3_2565: g@3 == 0
156+
main_caller_requires_2_2703: z@3 == 10
157+
main_caller_requires_3_2723: g@3 == 0
156158
Obligation:
157159
z@3 > 0
158160
159-
Label: main_caller_ensures_4_2584
161+
Label: main_caller_ensures_4_2742
160162
Property: assert
161163
Assumptions:
162-
main_caller_requires_2_2545: z@3 == 10
163-
main_caller_requires_3_2565: g@3 == 0
164-
callElimAssume_inc_ensures_1_2429_7: g@5 == g@3 + 5 + z@5
164+
main_caller_requires_2_2703: z@3 == 10
165+
main_caller_requires_3_2723: g@3 == 0
166+
callElimAssume_inc_ensures_1_2587_7: g@5 == g@3 + 5 + z@5
165167
Obligation:
166168
g@5 == 15
167169
168170
---
169171
info:
170-
Obligation: inc_ensures_1_2429
172+
Obligation: inc_ensures_1_2587
171173
Property: assert
172174
Result: ✅ pass
173175
174-
Obligation: callElimAssert_inc_requires_0_2411_6
176+
Obligation: callElimAssert_inc_requires_0_2569_6
175177
Property: assert
176178
Result: ✅ pass
177179
178-
Obligation: main_caller_ensures_4_2584
180+
Obligation: main_caller_ensures_4_2742
179181
Property: assert
180182
Result: ❓ unknown
181183
Model:

0 commit comments

Comments
 (0)