refactor(goal): Use site in goal state functions
This commit is contained in:
parent
0b731273b2
commit
42bb20df4a
|
@ -15,9 +15,15 @@ inductive Site where
|
||||||
| focus (goal : MVarId)
|
| focus (goal : MVarId)
|
||||||
| prefer (goal : MVarId)
|
| prefer (goal : MVarId)
|
||||||
| unfocus
|
| unfocus
|
||||||
|
deriving BEq, Inhabited
|
||||||
|
|
||||||
instance : Coe MVarId Site where
|
instance : Coe MVarId Site where
|
||||||
coe := .focus
|
coe := .focus
|
||||||
|
instance : ToString Site where
|
||||||
|
toString
|
||||||
|
| .focus { name } => s!"[{name}]"
|
||||||
|
| .prefer { name } => s!"[{name},...]"
|
||||||
|
| .unfocus => "[*]"
|
||||||
|
|
||||||
/-- Executes a `TacticM` on a site and return affected goals -/
|
/-- Executes a `TacticM` on a site and return affected goals -/
|
||||||
protected def Site.runTacticM (site : Site)
|
protected def Site.runTacticM (site : Site)
|
||||||
|
@ -29,15 +35,19 @@ protected def Site.runTacticM (site : Site)
|
||||||
let a ← f
|
let a ← f
|
||||||
return (a, [goal])
|
return (a, [goal])
|
||||||
| .prefer goal => do
|
| .prefer goal => do
|
||||||
let prev ← Elab.Tactic.getUnsolvedGoals
|
let before ← Elab.Tactic.getUnsolvedGoals
|
||||||
let otherGoals := prev.filter (· != goal)
|
let otherGoals := before.filter (· != goal)
|
||||||
Elab.Tactic.setGoals (goal :: otherGoals)
|
Elab.Tactic.setGoals (goal :: otherGoals)
|
||||||
let a ← f
|
let a ← f
|
||||||
return (a, ← prev.filterM (·.isAssignedOrDelayedAssigned))
|
let after ← Elab.Tactic.getUnsolvedGoals
|
||||||
|
let parents := before.filter (¬ after.contains ·)
|
||||||
|
return (a, parents)
|
||||||
| .unfocus => do
|
| .unfocus => do
|
||||||
let prev ← Elab.Tactic.getUnsolvedGoals
|
let before ← Elab.Tactic.getUnsolvedGoals
|
||||||
let a ← f
|
let a ← f
|
||||||
return (a, ← prev.filterM (·.isAssignedOrDelayedAssigned))
|
let after ← Elab.Tactic.getUnsolvedGoals
|
||||||
|
let parents := before.filter (¬ after.contains ·)
|
||||||
|
return (a, parents)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Kernel view of the state of a proof
|
Kernel view of the state of a proof
|
||||||
|
@ -56,6 +66,8 @@ structure GoalState where
|
||||||
-- finished executing.
|
-- finished executing.
|
||||||
fragments : FragmentMap := .empty
|
fragments : FragmentMap := .empty
|
||||||
|
|
||||||
|
def throwNoGoals { m α } [Monad m] [MonadError m] : m α := throwError "no goals to be solved"
|
||||||
|
|
||||||
@[export pantograph_goal_state_create_m]
|
@[export pantograph_goal_state_create_m]
|
||||||
protected def GoalState.create (expr: Expr): Elab.TermElabM GoalState := do
|
protected def GoalState.create (expr: Expr): Elab.TermElabM GoalState := do
|
||||||
-- May be necessary to immediately synthesise all metavariables if we need to leave the elaboration context.
|
-- May be necessary to immediately synthesise all metavariables if we need to leave the elaboration context.
|
||||||
|
@ -78,8 +90,18 @@ protected def GoalState.createFromMVars (goals: List MVarId) (root: MVarId): Met
|
||||||
root,
|
root,
|
||||||
savedState,
|
savedState,
|
||||||
}
|
}
|
||||||
|
@[always_inline]
|
||||||
protected def GoalState.goals (state: GoalState): List MVarId :=
|
protected def GoalState.goals (state: GoalState): List MVarId :=
|
||||||
state.savedState.tactic.goals
|
state.savedState.tactic.goals
|
||||||
|
@[always_inline]
|
||||||
|
protected def GoalState.mainGoal? (state : GoalState) : Option MVarId :=
|
||||||
|
state.goals.head?
|
||||||
|
@[always_inline]
|
||||||
|
protected def GoalState.actingGoal? (state : GoalState) (site : Site) : Option MVarId := do
|
||||||
|
match site with
|
||||||
|
| .focus goal | .prefer goal => return goal
|
||||||
|
| .unfocus => state.mainGoal?
|
||||||
|
|
||||||
@[export pantograph_goal_state_goals]
|
@[export pantograph_goal_state_goals]
|
||||||
protected def GoalState.goalsArray (state: GoalState): Array MVarId := state.goals.toArray
|
protected def GoalState.goalsArray (state: GoalState): Array MVarId := state.goals.toArray
|
||||||
protected def GoalState.mctx (state: GoalState): MetavarContext :=
|
protected def GoalState.mctx (state: GoalState): MetavarContext :=
|
||||||
|
@ -91,8 +113,10 @@ protected def GoalState.env (state: GoalState): Environment :=
|
||||||
protected def GoalState.metaContextOfGoal (state: GoalState) (mvarId: MVarId): Option Meta.Context := do
|
protected def GoalState.metaContextOfGoal (state: GoalState) (mvarId: MVarId): Option Meta.Context := do
|
||||||
let mvarDecl ← state.mctx.findDecl? mvarId
|
let mvarDecl ← state.mctx.findDecl? mvarId
|
||||||
return { lctx := mvarDecl.lctx, localInstances := mvarDecl.localInstances }
|
return { lctx := mvarDecl.lctx, localInstances := mvarDecl.localInstances }
|
||||||
|
@[always_inline]
|
||||||
protected def GoalState.metaState (state: GoalState): Meta.State :=
|
protected def GoalState.metaState (state: GoalState): Meta.State :=
|
||||||
state.savedState.term.meta.meta
|
state.savedState.term.meta.meta
|
||||||
|
@[always_inline]
|
||||||
protected def GoalState.coreState (state: GoalState): Core.SavedState :=
|
protected def GoalState.coreState (state: GoalState): Core.SavedState :=
|
||||||
state.savedState.term.meta.core
|
state.savedState.term.meta.core
|
||||||
|
|
||||||
|
@ -192,8 +216,10 @@ protected def GoalState.getMVarEAssignment (goalState: GoalState) (mvarId: MVarI
|
||||||
@[export pantograph_goal_state_parent_exprs]
|
@[export pantograph_goal_state_parent_exprs]
|
||||||
protected def GoalState.parentExprs (state : GoalState) : List Expr :=
|
protected def GoalState.parentExprs (state : GoalState) : List Expr :=
|
||||||
state.parentMVars.map λ goal => state.getMVarEAssignment goal |>.get!
|
state.parentMVars.map λ goal => state.getMVarEAssignment goal |>.get!
|
||||||
|
@[always_inline]
|
||||||
protected def GoalState.hasUniqueParent (state : GoalState) : Bool :=
|
protected def GoalState.hasUniqueParent (state : GoalState) : Bool :=
|
||||||
state.parentMVars.length == 1
|
state.parentMVars.length == 1
|
||||||
|
@[always_inline]
|
||||||
protected def GoalState.parentExpr! (state : GoalState) : Expr :=
|
protected def GoalState.parentExpr! (state : GoalState) : Expr :=
|
||||||
assert! state.parentMVars.length == 1
|
assert! state.parentMVars.length == 1
|
||||||
(state.getMVarEAssignment state.parentMVars[0]!).get!
|
(state.getMVarEAssignment state.parentMVars[0]!).get!
|
||||||
|
@ -208,7 +234,8 @@ if conflicting assignments exist. We also assume the monotonicity property: In a
|
||||||
chain of descending goal states, a mvar cannot be unassigned, and once assigned
|
chain of descending goal states, a mvar cannot be unassigned, and once assigned
|
||||||
its assignment cannot change. -/
|
its assignment cannot change. -/
|
||||||
@[export pantograph_goal_state_replay_m]
|
@[export pantograph_goal_state_replay_m]
|
||||||
protected def GoalState.replay (dst : GoalState) (src src' : GoalState) : CoreM GoalState := do
|
protected def GoalState.replay (dst : GoalState) (src src' : GoalState) : CoreM GoalState :=
|
||||||
|
withTraceNode `Pantograph.GoalState.replay (fun _ => return m!"replay") do
|
||||||
let srcNGen := src.coreState.ngen
|
let srcNGen := src.coreState.ngen
|
||||||
let srcNGen' := src'.coreState.ngen
|
let srcNGen' := src'.coreState.ngen
|
||||||
let dstNGen := dst.coreState.ngen
|
let dstNGen := dst.coreState.ngen
|
||||||
|
@ -407,6 +434,7 @@ private def collectAllErroredMVars (src : MVarId) : Elab.TermElabM (List MVarId)
|
||||||
result := mvarDeps.foldl (·.insert ·) result
|
result := mvarDeps.foldl (·.insert ·) result
|
||||||
return result.toList
|
return result.toList
|
||||||
|
|
||||||
|
/-- Merger of two unique lists -/
|
||||||
private def mergeMVarLists (li1 li2 : List MVarId) : List MVarId :=
|
private def mergeMVarLists (li1 li2 : List MVarId) : List MVarId :=
|
||||||
let li2' := li2.filter (¬ li1.contains ·)
|
let li2' := li2.filter (¬ li1.contains ·)
|
||||||
li1 ++ li2'
|
li1 ++ li2'
|
||||||
|
@ -451,7 +479,7 @@ inductive TacticResult where
|
||||||
-- The given action cannot be executed in the state
|
-- The given action cannot be executed in the state
|
||||||
| invalidAction (message : String)
|
| invalidAction (message : String)
|
||||||
|
|
||||||
private def dumpMessageLog (prevMessageLength : Nat) : CoreM (Bool × Array String) := do
|
private def dumpMessageLog (prevMessageLength : Nat := 0) : CoreM (Bool × Array String) := do
|
||||||
let newMessages := (← Core.getMessageLog).toList.drop prevMessageLength
|
let newMessages := (← Core.getMessageLog).toList.drop prevMessageLength
|
||||||
let hasErrors := newMessages.any (·.severity == .error)
|
let hasErrors := newMessages.any (·.severity == .error)
|
||||||
let newMessages ← newMessages.mapM λ m => m.toString
|
let newMessages ← newMessages.mapM λ m => m.toString
|
||||||
|
@ -459,13 +487,12 @@ private def dumpMessageLog (prevMessageLength : Nat) : CoreM (Bool × Array Stri
|
||||||
return (hasErrors, newMessages.toArray)
|
return (hasErrors, newMessages.toArray)
|
||||||
|
|
||||||
def withCapturingError (elabM : Elab.Term.TermElabM GoalState) : Elab.TermElabM TacticResult := do
|
def withCapturingError (elabM : Elab.Term.TermElabM GoalState) : Elab.TermElabM TacticResult := do
|
||||||
-- FIXME: Maybe message log should be empty
|
assert! (← Core.getMessageLog).toList.isEmpty
|
||||||
let prevMessageLength := (← Core.getMessageLog).toList.length
|
|
||||||
try
|
try
|
||||||
let state ← elabM
|
let state ← elabM
|
||||||
|
|
||||||
-- Check if error messages have been generated in the core.
|
-- Check if error messages have been generated in the core.
|
||||||
let (hasError, newMessages) ← dumpMessageLog prevMessageLength
|
let (hasError, newMessages) ← dumpMessageLog
|
||||||
if hasError then
|
if hasError then
|
||||||
return .failure newMessages
|
return .failure newMessages
|
||||||
else
|
else
|
||||||
|
@ -473,62 +500,59 @@ def withCapturingError (elabM : Elab.Term.TermElabM GoalState) : Elab.TermElabM
|
||||||
catch exception =>
|
catch exception =>
|
||||||
match exception with
|
match exception with
|
||||||
| .internal _ =>
|
| .internal _ =>
|
||||||
let (_, messages) ← dumpMessageLog prevMessageLength
|
let (_, messages) ← dumpMessageLog
|
||||||
return .failure messages
|
return .failure messages
|
||||||
| _ => return .failure #[← exception.toMessageData.toString]
|
| _ => return .failure #[← exception.toMessageData.toString]
|
||||||
|
|
||||||
/-- Executes a `TacticM` monad on this `GoalState`, collecting the errors as necessary -/
|
/-- Executes a `TacticM` monad on this `GoalState`, collecting the errors as necessary -/
|
||||||
protected def GoalState.tryTacticM
|
protected def GoalState.tryTacticM
|
||||||
(state: GoalState) (goal: MVarId) (tacticM: Elab.Tactic.TacticM Unit)
|
(state: GoalState) (site : Site)
|
||||||
|
(tacticM: Elab.Tactic.TacticM Unit)
|
||||||
(guardMVarErrors : Bool := false)
|
(guardMVarErrors : Bool := false)
|
||||||
: Elab.TermElabM TacticResult := do
|
: Elab.TermElabM TacticResult :=
|
||||||
withCapturingError do
|
withCapturingError do
|
||||||
state.step goal tacticM guardMVarErrors
|
state.step site tacticM guardMVarErrors
|
||||||
|
|
||||||
/-- Execute a string tactic on given state. Restores TermElabM -/
|
/-- Execute a string tactic on given state. Restores TermElabM -/
|
||||||
@[export pantograph_goal_state_try_tactic_m]
|
@[export pantograph_goal_state_try_tactic_m]
|
||||||
protected def GoalState.tryTactic (state: GoalState) (goal: MVarId) (tactic: String):
|
protected def GoalState.tryTactic (state: GoalState) (site : Site) (tactic: String):
|
||||||
Elab.TermElabM TacticResult := do
|
Elab.TermElabM TacticResult := do
|
||||||
state.restoreElabM
|
state.restoreElabM
|
||||||
/-
|
let .some goal := state.actingGoal? site | throwNoGoals
|
||||||
if let .some fragment := state.fragments[goal]? then
|
if let .some fragment := state.fragments[goal]? then
|
||||||
return ← withCapturingError do
|
return ← withCapturingError do
|
||||||
let (moreFragments, state') ← state.step' goal (fragment.step goal tactic)
|
let (moreFragments, state') ← state.step' site (fragment.step goal tactic)
|
||||||
let fragments := moreFragments.fold (init := state.fragments.erase goal) λ acc mvarId f =>
|
let fragments := moreFragments.fold (init := state.fragments.erase goal) λ acc mvarId f =>
|
||||||
acc.insert mvarId f
|
acc.insert mvarId f
|
||||||
return { state' with fragments } -/
|
return { state' with fragments }
|
||||||
|
|
||||||
let catName := match isLHSGoal? (← goal.getType) with
|
|
||||||
| .some _ => `conv
|
|
||||||
| .none => `tactic
|
|
||||||
-- Normal tactic without fragment
|
-- Normal tactic without fragment
|
||||||
let tactic ← match Parser.runParserCategory
|
let tactic ← match Parser.runParserCategory
|
||||||
(env := ← MonadEnv.getEnv)
|
(env := ← getEnv)
|
||||||
(catName := catName)
|
(catName := `tactic)
|
||||||
(input := tactic)
|
(input := tactic)
|
||||||
(fileName := ← getFileName) with
|
(fileName := ← getFileName) with
|
||||||
| .ok stx => pure $ stx
|
| .ok stx => pure $ stx
|
||||||
| .error error => return .parseError error
|
| .error error => return .parseError error
|
||||||
let tacticM := Elab.Tactic.evalTactic tactic
|
let tacticM := Elab.Tactic.evalTactic tactic
|
||||||
withCapturingError do
|
withCapturingError do
|
||||||
state.step goal tacticM (guardMVarErrors := true)
|
state.step site tacticM (guardMVarErrors := true)
|
||||||
|
|
||||||
-- Specialized Tactics
|
-- Specialized Tactics
|
||||||
|
|
||||||
protected def GoalState.tryAssign (state: GoalState) (goal: MVarId) (expr: String):
|
protected def GoalState.tryAssign (state : GoalState) (site : Site) (expr : String)
|
||||||
Elab.TermElabM TacticResult := do
|
: Elab.TermElabM TacticResult := do
|
||||||
state.restoreElabM
|
state.restoreElabM
|
||||||
let expr ← match Parser.runParserCategory
|
let expr ← match Parser.runParserCategory
|
||||||
(env := ← MonadEnv.getEnv)
|
(env := ← getEnv)
|
||||||
(catName := `term)
|
(catName := `term)
|
||||||
(input := expr)
|
(input := expr)
|
||||||
(fileName := ← getFileName) with
|
(fileName := ← getFileName) with
|
||||||
| .ok syn => pure syn
|
| .ok syn => pure syn
|
||||||
| .error error => return .parseError error
|
| .error error => return .parseError error
|
||||||
state.tryTacticM goal $ Tactic.evalAssign expr
|
state.tryTacticM site $ Tactic.evalAssign expr
|
||||||
|
|
||||||
protected def GoalState.tryLet (state: GoalState) (goal: MVarId) (binderName: String) (type: String):
|
protected def GoalState.tryLet (state : GoalState) (site : Site) (binderName : String) (type : String)
|
||||||
Elab.TermElabM TacticResult := do
|
: Elab.TermElabM TacticResult := do
|
||||||
state.restoreElabM
|
state.restoreElabM
|
||||||
let type ← match Parser.runParserCategory
|
let type ← match Parser.runParserCategory
|
||||||
(env := ← MonadEnv.getEnv)
|
(env := ← MonadEnv.getEnv)
|
||||||
|
@ -537,23 +561,25 @@ protected def GoalState.tryLet (state: GoalState) (goal: MVarId) (binderName: St
|
||||||
(fileName := ← getFileName) with
|
(fileName := ← getFileName) with
|
||||||
| .ok syn => pure syn
|
| .ok syn => pure syn
|
||||||
| .error error => return .parseError error
|
| .error error => return .parseError error
|
||||||
state.tryTacticM goal $ Tactic.evalLet binderName.toName type
|
state.tryTacticM site $ Tactic.evalLet binderName.toName type
|
||||||
|
|
||||||
/-- Enter conv tactic mode -/
|
/-- Enter conv tactic mode -/
|
||||||
@[export pantograph_goal_state_conv_enter_m]
|
@[export pantograph_goal_state_conv_enter_m]
|
||||||
protected def GoalState.conv (state : GoalState) (goal : MVarId) :
|
protected def GoalState.conv (state : GoalState) (site : Site) :
|
||||||
Elab.TermElabM TacticResult := do
|
Elab.TermElabM TacticResult := do
|
||||||
|
let .some goal := state.actingGoal? site | throwNoGoals
|
||||||
if let .some (.conv ..) := state.fragments[goal]? then
|
if let .some (.conv ..) := state.fragments[goal]? then
|
||||||
return .invalidAction "Already in conv state"
|
return .invalidAction "Already in conv state"
|
||||||
withCapturingError do
|
withCapturingError do
|
||||||
let (fragments, state') ← state.step' goal Fragment.enterConv
|
let (fragments, state') ← state.step' site Fragment.enterConv
|
||||||
return {
|
return {
|
||||||
state' with
|
state' with
|
||||||
fragments := fragments.fold (init := state'.fragments) λ acc goal fragment =>
|
fragments := fragments.fold (init := state'.fragments) λ acc goal fragment =>
|
||||||
acc.insert goal fragment
|
acc.insert goal fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
/-- Exit from `conv` mode. Resumes all goals before the mode starts and applys the conv -/
|
/-- Exit from `conv` mode, and conclude all conversion tactic sentinels
|
||||||
|
descended from `goal`. -/
|
||||||
@[export pantograph_goal_state_conv_exit_m]
|
@[export pantograph_goal_state_conv_exit_m]
|
||||||
protected def GoalState.convExit (state : GoalState) (goal : MVarId):
|
protected def GoalState.convExit (state : GoalState) (goal : MVarId):
|
||||||
Elab.TermElabM TacticResult := do
|
Elab.TermElabM TacticResult := do
|
||||||
|
@ -571,8 +597,9 @@ protected def GoalState.calcPrevRhsOf? (state : GoalState) (goal : MVarId) : Opt
|
||||||
prevRhs?
|
prevRhs?
|
||||||
|
|
||||||
@[export pantograph_goal_state_try_calc_m]
|
@[export pantograph_goal_state_try_calc_m]
|
||||||
protected def GoalState.tryCalc (state : GoalState) (goal : MVarId) (pred : String)
|
protected def GoalState.tryCalc (state : GoalState) (site : Site) (pred : String)
|
||||||
: Elab.TermElabM TacticResult := do
|
: Elab.TermElabM TacticResult := do
|
||||||
|
let .some goal := state.actingGoal? site | throwNoGoals
|
||||||
let prevRhs? := state.calcPrevRhsOf? goal
|
let prevRhs? := state.calcPrevRhsOf? goal
|
||||||
withCapturingError do
|
withCapturingError do
|
||||||
let (moreFragments, state') ← state.step' goal do
|
let (moreFragments, state') ← state.step' goal do
|
||||||
|
|
|
@ -135,6 +135,7 @@ protected def Fragment.step (fragment : Fragment) (goal : MVarId) (s : String)
|
||||||
| .conv .. => do
|
| .conv .. => do
|
||||||
throwError "Direct operation on conversion tactic parent goal is not allowed"
|
throwError "Direct operation on conversion tactic parent goal is not allowed"
|
||||||
| fragment@(.convSentinel _) => do
|
| fragment@(.convSentinel _) => do
|
||||||
|
assert! isLHSGoal? (← goal.getType) |>.isSome
|
||||||
let tactic ← match Parser.runParserCategory
|
let tactic ← match Parser.runParserCategory
|
||||||
(env := ← MonadEnv.getEnv)
|
(env := ← MonadEnv.getEnv)
|
||||||
(catName := `conv)
|
(catName := `conv)
|
||||||
|
|
Loading…
Reference in New Issue