@@ -223,7 +223,7 @@ elab_rules : command
223223 $[require $req:term]*
224224 $[ensures $ens:term]* do $doSeq:doSeq
225225 ) => do
226- let (defCmd, obligation) ← Command.runTermElabM fun _vs => do
226+ let (defCmd, obligation, testingCtx ) ← Command.runTermElabM fun _vs => do
227227 let bindersIdents ← toBracketedBinderArrayLeafny binders
228228
229229 let modIds ← getModIds binders
@@ -251,6 +251,9 @@ elab_rules : command
251251 let pre <- req.andListWithName reqName
252252 let post <- ens.andListWithName ensName
253253
254+ let namelessPre <- req.andList
255+ let namelessPost <- ens.andList
256+
254257 let mut ret <- `(term| ())
255258 for modId in modIds do
256259 let modId := mkIdent <| modId.getId.appendAfter "New"
@@ -265,9 +268,13 @@ elab_rules : command
265268 pre := pre
266269 post := post
267270 }
268- return (defCmd, obligation)
271+ let newIds := modIds.map (fun x => Lean.mkIdent <| x.getId.appendAfter "New" )
272+ let modBinders ← newIds.zip mutTypes |>.mapM fun (newId, mutType) =>
273+ `(bracketedBinder| ($newId : $mutType))
274+ return (defCmd, obligation, { obligation with pre := namelessPre , post := namelessPost , modBinders , newIds })
269275 elabCommand defCmd
270276 velvetObligations.modify (·.insert name.getId obligation)
277+ velvetTestingContextMap.modify (·.insert name.getId testingCtx)
271278
272279notation "{" P "}" c "{" v "," Q "}" => triple P c (fun v => Q)
273280
@@ -302,3 +309,88 @@ elab_rules : command
302309
303310set_option linter.unusedVariables false in
304311def atomicAssertion {α : Type u} (n : Name) (a : α) := a
312+
313+ syntax "extract_program_for" ident : command
314+ syntax "prove_precondition_decidable_for" ident ("by" tacticSeq)? : command
315+ syntax "prove_postcondition_decidable_for" ident ("by" tacticSeq)? : command
316+ syntax "derive_tester_for" ident : command
317+
318+ def obtainVelvetTestingCtx (nameRaw : Ident) : CommandElabM (VelvetTestingCtx × Name) := do
319+ let ctxMap ← velvetTestingContextMap.get
320+ let name := nameRaw.getId
321+ unless ctxMap.contains name do
322+ throwError "{name} is not a Velvet program"
323+ return (ctxMap[name]!, name)
324+
325+ elab_rules : command
326+ | `(command| extract_program_for $nameRaw:ident ) => do
327+ -- assuming the thing is computable, then extract the program first
328+ let (ctx, name) ← obtainVelvetTestingCtx nameRaw
329+ let bindersIdents := ctx.binderIdents
330+ let ids := ctx.ids
331+ let execName := name.appendAfter "Exec"
332+ let execDefCmd ← `(command|
333+ def $(mkIdent execName) $bindersIdents* :=
334+ $(mkIdent ``NonDetT.extractWeak) ($nameRaw $ids*) (by extract_tactic))
335+ elabCommand execDefCmd
336+
337+ def elabDefiningDecidableInstancesForVelvetSpec (nameRaw : Ident)
338+ (pre? : Bool) (tac : Option (TSyntax `Lean.Parser.Tactic.tacticSeq)) : CommandElabM Unit := do
339+ let (ctx, name) ← obtainVelvetTestingCtx nameRaw
340+ let bindersIdents := ctx.binderIdents
341+ let (target, suffix, binders) :=
342+ if pre?
343+ then (ctx.pre, "PreDecidable" , bindersIdents)
344+ else (ctx.post, "PostDecidable" , bindersIdents ++ ctx.modBinders)
345+ let decidableInstName := name.appendAfter suffix
346+ -- let proof := tac.getD (← `(term| (by infer_instance) ))
347+ let tac := tac.getD (← `(Lean.Parser.Tactic.tacticSeq| skip ))
348+ let proof := (← `(Lean.Parser.Tactic.tacticSeq|
349+ repeat ' refine @instDecidableAnd _ _ ?_ ?_
350+ all_goals (try infer_instance)
351+ ($tac) ))
352+ let decidableInstDefCmd ← `(command|
353+ def $(mkIdent decidableInstName) $binders* :
354+ $(mkIdent ``Decidable) ($target) := by $proof)
355+ elabCommand decidableInstDefCmd
356+
357+ elab_rules : command
358+ | `(command| prove_precondition_decidable_for $nameRaw:ident ) => do
359+ elabDefiningDecidableInstancesForVelvetSpec nameRaw true none
360+ | `(command| prove_precondition_decidable_for $nameRaw:ident by $tac) => do
361+ elabDefiningDecidableInstancesForVelvetSpec nameRaw true (some tac)
362+ | `(command| prove_postcondition_decidable_for $nameRaw:ident ) => do
363+ elabDefiningDecidableInstancesForVelvetSpec nameRaw false none
364+ | `(command| prove_postcondition_decidable_for $nameRaw:ident by $tac) => do
365+ elabDefiningDecidableInstancesForVelvetSpec nameRaw false (some tac)
366+
367+ elab_rules : command
368+ | `(command| derive_tester_for $nameRaw:ident ) => do
369+ let (ctx, name) ← obtainVelvetTestingCtx nameRaw
370+ let execName ← do
371+ try resolveGlobalConstNoOverloadCore <| name.appendAfter "Exec"
372+ catch _ =>
373+ throwError "no executable found for {name}, please extract the program first"
374+ let ids := ctx.ids
375+ let retId := ctx.retId
376+ let ret := ctx.ret
377+ let bindersIdents := ctx.binderIdents
378+ let bundle (pre? : Bool) := if pre?
379+ then (ctx.pre, name.appendAfter "PreDecidable" , ids)
380+ else (ctx.post, name.appendAfter "PostDecidable" , ids ++ ctx.newIds)
381+ let decideTerm bundled : CommandElabM (TSyntax `term) := do
382+ let (target, instname, args) := bundled
383+ try
384+ let instname ← resolveGlobalConstNoOverloadCore instname
385+ `(term| (@$(mkIdent ``decide) _ ($(Syntax.mkApp (mkIdent instname) args))))
386+ catch _ =>
387+ `(term| ($(mkIdent ``decide) ($target)))
388+ let matcherTerm ← `(term|
389+ match ($(Syntax.mkApp (mkIdent execName) ids)) with
390+ | $(mkIdent ``DivM.res) ⟨$retId, $ret⟩ => $(← decideTerm <| bundle false )
391+ | _ => false )
392+ let ifTerm ← `(term| if $(← decideTerm <| bundle true ) then $matcherTerm else true )
393+ let testerName := name.appendAfter "Tester"
394+ let testerDefCmd ← `(command|
395+ def $(mkIdent testerName) $bindersIdents* : Bool := $ifTerm)
396+ elabCommand testerDefCmd
0 commit comments