This repository has been archived by the owner on Oct 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 216
/
Copy pathinteractive_base.lean
216 lines (182 loc) · 7.1 KB
/
interactive_base.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
204
205
206
207
208
209
210
211
212
213
214
215
216
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import init.data.option.instances
import init.meta.lean.parser init.meta.tactic init.meta.has_reflect
open lean
open lean.parser
local postfix `?`:9001 := optional
local postfix *:9001 := many
namespace interactive
/-- (parse p) as the parameter type of an interactive tactic will instruct the Lean parser
to run `p` when parsing the parameter and to pass the parsed value as an argument
to the tactic. -/
@[reducible] meta def parse {α : Type} [has_reflect α] (p : parser α) : Type := α
inductive loc : Type
| wildcard : loc
| ns : list name → loc
meta instance : has_reflect loc
| loc.wildcard := `(_)
| (loc.ns xs) := `(_)
meta def loc.include_goal : loc → bool
| loc.wildcard := tt
| (loc.ns []) := tt
| _ := ff
meta def loc.get_locals : loc → tactic (list expr)
| loc.wildcard := tactic.local_context
| (loc.ns xs) := mmap tactic.get_local xs
namespace types
variables {α β : Type}
-- optimized pretty printer
meta def brackets (l r : string) (p : parser α) := tk l *> p <* tk r
meta def list_of (p : parser α) := brackets "[" "]" $ sep_by (skip_info (tk ",")) p
/-- A 'tactic expression', which uses right-binding power 2 so that it is terminated by
'<|>' (rbp 2), ';' (rbp 1), and ',' (rbp 0). It should be used for any (potentially)
trailing expression parameters. -/
meta def texpr := qexpr 2
/-- Parse an identifier or a '_' -/
meta def ident_ : parser name := ident <|> tk "_" *> return `_
meta def using_ident := (tk "using" *> ident)?
meta def with_ident_list := (tk "with" *> ident_*) <|> return []
meta def without_ident_list := (tk "without" *> ident*) <|> return []
meta def location := (tk "at" *> (tk "*" *> return loc.wildcard <|> (loc.ns <$> ident*))) <|> return (loc.ns [])
meta def qexpr_list := list_of (qexpr 0)
meta def opt_qexpr_list := qexpr_list <|> return []
meta def qexpr_list_or_texpr := qexpr_list <|> list.ret <$> texpr
meta def only_flag : parser bool := (tk "only" *> return tt) <|> return ff
end types
precedence only:0
/-- Use `desc` as the interactive description of `p`. -/
meta def with_desc {α : Type} (desc : format) (p : parser α) : parser α := p
open expr format tactic types
private meta def maybe_paren : list format → format
| [] := ""
| [f] := f
| fs := paren (join fs)
private meta def unfold (e : expr) : tactic expr :=
do (expr.const f_name f_lvls) ← return e.get_app_fn | failed,
env ← get_env,
decl ← env.get f_name,
new_f ← decl.instantiate_value_univ_params f_lvls,
head_beta (expr.mk_app new_f e.get_app_args)
private meta def concat (f₁ f₂ : list format) :=
if f₁.empty then f₂ else if f₂.empty then f₁ else f₁ ++ [" "] ++ f₂
private meta def parser_desc_aux : expr → tactic (list format)
| `(ident) := return ["id"]
| `(ident_) := return ["id"]
| `(qexpr) := return ["expr"]
| `(tk %%c) := list.ret <$> to_fmt <$> eval_expr string c
| `(cur_pos) := return []
| `(pure ._) := return []
| `(._ <$> %%p) := parser_desc_aux p
| `(skip_info %%p) := parser_desc_aux p
| `(set_goal_info_pos %%p) := parser_desc_aux p
| `(with_desc %%desc %%p) := list.ret <$> eval_expr format desc
| `(%%p₁ <*> %%p₂) := do
f₁ ← parser_desc_aux p₁,
f₂ ← parser_desc_aux p₂,
return $ concat f₁ f₂
| `(%%p₁ <* %%p₂) := do
f₁ ← parser_desc_aux p₁,
f₂ ← parser_desc_aux p₂,
return $ concat f₁ f₂
| `(%%p₁ *> %%p₂) := do
f₁ ← parser_desc_aux p₁,
f₂ ← parser_desc_aux p₂,
return $ concat f₁ f₂
| `(many %%p) := do
f ← parser_desc_aux p,
return [maybe_paren f ++ "*"]
| `(optional %%p) := do
f ← parser_desc_aux p,
return [maybe_paren f ++ "?"]
| `(sep_by %%sep %%p) := do
f₁ ← parser_desc_aux sep,
f₂ ← parser_desc_aux p,
return [maybe_paren f₂ ++ join f₁, " ..."]
| `(%%p₁ <|> %%p₂) := do
f₁ ← parser_desc_aux p₁,
f₂ ← parser_desc_aux p₂,
return $ if f₁.empty then [maybe_paren f₂ ++ "?"] else
if f₂.empty then [maybe_paren f₁ ++ "?"] else
[paren $ join $ f₁ ++ [to_fmt " | "] ++ f₂]
| `(brackets %%l %%r %%p) := do
f ← parser_desc_aux p,
l ← eval_expr string l,
r ← eval_expr string r,
-- much better than the naive [l, " ", f, " ", r]
return [to_fmt l ++ join f ++ to_fmt r]
| e := do
e' ← (do e' ← unfold e,
guard $ e' ≠ e,
return e') <|>
(do f ← pp e,
fail $ to_fmt "don't know how to pretty print " ++ f),
parser_desc_aux e'
meta def param_desc : expr → tactic format
| `(parse %%p) := join <$> parser_desc_aux p
| `(opt_param %%t ._) := (++ "?") <$> pp t
| e := if is_constant e ∧ (const_name e).components.ilast = `itactic
then return $ to_fmt "{ tactic }"
else paren <$> pp e
meta constant decl_attributes : Type
meta constant decl_attributes.apply : decl_attributes → name → parser unit
meta structure decl_modifiers :=
(is_private : bool)
(is_protected : bool)
(is_meta : bool)
(is_mutual : bool)
(is_noncomputable : bool)
meta structure decl_meta_info :=
(attrs : decl_attributes)
(modifiers : decl_modifiers)
(doc_string : option string)
meta structure single_inductive_decl :=
(attrs : decl_attributes)
(sig : expr)
(intros : list expr)
meta def single_inductive_decl.name (d : single_inductive_decl) : name :=
d.sig.app_fn.const_name
meta structure inductive_decl :=
(u_names : list name)
(params : list expr)
(decls : list single_inductive_decl)
/-- Parses and elaborates a single or multiple mutual inductive declarations (without the `inductive` keyword), depending on `is_mutual` -/
meta constant inductive_decl.parse : decl_meta_info → parser inductive_decl
end interactive
section macros
open interaction_monad
open interactive
private meta def parse_format : string → list char → parser pexpr
| acc [] := pure ``(to_fmt %%(reflect acc))
| acc ('\n'::s) :=
do f ← parse_format "" s,
pure ``(to_fmt %%(reflect acc) ++ format.line ++ %%f)
| acc ('{'::'{'::s) := parse_format (acc ++ "{") s
| acc ('{'::s) :=
do (e, s) ← with_input (lean.parser.pexpr 0) s.as_string,
'}'::s ← return s.to_list | fail "'}' expected",
f ← parse_format "" s,
pure ``(to_fmt %%(reflect acc) ++ to_fmt %%e ++ %%f)
| acc (c::s) := parse_format (acc.str c) s
reserve prefix `format! `:100
@[user_notation]
meta def format_macro (_ : parse $ tk "format!") (s : string) : parser pexpr :=
parse_format "" s.to_list
private meta def parse_sformat : string → list char → parser pexpr
| acc [] := pure $ pexpr.of_expr (reflect acc)
| acc ('{'::'{'::s) := parse_sformat (acc ++ "{") s
| acc ('{'::s) :=
do (e, s) ← with_input (lean.parser.pexpr 0) s.as_string,
'}'::s ← return s.to_list | fail "'}' expected",
f ← parse_sformat "" s,
pure ``(%%(reflect acc) ++ to_string %%e ++ %%f)
| acc (c::s) := parse_sformat (acc.str c) s
reserve prefix `sformat! `:100
@[user_notation]
meta def sformat_macro (_ : parse $ tk "sformat!") (s : string) : parser pexpr :=
parse_sformat "" s.to_list
end macros