fix: preserve separators in evalSepByIndentTactic

This commit is contained in:
Gabriel Ebner 2022-09-16 17:12:48 +02:00 committed by Leonardo de Moura
parent ee9c9b1312
commit 3add955382
3 changed files with 95 additions and 52 deletions

View file

@ -35,42 +35,75 @@ open Parser.Tactic
@[builtinTactic paren] def evalParen : Tactic := fun stx =>
evalTactic stx[1]
def isCheckpointableTactic (arg : Syntax.Tactic) : TacticM Bool := do
def isCheckpointableTactic (arg : Syntax) : TacticM Bool := do
-- TODO: make it parametric
let kind := arg.1.getKind
let kind := arg.getKind
return kind == ``Lean.Parser.Tactic.save
partial def addCheckpoints (args : Array Syntax.Tactic) : TacticM (Array Syntax.Tactic) := do
-- if (← readThe Term.Context).tacticCache? |>.isSome then
if (← args.anyM fun arg => isCheckpointableTactic arg) then
let argsNew ← go 0 #[] #[]
return argsNew
return args
where
push (acc : Array Syntax.Tactic) (result : Array Syntax.Tactic) : Array Syntax.Tactic :=
if acc.isEmpty then
result
else
result.push <| Unhygienic.run do withRef acc.back do
`(tactic| checkpoint $[$acc]*)
/--
Takes a `sepByIndent tactic "; "`, and inserts `checkpoint` blocks for `save` tactics.
go (i : Nat) (acc : Array Syntax.Tactic) (result : Array Syntax.Tactic) : TacticM (Array Syntax.Tactic) := do
if h : i < args.size then
let arg := args.get ⟨i, h⟩
if (← isCheckpointableTactic arg) then
-- `argNew` is `arg` as singleton sequence. The idea is to make sure it does not satisfy `isCheckpointableTactic` anymore
let argNew := ⟨mkNullNode #[arg]⟩ -- HACK
let acc := acc.push argNew
go (i+1) #[] (push acc result)
else
go (i+1) (acc.push arg) result
Input:
```
a
b
save
c
d
save
e
```
Output:
```
checkpoint
a
b
save
checkpoint
c
d
save
e
```
-/
-- Note that we need to preserve the separators to show the right goals after semicolons.
def addCheckpoints (stx : Syntax) : TacticM Syntax := do
-- if (← readThe Term.Context).tacticCache? |>.isSome then
if !(← stx.getSepArgs.anyM isCheckpointableTactic) then return stx
let mut currentCheckpointBlock := #[]
let mut output := #[]
for i in [:stx.getArgs.size / 2] do
let tac := stx[2*i]
let sep? := stx.getArgs[2*i+1]?
if (← isCheckpointableTactic tac) then
let checkpoint : Syntax :=
mkNode ``checkpoint #[
mkAtomFrom tac "checkpoint",
mkNode ``tacticSeq #[
mkNode ``tacticSeq1Indented #[
-- HACK: null node is not a valid tactic, but prevents infinite loop
mkNullNode (currentCheckpointBlock.push tac)
]
]
]
currentCheckpointBlock := #[]
output := output.push checkpoint
if let some sep := sep? then output := output.push sep
else
return result ++ acc
currentCheckpointBlock := currentCheckpointBlock.push tac
if let some sep := sep? then currentCheckpointBlock := currentCheckpointBlock.push sep
output := output ++ currentCheckpointBlock
return stx.setArgs output
/-- Evaluate `sepByIndent tactic "; " -/
def evalSepByIndentTactic (stx : Syntax) : TacticM Unit := do
for seqElem in (← addCheckpoints (stx.getSepArgs.map (⟨·⟩))) do
evalTactic seqElem
let stx ← addCheckpoints stx
for arg in stx.getArgs, i in [:stx.getArgs.size] do
if i % 2 == 0 then
evalTactic arg
else
saveTacticInfoForToken arg
@[builtinTactic tacticSeq1Indented] def evalTacticSeq1Indented : Tactic := fun stx =>
evalSepByIndentTactic stx[0]

View file

@ -21,6 +21,8 @@ example : 0 + n = n := by
example : αα := by
intro a; apply a
--^ $/lean/plainGoal
--^ $/lean/plainGoal
--^ $/lean/plainGoal
example (h1 : n = m) (h2 : m = 0) : 0 = n := by
rw [h1, h2]

View file

