fix: preserve separators in evalSepByIndentTactic
This commit is contained in:
parent
ee9c9b1312
commit
3add955382
3 changed files with 95 additions and 52 deletions
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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"]}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue