-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSelectInsertConvDemo.lean
103 lines (86 loc) · 3.51 KB
/
SelectInsertConvDemo.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/-
Copyright (c) 2023 Patrick Massot. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Robin Böhne, Wojciech Nawrocki, Patrick Massot
-/
import Lean.Meta.ExprLens
import SelectInsertPanel
open Lean Meta Server
/-! # The conv? example -/
private structure SolveReturn where
expr : Expr
val? : Option String
listRest : List Nat
private def solveLevel (expr : Expr) (path : List Nat) : MetaM SolveReturn := match expr with
| Expr.app _ _ => do
let mut descExp := expr
let mut count := 0
let mut explicitList := []
-- we go through the application until we reach the end, counting how many explicit arguments it has and noting whether
-- they are explicit or implicit
while descExp.isApp do
if (←Lean.Meta.inferType descExp.appFn!).bindingInfo!.isExplicit then
explicitList := true::explicitList
count := count + 1
else
explicitList := false::explicitList
descExp := descExp.appFn!
-- we get the correct `enter` command by subtracting the number of `true`s in our list
let mut mutablePath := path
let mut length := count
explicitList := List.reverse explicitList
while !mutablePath.isEmpty && mutablePath.head! == 0 do
if explicitList.head! == true then
count := count - 1
explicitList := explicitList.tail!
mutablePath := mutablePath.tail!
let mut nextExp := expr
while length > count do
nextExp := nextExp.appFn!
length := length - 1
nextExp := nextExp.appArg!
let pathRest := if mutablePath.isEmpty then [] else mutablePath.tail!
return { expr := nextExp, val? := toString count , listRest := pathRest }
| Expr.lam n _ b _ => do
let name := match n with
| Name.str _ s => s
| _ => panic! "no name found"
return { expr := b, val? := name, listRest := path.tail! }
| Expr.forallE n _ b _ => do
let name := match n with
| Name.str _ s => s
| _ => panic! "no name found"
return { expr := b, val? := name, listRest := path.tail! }
| Expr.mdata _ b => do
match b with
| Expr.mdata _ _ => return { expr := b, val? := none, listRest := path }
| _ => return { expr := b.appFn!.appArg!, val? := none, listRest := path.tail!.tail! }
| _ => do
return { expr := ←(Lean.Core.viewSubexpr path.head! expr), val? := toString (path.head! + 1), listRest := path.tail! }
open Lean Syntax in
def insertEnter (subexprPos : Array Lean.SubExpr.GoalsLocation) (goalType : Expr) : MetaM String := do
let some pos := subexprPos[0]? | throwError "You must select something."
let ⟨_, .target subexprPos⟩ := pos | throwError "You must select something in the goal."
let mut list := (SubExpr.Pos.toArray subexprPos).toList
let mut expr := goalType
let mut retList := []
-- generate list of commands for `enter`
while !list.isEmpty do
let res ← solveLevel expr list
expr := res.expr
retList := match res.val? with
| none => retList
| some val => val::retList
list := res.listRest
-- build `enter [...]` string
retList := List.reverse retList
let mut enterval := "conv => enter " ++ toString retList
if enterval.contains '0' then enterval := "Error: Not a valid conv target"
if retList.isEmpty then enterval := ""
return enterval
mkSelectInsertTactic "conv?" "Conv 🔍"
"Use shift-click to select one sub-expression in the goal that you want to zoom on."
insertEnter
example (a : Nat) : a + a - a + a = a := by
-- Put your cursor on the next line
all_goals { sorry }