forked from leanprover/lean4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DefView.lean
203 lines (183 loc) · 8.25 KB
/
DefView.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Sebastian Ullrich
-/
import Lean.Meta.ForEachExpr
import Lean.Elab.Command
import Lean.Elab.DeclUtil
import Lean.Meta.CollectFVars
namespace Lean.Elab
inductive DefKind where
| def | theorem | example | opaque | abbrev
deriving Inhabited, BEq
def DefKind.isTheorem : DefKind → Bool
| .theorem => true
| _ => false
def DefKind.isDefOrAbbrevOrOpaque : DefKind → Bool
| .def => true
| .opaque => true
| .abbrev => true
| _ => false
def DefKind.isExample : DefKind → Bool
| .example => true
| _ => false
structure DefView where
kind : DefKind
ref : Syntax
modifiers : Modifiers
declId : Syntax
binders : Syntax
type? : Option Syntax
value : Syntax
deriving? : Option (Array Syntax) := none
deriving Inhabited
def DefView.isInstance (view : DefView) : Bool :=
view.modifiers.attrs.any fun attr => attr.name == `instance
namespace Command
open Meta
def mkDefViewOfAbbrev (modifiers : Modifiers) (stx : Syntax) : DefView :=
-- leading_parser "abbrev " >> declId >> optDeclSig >> declVal
let (binders, type) := expandOptDeclSig stx[2]
let modifiers := modifiers.addAttribute { name := `inline }
let modifiers := modifiers.addAttribute { name := `reducible }
{ ref := stx, kind := DefKind.abbrev, modifiers,
declId := stx[1], binders, type? := type, value := stx[3] }
def mkDefViewOfDef (modifiers : Modifiers) (stx : Syntax) : DefView :=
-- leading_parser "def " >> declId >> optDeclSig >> declVal >> optDefDeriving
let (binders, type) := expandOptDeclSig stx[2]
let deriving? := if stx[4].isNone then none else some stx[4][1].getSepArgs
{ ref := stx, kind := DefKind.def, modifiers,
declId := stx[1], binders, type? := type, value := stx[3], deriving? }
def mkDefViewOfTheorem (modifiers : Modifiers) (stx : Syntax) : DefView :=
-- leading_parser "theorem " >> declId >> declSig >> declVal
let (binders, type) := expandDeclSig stx[2]
{ ref := stx, kind := DefKind.theorem, modifiers,
declId := stx[1], binders, type? := some type, value := stx[3] }
private partial def mkInstanceNameFromExpr (binders : Array Expr) (e : Expr) : MetaM String := do
let mut (strings, s) ← go e (HashSet.insert {} "")
let fvars := (collectFVars {} e).fvarSet
for binder in binders do
-- Only mention binders that aren't implied by `e`. (These must be additional classes.)
unless fvars.contains binder.fvarId! do
let ty ← inferType binder
let (strings', s') ← go ty strings
(strings, s) := (strings', s ++ if s' == "" then "" else "Of" ++ s')
return s
where
go (e : Expr) (strings : HashSet String) : MetaM (HashSet String × String) := do
let (strings', s) ← go' e strings
return (strings'.insert s, if strings.contains s then "" else s)
go' (e : Expr) (strings : HashSet String) : MetaM (HashSet String × String) := do
match e with
| .app .. =>
e.withApp fun f args => do
-- Visit only the explicit arguments to `f` and type arguments.
forallBoundedTelescope (← inferType f) args.size fun args' _ => do
let mut (strings, s) ← go f strings
for arg in args, arg' in args' do
let bi ← arg'.fvarId!.getBinderInfo
let isTy ← Meta.isType arg
if bi == .default || (isTy && !arg.isSort) then
let (strings', sarg) ← go arg strings
(strings, s) := (strings', s ++ sarg)
return (strings, s)
| .forallE n ty body bi =>
withLocalDecl n bi ty fun arg => do
let body := body.instantiate1 arg
let (strings, sty) ← go ty strings
let (strings, sbody) ← go body strings
return (strings, "Forall" ++ sty ++ sbody)
| .lam n ty body bi =>
if let some e := Expr.etaExpandedStrict? e then
go' e strings
else
withLocalDecl n bi ty fun arg => do
let body := body.instantiate1 arg
let (strings, sbody) ← go body strings
return (strings, "Fun" ++ sbody)
| .sort .. =>
if e.isProp then return (strings, "Prop")
else if e.isType then return (strings, "Type")
else return (strings, "Sort")
| .const name .. =>
return match name.eraseMacroScopes with
| .str _ str => (strings, str.capitalize)
| _ => (strings, "")
| _ => return (strings, "")
/--
Generate a name for an instance with the given type.
Note that we elaborate the type twice. Once for producing the name, and another when elaborating the declaration. -/
def mkInstanceName (binders : Array Syntax) (type : Syntax) : CommandElabM Name := do
let savedState ← get
let name ←
try
runTermElabM fun _ => Term.withAutoBoundImplicit <| Term.elabBinders binders fun binds => Term.withoutErrToSorry do
let type ← instantiateMVars (← Term.elabType type)
forallTelescope type fun binds' type' => mkInstanceNameFromExpr (binds ++ binds') type'
catch _ =>
pure s!"@{← getMainModule}"
set savedState
liftMacroM <| mkUnusedBaseName <| Name.mkSimple ("inst" ++ name)
def mkDefViewOfInstance (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView := do
-- leading_parser Term.attrKind >> "instance " >> optNamedPrio >> optional declId >> declSig >> declVal
let attrKind ← liftMacroM <| toAttributeKind stx[0]
let prio ← liftMacroM <| expandOptNamedPrio stx[2]
let attrStx ← `(attr| instance $(quote prio):num)
let (binders, type) := expandDeclSig stx[4]
let modifiers := modifiers.addAttribute { kind := attrKind, name := `instance, stx := attrStx }
let declId ← match stx[3].getOptional? with
| some declId => pure declId
| none =>
let id ← mkInstanceName binders.getArgs type
pure <| mkNode ``Parser.Command.declId #[mkIdentFrom stx id, mkNullNode]
return {
ref := stx, kind := DefKind.def, modifiers := modifiers,
declId := declId, binders := binders, type? := type, value := stx[5]
}
def mkDefViewOfOpaque (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView := do
-- leading_parser "opaque " >> declId >> declSig >> optional declValSimple
let (binders, type) := expandDeclSig stx[2]
let val ← match stx[3].getOptional? with
| some val => pure val
| none =>
let val ← if modifiers.isUnsafe then `(default_or_ofNonempty% unsafe) else `(default_or_ofNonempty%)
pure <| mkNode ``Parser.Command.declValSimple #[ mkAtomFrom stx ":=", val ]
return {
ref := stx, kind := DefKind.opaque, modifiers := modifiers,
declId := stx[1], binders := binders, type? := some type, value := val
}
def mkDefViewOfExample (modifiers : Modifiers) (stx : Syntax) : DefView :=
-- leading_parser "example " >> declSig >> declVal
let (binders, type) := expandOptDeclSig stx[1]
let id := mkIdentFrom stx `_example
let declId := mkNode ``Parser.Command.declId #[id, mkNullNode]
{ ref := stx, kind := DefKind.example, modifiers := modifiers,
declId := declId, binders := binders, type? := type, value := stx[2] }
def isDefLike (stx : Syntax) : Bool :=
let declKind := stx.getKind
declKind == ``Parser.Command.abbrev ||
declKind == ``Parser.Command.def ||
declKind == ``Parser.Command.theorem ||
declKind == ``Parser.Command.opaque ||
declKind == ``Parser.Command.instance ||
declKind == ``Parser.Command.example
def mkDefView (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView :=
let declKind := stx.getKind
if declKind == ``Parser.Command.«abbrev» then
return mkDefViewOfAbbrev modifiers stx
else if declKind == ``Parser.Command.def then
return mkDefViewOfDef modifiers stx
else if declKind == ``Parser.Command.theorem then
return mkDefViewOfTheorem modifiers stx
else if declKind == ``Parser.Command.opaque then
mkDefViewOfOpaque modifiers stx
else if declKind == ``Parser.Command.instance then
mkDefViewOfInstance modifiers stx
else if declKind == ``Parser.Command.example then
return mkDefViewOfExample modifiers stx
else
throwError "unexpected kind of definition"
builtin_initialize registerTraceClass `Elab.definition
end Command
end Lean.Elab