| /- Prograde (forward) reasoning tactics -/ |
| import Lean.Meta |
| import Lean.Elab.Tactic |
|
|
| namespace Pantograph.Tactic |
|
|
| open Lean |
|
|
| private def mkUpstreamMVar (goal: MVarId) : MetaM Expr := do |
| Meta.mkFreshExprSyntheticOpaqueMVar (β goal.getType) (tag := β goal.getTag) |
|
|
|
|
| / |
| def define (mvarId: MVarId) (binderName: Name) (expr: Expr): MetaM (FVarId Γ MVarId) := mvarId.withContext do |
| mvarId.checkNotAssigned `Pantograph.Tactic.define |
| let type β Meta.inferType expr |
|
|
| Meta.withLetDecl binderName type expr Ξ» fvar => do |
| let mvarUpstream β mkUpstreamMVar mvarId |
| mvarId.assign $ β Meta.mkLetFVars #[fvar] mvarUpstream |
| pure (fvar.fvarId!, mvarUpstream.mvarId!) |
|
|
| def evalDefine (binderName: Name) (expr: Syntax): Elab.Tactic.TacticM Unit := do |
| let goal β Elab.Tactic.getMainGoal |
| let expr β goal.withContext $ Elab.Term.elabTerm (stx := expr) (expectedType? := .none) |
| let (_, mvarId) β define goal binderName expr |
| Elab.Tactic.replaceMainGoal [mvarId] |
|
|
| structure BranchResult where |
| fvarId?: Option FVarId := .none |
| branch: MVarId |
| main: MVarId |
|
|
| def Β«haveΒ» (mvarId: MVarId) (binderName: Name) (type: Expr): MetaM BranchResult := mvarId.withContext do |
| mvarId.checkNotAssigned `Pantograph.Tactic.have |
| let lctx β MonadLCtx.getLCtx |
| |
| let mvarBranch β Meta.mkFreshExprMVarAt lctx (β Meta.getLocalInstances) type |
|
|
| |
| let fvarId β mkFreshFVarId |
| let lctxUpstream := lctx.mkLocalDecl fvarId binderName type |
| let mvarUpstream β |
| Meta.withLCtx lctxUpstream #[] do |
| Meta.withNewLocalInstances #[.fvar fvarId] 0 do |
| let mvarUpstream β mkUpstreamMVar mvarId |
| |
| mvarId.assign $ β Meta.mkLambdaFVars #[.fvar fvarId] mvarUpstream |
| pure mvarUpstream |
|
|
| return { |
| fvarId? := .some fvarId, |
| branch := mvarBranch.mvarId!, |
| main := mvarUpstream.mvarId!, |
| } |
|
|
| def evalHave (binderName: Name) (type: Syntax): Elab.Tactic.TacticM Unit := do |
| let goal β Elab.Tactic.getMainGoal |
| let nextGoals: List MVarId β goal.withContext do |
| let type β Elab.Term.elabType (stx := type) |
| let result β Β«haveΒ» goal binderName type |
| pure [result.branch, result.main] |
| Elab.Tactic.replaceMainGoal nextGoals |
|
|
| def Β«letΒ» (mvarId: MVarId) (binderName: Name) (type: Expr): MetaM BranchResult := mvarId.withContext do |
| mvarId.checkNotAssigned `Pantograph.Tactic.let |
| let lctx β MonadLCtx.getLCtx |
|
|
| |
| let mvarBranch β Meta.mkFreshExprMVarAt lctx (β Meta.getLocalInstances) type (userName := binderName) |
|
|
| assert! Β¬ type.hasLooseBVars |
| let mvarUpstream β Meta.withLetDecl binderName type mvarBranch $ Ξ» fvar => do |
| let mvarUpstream β mkUpstreamMVar mvarId |
| mvarId.assign $ β Meta.mkLetFVars #[fvar] mvarUpstream |
| pure mvarUpstream |
|
|
| return { |
| branch := mvarBranch.mvarId!, |
| main := mvarUpstream.mvarId!, |
| } |
|
|
| def evalLet (binderName: Name) (type: Syntax): Elab.Tactic.TacticM Unit := do |
| let goal β Elab.Tactic.getMainGoal |
| let type β goal.withContext $ Elab.Term.elabType (stx := type) |
| let result β Β«letΒ» goal binderName type |
| Elab.Tactic.replaceMainGoal [result.branch, result.main] |
|
|