Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
12e7e3e
add CFG to procedure body, no error handling, tests pass
PROgram52bc May 5, 2026
cbeee72
eliminate toStmts and use pattern matching/error handling
PROgram52bc May 5, 2026
723b1ae
add parser support for user-facing syntax with examples and tests
PROgram52bc May 6, 2026
602741c
Add TODO comments for two-stage GOTO pipeline refactor
PROgram52bc May 6, 2026
dbb6f91
add DetCFG abbrev, add obligation extraction and call extraction for …
PROgram52bc May 6, 2026
39123b0
refactor ObligationExtraction
PROgram52bc May 6, 2026
814530e
Address PR review: getCfg, CBMC error, CFG eval, grammar comment
PROgram52bc May 6, 2026
051f976
integrate semantics for Call statements which could invoke procedures…
PROgram52bc May 6, 2026
48a2a32
CST support for unstructured programs
PROgram52bc May 6, 2026
5d3aba6
add explicit comments on funcDecl extraction for unstructured program
PROgram52bc May 6, 2026
1b8a0e5
add ANF comment
PROgram52bc May 6, 2026
6c7a61a
alphaEquiv for CFG
PROgram52bc May 6, 2026
4ccddf4
no-op when inlining unstructured procedures
PROgram52bc May 6, 2026
b295843
add more support for CFG handling
PROgram52bc May 6, 2026
d184ea0
simplify StatementEval
PROgram52bc May 6, 2026
70cda23
indent
PROgram52bc May 6, 2026
10cb1eb
Address PR review: remove .stmts, refine Body interface, cleanup
PROgram52bc May 6, 2026
58695e5
Regenerate editor syntax files for new CFG keywords (goto, cfg)
PROgram52bc May 7, 2026
39acfc8
StatementEval returns error on nonexisting label
PROgram52bc May 7, 2026
15cfcf0
Refine unstructured procedure cases, add comments
PROgram52bc May 7, 2026
9d1de97
define variable infrastructures
PROgram52bc May 7, 2026
7e20805
refactor
PROgram52bc May 7, 2026
03c940e
Precond Elim for CFGs
PROgram52bc May 7, 2026
eba79e4
add error branch for renameAllLocalNames in ProcedureInlining
PROgram52bc May 7, 2026
c993332
intermediate proof fix
PROgram52bc May 7, 2026
e6d71f7
fix proof
PROgram52bc May 7, 2026
e5c4793
comment
PROgram52bc May 7, 2026
3bfd467
fix WFProcedure
PROgram52bc May 7, 2026
6d937fc
restore comments
PROgram52bc May 7, 2026
9eb49ab
run out of fuel warning
PROgram52bc May 7, 2026
402e43d
better comments on WF
PROgram52bc May 7, 2026
18b41d8
error on goto with 2+ targets
PROgram52bc May 7, 2026
d694805
refine type checker for CFG
PROgram52bc May 7, 2026
21a86aa
simplify
PROgram52bc May 7, 2026
09973f6
refine comments
PROgram52bc May 7, 2026
4305a67
fix: propagate error in runCFG fallthrough and clarify ObligationExtr…
PROgram52bc May 11, 2026
035fa8b
test: add end-to-end CFG verification and body preservation tests
PROgram52bc May 11, 2026
74a0977
fix: wrap Procedure.body assignment in TerminationCheck.lean for Body…
PROgram52bc May 11, 2026
8f0939d
fix: split postconditionsValid into structured/CFG fields and add Cor…
PROgram52bc May 12, 2026
8e944c7
refactor: enrich CoreBodyExec with terminal eval and unify postcondit…
PROgram52bc May 12, 2026
7e5884f
Merge branch 'main' into htd/unstructured-procedure
PROgram52bc May 12, 2026
cf067e8
implement type checking for CFG
PROgram52bc May 12, 2026
39afe3e
Implement symbolic executor for CFG
PROgram52bc May 12, 2026
c1299b8
abstract collectCmds
PROgram52bc May 12, 2026
b9334dc
add more documentation/better abstraction
PROgram52bc May 12, 2026
4d29cde
add metadata to unstructured programs
PROgram52bc May 8, 2026
6f2aca0
feat: preserve loop contracts in CFG transfer metadata
PROgram52bc May 12, 2026
6d2582c
fix: split transfer_goto grammar to enforce 1 or 2 targets at parse time
PROgram52bc May 12, 2026
11f11eb
fix: increment var_def counter when generating nondet goto fvar
PROgram52bc May 12, 2026
7f0d3b9
Fix binding bug in CFG Parser
PROgram52bc May 12, 2026
12b0295
fix comments
PROgram52bc May 12, 2026
b0640fd
refactor: use Procedure.Body.getStructured instead of raw match
PROgram52bc May 12, 2026
b9bb6bb
simplify CFG Eval
PROgram52bc May 13, 2026
63181c9
feat: add CFG-based Core-to-GOTO pipeline alongside direct path
PROgram52bc May 13, 2026
891d1c4
fix comments
PROgram52bc May 14, 2026
86e4600
Elimiate unnecessary constructor
PROgram52bc May 14, 2026
0fcdc25
Add PR template warning about repository split (#1166)
atomb May 14, 2026
4759712
Htd/unstructured procedure experiment (#1169)
PROgram52bc May 15, 2026
99b84e5
lake: build Strata lib as a test-driver dependency (#1138)
tautschnig May 15, 2026
8acaa4b
The small-step semantics of Imperative must have scoped var init, rem…
aqjune-aws May 15, 2026
a5d36ed
Support SMT string literals and common string ops in translateTerm (#…
tautschnig May 15, 2026
50b0e12
feat: introduce Provenance type and migrate metadata from FileRange (…
MikaelMayer May 15, 2026
e529f8b
Merge branch 'main' into htd/unstructured-procedure
PROgram52bc May 15, 2026
1d47569
Fix bug: ADT constructors do not change `Map` to `Array` when using u…
thanhnguyen-aws May 18, 2026
75e806e
Core.formatProgram to produce round-trip-parseable output for all con…
MikaelMayer May 18, 2026
0b4c836
Merge branch 'main' into htd/unstructured-procedure
PROgram52bc May 18, 2026
6b3c065
bump maxRecDepth
PROgram52bc May 18, 2026
7e0bfc7
Merge branch 'origin/main2' into htd/unstructured-procedure
PROgram52bc May 26, 2026
7455fc6
review: address PR #1196 feedback (atomb)
PROgram52bc May 29, 2026
049ffc5
lint: replace panic! in nondetTransferToCST with ToCSTM.logError fall…
PROgram52bc May 29, 2026
0a9c25b
Merge remote-tracking branch 'origin/main2' into htd/unstructured-pro…
PROgram52bc May 29, 2026
8734b66
test: adapt new tests from main2 to Procedure.Body sum type
PROgram52bc May 29, 2026
b44918a
grammar: split " else goto " into two adjacent literals to keep edito…
PROgram52bc May 29, 2026
fb40291
Merge branch 'main2' into htd/unstructured-procedure
atomb Jun 1, 2026
0f35daf
Merge branch 'main2' into htd/unstructured-procedure
PROgram52bc Jun 4, 2026
31f19bb
fix(merge): post-merge build/test fixups for PR1196 vs main2
PROgram52bc Jun 4, 2026
000a564
fix(test): refresh global_readonly_call expected obligation IDs
PROgram52bc Jun 4, 2026
496f47e
fix(eval): clear Env.deferred on false branch of CFG condGoto (#1317)
PROgram52bc Jun 4, 2026
7218d1d
refactor: drop default MetaData on remaining transfer constructors (f…
PROgram52bc Jun 5, 2026
02dfc08
Merge branch 'main2' into htd/unstructured-procedure
PROgram52bc Jun 5, 2026
9682784
fix(test): use umbrella Strata.DL.Lambda import
PROgram52bc Jun 5, 2026
a3825ca
fix(translator): emit conditional transfer with empty accum
PROgram52bc Jun 8, 2026
7750731
Merge remote-tracking branch 'origin/main2' into htd/unstructured-pro…
PROgram52bc Jun 8, 2026
cb658ca
fix(test): refresh Loops.lean #guard_msgs provenance byte ranges afte…
PROgram52bc Jun 8, 2026
d56b205
fix(test): refresh Exit.lean #guard_msgs provenance byte ranges
PROgram52bc Jun 8, 2026
8bb2739
wip(reconcile #1196): Procedure migrated
PROgram52bc Jun 12, 2026
b4b3af7
wip(reconcile #1196): ProcedureType + FormatCore migrated
PROgram52bc Jun 12, 2026
519804a
wip(reconcile #1196): Translate migrated
PROgram52bc Jun 12, 2026
62fb44d
wip(reconcile #1196): StatementSemantics migrated (keep CoreCFGStepSt…
PROgram52bc Jun 12, 2026
340305a
wip(reconcile #1196): StatementEval migrated (keep runCFG path)
PROgram52bc Jun 12, 2026
2f65146
wip(reconcile #1196): ProcedureEval + WF migrated
PROgram52bc Jun 12, 2026
49b1bbb
wip(reconcile #1196): ObligationExtraction migrated
PROgram52bc Jun 12, 2026
c94a553
wip(reconcile #1196): CoreToCProverGOTO migrated
PROgram52bc Jun 12, 2026
0c5a0b5
wip(reconcile #1196): Transform batch (ANFEncoder, CoreSpecification,…
PROgram52bc Jun 12, 2026
5806719
wip(reconcile #1196): ProcBodyVerifyCorrect migrated (adopt main2 blo…
PROgram52bc Jun 12, 2026
d5adf55
wip(reconcile #1196): test files (Exit golden + ProcedureInlining CFG…
PROgram52bc Jun 12, 2026
f991814
wip(reconcile #1196): CoreCFGToGOTOPipeline definedVars arity fix (ca…
PROgram52bc Jun 12, 2026
0360056
Merge remote-tracking branch 'origin/main2' into htd/sync-1196
PROgram52bc Jun 26, 2026
9c0a369
fix(test): migrate StructuredToUnstructuredTests fixture to new typec…
PROgram52bc Jun 26, 2026
fd06592
fix(test): update NondetChoice CFG golden for nondet-goto init lowering
PROgram52bc Jun 26, 2026
6754400
fix(StrataBoole): drop redundant command_cfg_procedure match arm
PROgram52bc Jun 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Strata/Backends/CBMC/GOTO.lean
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
-/
module

import Strata.Backends.CBMC.GOTO.CoreCFGToGOTOPipeline
import Strata.Backends.CBMC.GOTO.CoreToCProverGOTO
import Strata.Backends.CBMC.GOTO.CoreToGOTOPipeline
import Strata.Backends.CBMC.GOTO.DefaultSymbols
Expand Down
305 changes: 305 additions & 0 deletions Strata/Backends/CBMC/GOTO/CoreCFGToGOTOPipeline.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
/-
Copyright Strata Contributors

SPDX-License-Identifier: Apache-2.0 OR MIT
-/
module

public import Strata.Backends.CBMC.CollectSymbols
public import Strata.Backends.CBMC.GOTO.CoreToCProverGOTO
import Strata.Backends.CBMC.GOTO.CoreToGOTOPipeline
import Strata.Transform.StructuredToUnstructured
import Strata.Languages.Core.StatementSemantics

/-! ## Core-to-GOTO translation via CFG

Alternative pipeline that translates Core procedures to CProver GOTO by going
through the CFG representation:

- **Structured body** → `stmtsToCFG` → `coreCFGToGotoTransform`
- **CFG body** → `coreCFGToGotoTransform`

This coexists with the direct path in `CoreToGOTOPipeline.lean`.
-/

namespace Strata

public section

/-! ### Rename helpers for Core commands (CmdExt) -/

private def renameCoreCallArg
(rn : Std.HashMap String String)
: Core.CallArg Core.Expression → Core.CallArg Core.Expression
| .inArg e => .inArg (renameExpr rn e)
| .inoutArg id => .inoutArg (renameIdent rn id)
| .outArg id => .outArg (renameIdent rn id)

private def renameCoreCommand
(rn : Std.HashMap String String)
: Core.Command → Core.Command
| .cmd c => .cmd (renameCmd rn c)
| .call procName callArgs md =>
.call procName (callArgs.map (renameCoreCallArg rn)) md

private partial def renameCoreStmt
(rn : Std.HashMap String String)
: Core.Statement → Core.Statement
| .cmd c => .cmd (renameCoreCommand rn c)
| .block l stmts md =>
.block l (stmts.map (renameCoreStmt rn)) md
| .ite c t e md =>
.ite (c.map (renameExpr rn)) (t.map (renameCoreStmt rn)) (e.map (renameCoreStmt rn)) md
| .loop g m i body md =>
.loop (g.map (renameExpr rn)) (m.map (renameExpr rn))
(i.map (fun (l, e) => (l, renameExpr rn e)))
(body.map (renameCoreStmt rn)) md
| .exit l md => .exit l md
| .funcDecl d md => .funcDecl d md
| .typeDecl tc md => .typeDecl tc md

private def renameCoreDetCFG
(rn : Std.HashMap String String)
(cfg : Core.DetCFG) : Core.DetCFG :=
{ cfg with blocks := cfg.blocks.map fun (label, block) =>
(label, { cmds := block.cmds.map (renameCoreCommand rn),
transfer := match block.transfer with
| .condGoto cond lt lf md =>
.condGoto (renameExpr rn cond) lt lf md
| .finish md => .finish md }) }

/-! ### Core-specific CFG-to-GOTO translation -/

/--
Translate a Core `DetCFG` to CProver GOTO instructions.

Like `detCFGToGotoTransform` but handles `Core.Command` (which includes
`CmdExt.call`). The CFG should already have identifiers renamed via
`renameCoreDetCFG`.
-/
def coreCFGToGotoTransform
Comment thread
PROgram52bc marked this conversation as resolved.
(_Env : Core.Expression.TyEnv) (functionName : String)
(cfg : Core.DetCFG)
(trans : Imperative.GotoTransform Core.Expression.TyEnv)
: Except Std.Format (Imperative.GotoTransform Core.Expression.TyEnv) := do
let toExpr := Lambda.LExpr.toGotoExprCtx
(TBase := ⟨Core.ExpressionMetadata, Unit⟩) []
-- Verify entry block is first
match cfg.blocks with
| (firstLabel, _) :: _ =>
if firstLabel != cfg.entry then
throw f!"[coreCFGToGotoTransform] Entry label '{cfg.entry}' does not match \
first block label '{firstLabel}'."
| [] => pure ()
let mut trans := trans
let mut pendingPatches : Array (Nat × String) := #[]
let mut labelMap : Std.HashMap String Nat := {}
let mut loopContracts : Std.HashMap String (Imperative.MetaData Core.Expression) := {}
for (label, block) in cfg.blocks do
labelMap := labelMap.insert label trans.nextLoc
let srcLoc : CProverGOTO.SourceLocation :=
{ CProverGOTO.SourceLocation.nil with function := functionName }
trans := Imperative.emitLabel label srcLoc trans
-- Translate each command
for cmd in block.cmds do
match cmd with
| .cmd c =>
trans ← Imperative.Cmd.toGotoInstructions trans.T functionName c trans
| .call procName callArgs _md =>
let lhs := Core.CallArg.getLhs callArgs
let args := Core.CallArg.getInputExprs callArgs
let argExprs ← args.mapM toExpr
let lhsExpr := match lhs with
| id :: _ =>
let name := Core.CoreIdent.toPretty id
let ty := match trans.T.context.types.find? id with
| some lty =>
match lty.toMonoTypeUnsafe.toGotoType with
| .ok gty => gty
| .error _ =>
dbg_trace s!"warning: type conversion failed for {name}, defaulting to Integer"
.Integer
| none =>
dbg_trace s!"warning: no type found for {name}, defaulting to Integer"
.Integer
CProverGOTO.Expr.symbol name ty
| [] => CProverGOTO.Expr.symbol "" .Empty
let calleeExpr := CProverGOTO.Expr.symbol procName
(CProverGOTO.Ty.mkCode (argExprs.map (·.type)) lhsExpr.type)
let callCode := CProverGOTO.Code.functionCall lhsExpr calleeExpr argExprs
let inst : CProverGOTO.Instruction :=
{ type := .FUNCTION_CALL, code := callCode, locationNum := trans.nextLoc }
trans := { trans with
instructions := trans.instructions.push inst
nextLoc := trans.nextLoc + 1 }
-- Translate the transfer command
match block.transfer with
| .condGoto cond lt lf md =>
let transferSrcLoc := Imperative.metadataToSourceLoc md functionName trans.sourceText
let cond_expr ← toExpr cond
let hasLoopContract := md.any fun elem =>
elem.fld == Imperative.MetaData.specLoopInvariant ||
elem.fld == Imperative.MetaData.specDecreases
if hasLoopContract then
loopContracts := loopContracts.insert label md
let (trans', falseIdx) :=
Imperative.emitCondGoto (CProverGOTO.Expr.not cond_expr) transferSrcLoc trans
trans := trans'
pendingPatches := pendingPatches.push (falseIdx, lf)
let (trans', trueIdx) := Imperative.emitUncondGoto transferSrcLoc trans
trans := trans'
pendingPatches := pendingPatches.push (trueIdx, lt)
| .finish _md =>
pure ()
-- Second pass: resolve labels and annotate backward-edge GOTOs with loop contracts
let mut resolvedPatches : List (Nat × Nat) := []
for (idx, label) in pendingPatches do
match labelMap[label]? with
| some targetLoc =>
resolvedPatches := (idx, targetLoc) :: resolvedPatches
if let some md := loopContracts[label]? then
let instLoc := trans.instructions[idx]!.locationNum
if targetLoc ≤ instLoc then
let mut guard := trans.instructions[idx]!.guard
for elem in md do
if elem.fld == Imperative.MetaData.specLoopInvariant then
if let .expr e := elem.value then
let gotoExpr ← toExpr e
guard := guard.setNamedField "#spec_loop_invariant" gotoExpr
if elem.fld == Imperative.MetaData.specDecreases then
if let .expr e := elem.value then
let gotoExpr ← toExpr e
guard := guard.setNamedField "#spec_decreases" gotoExpr
trans := { trans with
instructions := trans.instructions.set! idx
{ trans.instructions[idx]! with guard := guard } }
| none =>
throw f!"[coreCFGToGotoTransform] Unresolved label '{label}' referenced \
by GOTO at instruction index {idx}."
return Imperative.patchGotoTargets trans resolvedPatches

/-! ### Pipeline wrapper -/

/--
Translate a Core procedure to CProver GOTO via the CFG representation.

Mirrors `procedureToGotoCtx` but routes through `stmtsToCFG` +
`coreCFGToGotoTransform` instead of the direct Stmt-to-GOTO path.
-/
def procedureToGotoCtxViaCFG
(Env : Core.Expression.TyEnv) (p : Core.Procedure)
(sourceText : Option String := none)
(axioms : List Core.Axiom := [])
(distincts :
List (Core.Expression.Ident × List Core.Expression.Expr) := [])
: Except Std.Format
(CoreToGOTO.CProverGOTO.Context × List Core.Function) := do
let pname := Core.CoreIdent.toPretty p.header.name
if !p.header.typeArgs.isEmpty then
.error f!"[procedureToGotoCtxViaCFG] Polymorphic procedures unsupported."
let ret_ty := CProverGOTO.Ty.Empty
let formals := p.header.inputs.keys.map Core.CoreIdent.toPretty
let formals_tys ← p.header.inputs.values.mapM Lambda.LMonoTy.toGotoType
let new_formals := formals.map (CProverGOTO.mkFormalSymbol pname ·)
let formals_tys : Map String CProverGOTO.Ty := formals.zip formals_tys
let outputs := p.header.outputs.keys.map Core.CoreIdent.toPretty
let new_outputs := outputs.map (CProverGOTO.mkLocalSymbol pname ·)
let locals_from_body := match p.body with
| .structured ss => (Imperative.Block.definedVars ss false).map Core.CoreIdent.toPretty
| .cfg c => c.blocks.flatMap (fun (_, blk) =>
blk.cmds.flatMap Core.Command.definedVars)
|>.map Core.CoreIdent.toPretty
let new_locals := locals_from_body.map (CProverGOTO.mkLocalSymbol pname ·)
let rn : Std.HashMap String String :=
(formals.zip new_formals ++ outputs.zip new_outputs ++ locals_from_body.zip new_locals).foldl
(init := {}) fun m (k, v) => m.insert k v
-- Seed the type environment with renamed input and output parameter types
let inputEntries : Map Core.Expression.Ident Core.Expression.Ty :=
(new_formals.zip p.header.inputs.values).map fun (n, ty) =>
(((n : Core.CoreIdent)), .forAll [] ty)
let outputEntries : Map Core.Expression.Ident Core.Expression.Ty :=
(new_outputs.zip p.header.outputs.values).map fun (n, ty) =>
(((n : Core.CoreIdent)), .forAll [] ty)
let Env' : Core.Expression.TyEnv :=
Lambda.TEnv.addInNewestContext (T := ⟨Core.ExpressionMetadata, Unit⟩)
Env (inputEntries ++ outputEntries)
-- Emit axioms as ASSUME instructions
let mut axiomInsts : Array CProverGOTO.Instruction := #[]
let mut axiomLoc : Nat := 0
for ax in axioms do
let gotoExpr ← Lambda.LExpr.toGotoExprCtx
(TBase := ⟨Core.ExpressionMetadata, Unit⟩) [] ax.e
if gotoExpr.hasUnsupportedQuantifierTypes then continue
axiomInsts := axiomInsts.push
{ type := .ASSUME, locationNum := axiomLoc,
guard := gotoExpr,
sourceLoc := { CProverGOTO.SourceLocation.nil with
function := pname, comment := s!"axiom {ax.name}" } }
axiomLoc := axiomLoc + 1
-- Emit distinct declarations as pairwise != ASSUME instructions
for (dname, exprs) in distincts do
let gotoExprs ← exprs.mapM
(Lambda.LExpr.toGotoExprCtx (TBase := ⟨Core.ExpressionMetadata, Unit⟩) [])
for i in List.range gotoExprs.length do
for j in List.range gotoExprs.length do
if i < j then
let ei := gotoExprs[i]!
let ej := gotoExprs[j]!
let neqExpr : CProverGOTO.Expr :=
{ id := .binary .NotEqual, type := .Boolean, operands := [ei, ej] }
let srcLoc : CProverGOTO.SourceLocation :=
{ CProverGOTO.SourceLocation.nil with
function := pname
comment := s!"distinct {Core.CoreIdent.toPretty dname}" }
axiomInsts := axiomInsts.push
{ type := .ASSUME, locationNum := axiomLoc, guard := neqExpr, sourceLoc := srcLoc }
axiomLoc := axiomLoc + 1
-- Build the CFG (from structured body or use existing CFG)
let (cfg, liftedFuncs) ← match p.body with
| .structured ss => do
let (liftedFuncs, body) ← collectFuncDecls ss
let renamedBody := body.map (renameCoreStmt rn)
let cfg := Imperative.stmtsToCFG renamedBody
pure (cfg, liftedFuncs)
| .cfg c => do
let cfg := renameCoreDetCFG rn c
pure (cfg, [])
-- Translate CFG to GOTO
let ans ← coreCFGToGotoTransform Env' pname cfg
{ instructions := axiomInsts, nextLoc := axiomLoc, T := Env', sourceText := sourceText }
let ending_insts : Array CProverGOTO.Instruction :=
#[{ type := .END_FUNCTION, locationNum := ans.nextLoc + 1 }]
let pgm := { name := pname,
parameterIdentifiers := new_formals.toArray,
instructions := ans.instructions ++ ending_insts }
-- Translate procedure contracts
let mut contracts : List (String × Lean.Json) := []
let preExprs := p.spec.preconditions.values.filter (fun c => c.attr == .Default)
|>.map (fun c => renameExpr rn c.expr)
let postExprs := p.spec.postconditions.values.filter (fun c => c.attr == .Default)
|>.map (fun c => renameExpr rn c.expr)
let toGotoExpr := Lambda.LExpr.toGotoExprCtx
(TBase := ⟨Core.ExpressionMetadata, Unit⟩) []
if !preExprs.isEmpty then
let preGoto ← preExprs.mapM toGotoExpr
let preJson ← (preGoto.mapM CProverGOTO.exprToJson).mapError (fun e => f!"{e}")
contracts := contracts ++ [("#spec_requires",
Lean.Json.mkObj [("id", ""), ("sub", Lean.Json.arr preJson.toArray)])]
if !postExprs.isEmpty then
let postGoto ← postExprs.mapM toGotoExpr
let postJson ← (postGoto.mapM CProverGOTO.exprToJson).mapError (fun e => f!"{e}")
contracts := contracts ++ [("#spec_ensures",
Lean.Json.mkObj [("id", ""), ("sub", Lean.Json.arr postJson.toArray)])]
-- Build localTypes map for output parameters
let output_tys ← p.header.outputs.values.mapM Lambda.LMonoTy.toGotoType
let localTypes : Std.HashMap String CProverGOTO.Ty :=
(outputs.zip output_tys).foldl (init := {}) fun m (k, v) => m.insert k v
let ctx : CoreToGOTO.CProverGOTO.Context :=
{ program := pgm, formals := formals_tys, ret := ret_ty,
locals := outputs ++ locals_from_body, contracts := contracts,
localTypes := localTypes }
return (ctx, liftedFuncs)

end -- public section

end Strata
30 changes: 25 additions & 5 deletions Strata/DL/Imperative/BasicBlock.lean
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,25 @@ where `n` is the total number of blocks in the graph.
where execution should proceed next, if anywhere. -/
inductive DetTransferCmd (Label : Type) (P : PureExpr) where
/-- Transfer to `lt` if `p` is true, or `lf` is `p` is false. -/
| condGoto (p : P.Expr) (lt lf : Label) (md : MetaData P := .empty)
| condGoto (p : P.Expr) (lt lf : Label) (md : MetaData P)
/-- Stop execution of the current unstructured program. If in a procedure
body, this can be interpreted as returning to the caller. -/
| finish (md : MetaData P := .empty)
| finish (md : MetaData P)

/-- For the moment, we don't have an unconditional jump in the language, and
model it instead using `condGoto`. By defining this function, we can easily
create unconditional jumps, and future proof against the possibility of adding
it as a constructor in the future. -/
def DetTransferCmd.goto [HasBool P] (l : Label) : DetTransferCmd Label P :=
condGoto HasBool.tt l l
def DetTransferCmd.goto [HasBool P] (l : Label) (md : MetaData P) : DetTransferCmd Label P :=
condGoto HasBool.tt l l md

/-- A `NondetTransfer` command terminates a non-deterministic basic block,
indicating the list of possible blocks where execution could proceed next, if
anywhere. -/
inductive NondetTransferCmd (Label : Type) (P : PureExpr) where
/-- Transfer to any one of a list of labels, non-deterministically. `goto`
with no labels is equivalent to `finish` in `DetTransferCmd` -/
| goto (ls : List Label) (md : MetaData P := .empty)
| goto (ls : List Label) (md : MetaData P)
deriving Inhabited

def NondetTransferCmd.targets : NondetTransferCmd Label P → List Label
Expand Down Expand Up @@ -79,6 +79,26 @@ structure CFG (Label Block : Type) where

--------

/-- Strip metadata from a deterministic transfer command. -/
def DetTransferCmd.stripMetaData : DetTransferCmd Label P → DetTransferCmd Label P
| .condGoto p lt lf _ => .condGoto p lt lf .empty
| .finish _ => .finish .empty

/-- Strip metadata from a non-deterministic transfer command. -/
def NondetTransferCmd.stripMetaData : NondetTransferCmd Label P → NondetTransferCmd Label P
| .goto ls _ => .goto ls .empty

/-- Strip transfer metadata from a deterministic basic block. -/
def DetBlock.stripMetaData (blk : DetBlock Label Cmd P) : DetBlock Label Cmd P :=
{ blk with transfer := blk.transfer.stripMetaData }

/-- Strip transfer metadata from all blocks in a deterministic CFG. -/
def CFG.stripDetMetaData (cfg : CFG Label (DetBlock Label Cmd P)) :
CFG Label (DetBlock Label Cmd P) :=
{ cfg with blocks := cfg.blocks.map fun (lbl, blk) => (lbl, blk.stripMetaData) }

--------

open Std (ToFormat Format format)

def formatDetTransferCmd (P : PureExpr) (c : DetTransferCmd Label P)
Expand Down
Loading
Loading