2023-05-21 17:41:39 -07:00
|
|
|
|
import Lean
|
|
|
|
|
|
|
|
|
|
import Pantograph.Symbols
|
2023-05-27 23:10:39 -07:00
|
|
|
|
import Pantograph.Serial
|
2023-05-21 17:41:39 -07:00
|
|
|
|
|
|
|
|
|
/-
|
|
|
|
|
The proof state manipulation system
|
|
|
|
|
|
|
|
|
|
A proof state is launched by providing
|
2023-05-24 00:54:48 -07:00
|
|
|
|
1. Environment: `Environment`
|
|
|
|
|
2. Expression: `Expr`
|
2023-05-21 17:41:39 -07:00
|
|
|
|
The expression becomes the first meta variable in the saved tactic state
|
2023-05-24 00:54:48 -07:00
|
|
|
|
`Elab.Tactic.SavedState`.
|
2023-05-21 17:41:39 -07:00
|
|
|
|
From this point on, any proof which extends
|
2023-05-24 00:54:48 -07:00
|
|
|
|
`Elab.Term.Context` and
|
2023-05-21 17:41:39 -07:00
|
|
|
|
-/
|
|
|
|
|
|
2023-05-24 00:54:48 -07:00
|
|
|
|
def Lean.MessageLog.getErrorMessages (log : MessageLog) : MessageLog :=
|
2023-08-14 17:07:53 -07:00
|
|
|
|
{
|
|
|
|
|
msgs := log.msgs.filter fun m => match m.severity with | MessageSeverity.error => true | _ => false
|
|
|
|
|
}
|
2023-05-21 17:41:39 -07:00
|
|
|
|
|
|
|
|
|
|
2023-05-24 00:54:48 -07:00
|
|
|
|
namespace Pantograph
|
|
|
|
|
open Lean
|
2023-05-21 17:41:39 -07:00
|
|
|
|
|
2023-08-27 19:53:09 -07:00
|
|
|
|
structure GoalState where
|
|
|
|
|
mvarId: MVarId
|
2023-05-24 00:54:48 -07:00
|
|
|
|
savedState : Elab.Tactic.SavedState
|
2023-05-21 17:41:39 -07:00
|
|
|
|
|
2023-05-24 00:54:48 -07:00
|
|
|
|
abbrev M := Elab.TermElabM
|
2023-05-21 17:41:39 -07:00
|
|
|
|
|
2023-08-27 19:53:09 -07:00
|
|
|
|
def GoalState.create (expr: Expr): M GoalState := do
|
2023-05-24 00:54:48 -07:00
|
|
|
|
let expr ← instantiateMVars expr
|
|
|
|
|
let goal := (← Meta.mkFreshExprMVar expr (kind := MetavarKind.synthetic))
|
|
|
|
|
let savedStateMonad: Elab.Tactic.TacticM Elab.Tactic.SavedState := MonadBacktrack.saveState
|
2023-05-23 05:12:46 -07:00
|
|
|
|
let savedState ← savedStateMonad { elaborator := .anonymous } |>.run' { goals := [goal.mvarId!]}
|
|
|
|
|
return {
|
2023-08-27 19:53:09 -07:00
|
|
|
|
savedState := savedState,
|
|
|
|
|
mvarId := goal.mvarId!
|
2023-05-21 17:41:39 -07:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-24 00:54:48 -07:00
|
|
|
|
def execute_tactic (state: Elab.Tactic.SavedState) (goal: MVarId) (tactic: String) :
|
|
|
|
|
M (Except (Array String) (Elab.Tactic.SavedState × List MVarId)):= do
|
|
|
|
|
let tacticM (stx: Syntax): Elab.Tactic.TacticM (Except (Array String) (Elab.Tactic.SavedState × List MVarId)) := do
|
2023-05-23 05:12:46 -07:00
|
|
|
|
state.restore
|
2023-05-24 00:54:48 -07:00
|
|
|
|
Elab.Tactic.setGoals [goal]
|
2023-05-21 17:41:39 -07:00
|
|
|
|
try
|
2023-05-24 00:54:48 -07:00
|
|
|
|
Elab.Tactic.evalTactic stx
|
|
|
|
|
if (← getThe Core.State).messages.hasErrors then
|
|
|
|
|
let messages := (← getThe Core.State).messages.getErrorMessages |>.toList.toArray
|
|
|
|
|
let errors ← (messages.map Message.data).mapM fun md => md.toString
|
2023-05-23 05:12:46 -07:00
|
|
|
|
return .error errors
|
|
|
|
|
else
|
2023-05-24 00:54:48 -07:00
|
|
|
|
return .ok (← MonadBacktrack.saveState, ← Elab.Tactic.getUnsolvedGoals)
|
2023-05-23 05:12:46 -07:00
|
|
|
|
catch exception =>
|
|
|
|
|
return .error #[← exception.toMessageData.toString]
|
2023-05-24 00:54:48 -07:00
|
|
|
|
match Parser.runParserCategory
|
|
|
|
|
(env := ← MonadEnv.getEnv)
|
2023-05-21 17:41:39 -07:00
|
|
|
|
(catName := `tactic)
|
|
|
|
|
(input := tactic)
|
|
|
|
|
(fileName := "<stdin>") with
|
|
|
|
|
| Except.error err => return .error #[err]
|
2023-05-23 05:12:46 -07:00
|
|
|
|
| Except.ok stx => tacticM stx { elaborator := .anonymous } |>.run' state.tactic
|
2023-05-21 17:41:39 -07:00
|
|
|
|
|
|
|
|
|
/-- Response for executing a tactic -/
|
|
|
|
|
inductive TacticResult where
|
|
|
|
|
-- Goes to next state
|
2023-08-27 19:53:09 -07:00
|
|
|
|
| success (goals: Array (GoalState × Commands.Goal))
|
2023-05-21 17:41:39 -07:00
|
|
|
|
-- Fails with messages
|
|
|
|
|
| failure (messages: Array String)
|
|
|
|
|
|
2023-08-27 19:53:09 -07:00
|
|
|
|
namespace TacticResult
|
|
|
|
|
|
|
|
|
|
def is_success: TacticResult → Bool
|
|
|
|
|
| .success _ => true
|
|
|
|
|
| .failure _ => false
|
|
|
|
|
|
|
|
|
|
end TacticResult
|
|
|
|
|
|
2023-05-21 17:41:39 -07:00
|
|
|
|
/-- Execute tactic on given state -/
|
2023-08-27 19:53:09 -07:00
|
|
|
|
def GoalState.execute (goal: GoalState) (tactic: String):
|
|
|
|
|
Commands.OptionsT M TacticResult := do
|
2023-08-14 21:43:40 -07:00
|
|
|
|
let options ← read
|
2023-08-27 19:53:09 -07:00
|
|
|
|
match (← execute_tactic (state := goal.savedState) (goal := goal.mvarId) (tactic := tactic)) with
|
|
|
|
|
| .error errors =>
|
|
|
|
|
return .failure errors
|
|
|
|
|
| .ok (nextState, nextGoals) =>
|
|
|
|
|
if nextGoals.isEmpty then
|
|
|
|
|
return .success #[]
|
|
|
|
|
else
|
|
|
|
|
let nextGoals: List GoalState := nextGoals.map fun mvarId => { mvarId, savedState := nextState }
|
|
|
|
|
let parentDecl? := (← MonadMCtx.getMCtx).findDecl? goal.mvarId
|
|
|
|
|
let goals ← nextGoals.mapM fun nextGoal => do
|
|
|
|
|
match (← MonadMCtx.getMCtx).findDecl? nextGoal.mvarId with
|
|
|
|
|
| .some mvarDecl =>
|
|
|
|
|
let serializedGoal ← serialize_goal options mvarDecl (parentDecl? := parentDecl?)
|
|
|
|
|
return (nextGoal, serializedGoal)
|
|
|
|
|
| .none => throwError nextGoal.mvarId
|
|
|
|
|
return .success goals.toArray
|
2023-05-21 17:41:39 -07:00
|
|
|
|
|
2023-05-24 00:54:48 -07:00
|
|
|
|
end Pantograph
|