@ -37,64 +37,72 @@
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 25, "character": 3}}
"position": {"line": 21, "character": 10}}
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 21, "character": 11}}
{"rendered": "```lean\nα : Sort ?u\na : α\n⊢ α\n```",
"goals": ["α : Sort ?u\na : α\n⊢ α"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 27, "character": 3}}
{"rendered": "```lean\nn m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = n\n```",
"goals": ["n m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = n"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 25, "character": 9}}
"position": {"line": 27, "character": 9}}
{"rendered": "```lean\nn m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = m\n```",
"goals": ["n m : Nat\nh1 : n = m\nh2 : m = 0\n⊢ 0 = m"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 25, "character": 13}}
"position": {"line": 27, "character": 13}}
{"rendered": "no goals", "goals": []}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 32, "character": 3}}
"position": {"line": 34, "character": 3}}
{"rendered": "```lean\ncase zero\n⊢ 0 + Nat.zero = Nat.zero\n```",
"goals": ["case zero\n⊢ 0 + Nat.zero = Nat.zero"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 38, "character": 3}}
"position": {"line": 40, "character": 3}}
{"rendered":
"```lean\ncase zero\n⊢ 0 + Nat.zero = Nat.zero\n```\n---\n```lean\ncase succ\nn✝ : Nat\n: 0 + n✝ = n✝\n⊢ 0 + Nat.succ n✝ = Nat.succ n✝\n```",
"goals":
["case zero\n⊢ 0 + Nat.zero = Nat.zero",
"case succ\nn✝ : Nat\n: 0 + n✝ = n✝\n⊢ 0 + Nat.succ n✝ = Nat.succ n✝"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 42, "character": 3}}
"position": {"line": 44, "character": 3}}
{"rendered":
"```lean\ncase zero\n⊢ 0 + Nat.zero = Nat.zero\n```\n---\n```lean\ncase succ\nn✝ : Nat\n⊢ 0 + Nat.succ n✝ = Nat.succ n✝\n```",
"goals":
["case zero\n⊢ 0 + Nat.zero = Nat.zero",
"case succ\nn✝ : Nat\n⊢ 0 + Nat.succ n✝ = Nat.succ n✝"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 46, "character": 3}}
"position": {"line": 48, "character": 3}}
{"rendered": "```lean\na b : Nat\n⊢ a = b\n```",
"goals": ["a b : Nat\n⊢ a = b"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 49, "character": 20}}
"position": {"line": 51, "character": 20}}
{"rendered": "```lean\nα : Sort ?u\n⊢ αα\n```",
"goals": ["α : Sort ?u\n⊢ αα"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 53, "character": 3}}
"position": {"line": 55, "character": 3}}
{"rendered":
"```lean\nα : Sort ?u\np : α → Prop\na b : α\ninst✝ : DecidablePred p\nh : ∀ {p : α → Prop} [inst : DecidablePred p], p a → p b\n⊢ p a\n```",
"goals":
["α : Sort ?u\np : α → Prop\na b : α\ninst✝ : DecidablePred p\nh : ∀ {p : α → Prop} [inst : DecidablePred p], p a → p b\n⊢ p a"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 59, "character": 3}}
"position": {"line": 61, "character": 3}}
{"rendered": "```lean\ncase left\n⊢ True\n```", "goals": ["case left\n⊢ True"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 61, "character": 3}}
"position": {"line": 63, "character": 3}}
{"rendered": "```lean\ncase right\n⊢ False\n```",
"goals": ["case right\n⊢ False"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 66, "character": 3}}
{"rendered": "```lean\ncase left\n⊢ True\n```", "goals": ["case left\n⊢ True"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 68, "character": 3}}
{"rendered": "```lean\ncase left\n⊢ True\n```", "goals": ["case left\n⊢ True"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 70, "character": 3}}
{"rendered": "```lean\ncase right\n⊢ False\n```",
"goals": ["case right\n⊢ False"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 76, "character": 29}}
"position": {"line": 78, "character": 29}}
{"rendered":
"```lean\nt a n✝ : Nat\n: t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + t * Nat.succ n✝\n```\n---\n```lean\nt a n✝ : Nat\n: t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)\n```\n---\n```lean\nt a n✝ : Nat\n: t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)\n```",
"goals":
@ -102,37 +110,37 @@
"t a n✝ : Nat\n: t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)",
"t a n✝ : Nat\n: t * (a + n✝) = t * a + t * n✝\n⊢ t * (a + n✝) + t = t * a + (t * n✝ + t)"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 80, "character": 53}}
"position": {"line": 82, "character": 53}}
{"rendered":
"```lean\ncase nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)\n```",
"goals":
["case nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 80, "character": 54}}
"position": {"line": 82, "character": 54}}
{"rendered":
"```lean\ncase nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)\n```",
"goals":
["case nil\nα : Type ?u\nbs cs : List α\n⊢ [] ++ bs ++ cs = [] ++ (bs ++ cs)"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 84, "character": 38}}
"position": {"line": 86, "character": 38}}
{"rendered": "no goals", "goals": []}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 87, "character": 39}}
"position": {"line": 89, "character": 39}}
null
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 91, "character": 16}}
"position": {"line": 93, "character": 16}}
{"rendered":
"```lean\ncase left\n⊢ True\n```\n---\n```lean\ncase right\n⊢ False\n```",
"goals": ["case left\n⊢ True", "case right\n⊢ False"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 95, "character": 8}}
"position": {"line": 97, "character": 8}}
{"rendered": "```lean\n| True = True\n```", "goals": ["| True = True"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 97, "character": 4}}
"position": {"line": 99, "character": 4}}
{"rendered": "```lean\n| True = True\n```", "goals": ["| True = True"]}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 99, "character": 2}}
"position": {"line": 101, "character": 2}}
{"rendered": "no goals", "goals": []}
{"textDocument": {"uri": "file://plainGoal.lean"},
"position": {"line": 103, "character": 2}}
"position": {"line": 105, "character": 2}}
{"rendered": "```lean\n⊢ False\n```", "goals": ["⊢ False"]}