aboutsummaryrefslogtreecommitdiffhomepage
path: root/plugins/ltac/coretactics.ml4
blob: 61525cb49d8411800f7d6780104e359cad62ee5f (plain)
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
(************************************************************************)
(*         *   The Coq Proof Assistant / The Coq Development Team       *)
(*  v      *   INRIA, CNRS and contributors - Copyright 1999-2018       *)
(* <O___,, *       (see CREDITS file for the list of authors)           *)
(*   \VV/  **************************************************************)
(*    //   *    This file is distributed under the terms of the         *)
(*         *     GNU Lesser General Public License Version 2.1          *)
(*         *     (see LICENSE file for the text of the license)         *)
(************************************************************************)

open Util
open Locus
open Tactypes
open Genredexpr
open Stdarg
open Extraargs
open Tacarg
open Names
open Logic

DECLARE PLUGIN "ltac_plugin"

(** Basic tactics *)

TACTIC EXTEND reflexivity
  [ "reflexivity" ] -> [ Tactics.intros_reflexivity ]
END

TACTIC EXTEND exact
  [ "exact" casted_constr(c) ] -> [ Tactics.exact_no_check c ]
END

TACTIC EXTEND assumption
  [ "assumption" ] -> [ Tactics.assumption ]
END

TACTIC EXTEND etransitivity
  [ "etransitivity" ] -> [ Tactics.intros_transitivity None ]
END

TACTIC EXTEND cut
  [ "cut" constr(c) ] -> [ Tactics.cut c ]
END

TACTIC EXTEND exact_no_check
  [ "exact_no_check" constr(c) ] -> [ Tactics.exact_no_check c ]
END

TACTIC EXTEND vm_cast_no_check
  [ "vm_cast_no_check" constr(c) ] -> [ Tactics.vm_cast_no_check c ]
END

TACTIC EXTEND native_cast_no_check
  [ "native_cast_no_check" constr(c) ] -> [ Tactics.native_cast_no_check c ]
END

TACTIC EXTEND casetype
  [ "casetype" constr(c) ] -> [ Tactics.case_type c ]
END

TACTIC EXTEND elimtype
  [ "elimtype" constr(c) ] -> [ Tactics.elim_type c ]
END

TACTIC EXTEND lapply
  [ "lapply" constr(c) ] -> [ Tactics.cut_and_apply c ]
END

TACTIC EXTEND transitivity
  [ "transitivity" constr(c) ] -> [ Tactics.intros_transitivity (Some c) ]
END

(** Left *)

TACTIC EXTEND left
  [ "left" ] -> [ Tactics.left_with_bindings false NoBindings ]
END

TACTIC EXTEND eleft
  [ "eleft" ] -> [ Tactics.left_with_bindings true NoBindings ]
END

TACTIC EXTEND left_with
  [ "left" "with" bindings(bl) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES false bl (fun bl -> Tactics.left_with_bindings false bl)
  ]
END

TACTIC EXTEND eleft_with
  [ "eleft" "with" bindings(bl) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES true bl (fun bl -> Tactics.left_with_bindings true bl)
  ]
END

(** Right *)

TACTIC EXTEND right
  [ "right" ] -> [ Tactics.right_with_bindings false NoBindings ]
END

TACTIC EXTEND eright
  [ "eright" ] -> [ Tactics.right_with_bindings true NoBindings ]
END

TACTIC EXTEND right_with
  [ "right" "with" bindings(bl) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES false bl (fun bl -> Tactics.right_with_bindings false bl)
  ]
END

TACTIC EXTEND eright_with
  [ "eright" "with" bindings(bl) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES true bl (fun bl -> Tactics.right_with_bindings true bl)
  ]
END

(** Constructor *)

TACTIC EXTEND constructor
  [ "constructor" ] -> [ Tactics.any_constructor false None ]
| [ "constructor" int_or_var(i) ] -> [
    Tactics.constructor_tac false None i NoBindings
  ]
| [ "constructor" int_or_var(i) "with" bindings(bl) ] -> [
    let tac bl = Tactics.constructor_tac false None i bl in
    Tacticals.New.tclDELAYEDWITHHOLES false bl tac
  ]
END

TACTIC EXTEND econstructor
  [ "econstructor" ] -> [ Tactics.any_constructor true None ]
| [ "econstructor" int_or_var(i) ] -> [
    Tactics.constructor_tac true None i NoBindings
  ]
| [ "econstructor" int_or_var(i) "with" bindings(bl) ] -> [
    let tac bl = Tactics.constructor_tac true None i bl in
    Tacticals.New.tclDELAYEDWITHHOLES true bl tac
  ]
END

(** Specialize *)

TACTIC EXTEND specialize
  [ "specialize" constr_with_bindings(c) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES false c (fun c -> Tactics.specialize c None)
  ]
| [ "specialize" constr_with_bindings(c) "as" intropattern(ipat) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES false c (fun c -> Tactics.specialize c (Some ipat))
  ]
END

TACTIC EXTEND symmetry
  [ "symmetry" ] -> [ Tactics.intros_symmetry {onhyps=Some[];concl_occs=AllOccurrences} ]
END

TACTIC EXTEND symmetry_in
| [ "symmetry" "in" in_clause(cl) ] -> [ Tactics.intros_symmetry cl ]
END

(** Split *)

let rec delayed_list = function
| [] -> fun _ sigma -> (sigma, [])
| x :: l ->
  fun env sigma ->
    let (sigma, x) = x env sigma in
    let (sigma, l) = delayed_list l env sigma in
    (sigma, x :: l)

TACTIC EXTEND split
  [ "split" ] -> [ Tactics.split_with_bindings false [NoBindings] ]
END

TACTIC EXTEND esplit
  [ "esplit" ] -> [ Tactics.split_with_bindings true [NoBindings] ]
END

TACTIC EXTEND split_with
  [ "split" "with" bindings(bl) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES false bl (fun bl -> Tactics.split_with_bindings false [bl])
  ]
END

TACTIC EXTEND esplit_with
  [ "esplit" "with" bindings(bl) ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES true bl (fun bl -> Tactics.split_with_bindings true [bl])
  ]
END

TACTIC EXTEND exists
  [ "exists" ] -> [ Tactics.split_with_bindings false [NoBindings] ]
| [ "exists" ne_bindings_list_sep(bll, ",") ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES false (delayed_list bll) (fun bll -> Tactics.split_with_bindings false bll)
  ]
END

TACTIC EXTEND eexists
  [ "eexists" ] -> [ Tactics.split_with_bindings true [NoBindings] ]
| [ "eexists" ne_bindings_list_sep(bll, ",") ] -> [
    Tacticals.New.tclDELAYEDWITHHOLES true (delayed_list bll) (fun bll -> Tactics.split_with_bindings true bll)
  ]
END

(** Intro *)

TACTIC EXTEND intros_until
  [ "intros" "until" quantified_hypothesis(h) ] -> [ Tactics.intros_until h ]
END

TACTIC EXTEND intro
| [ "intro" ] -> [ Tactics.intro_move None MoveLast ]
| [ "intro" ident(id) ] -> [ Tactics.intro_move (Some id) MoveLast ]
| [ "intro" ident(id) "at" "top" ] -> [ Tactics.intro_move (Some id) MoveFirst ]
| [ "intro" ident(id) "at" "bottom" ] -> [ Tactics.intro_move (Some id) MoveLast ]
| [ "intro" ident(id) "after" hyp(h) ] -> [ Tactics.intro_move (Some id) (MoveAfter h) ]
| [ "intro" ident(id) "before" hyp(h) ] -> [ Tactics.intro_move (Some id) (MoveBefore h) ]
| [ "intro" "at" "top" ] -> [ Tactics.intro_move None MoveFirst ]
| [ "intro" "at" "bottom" ] -> [ Tactics.intro_move None MoveLast ]
| [ "intro" "after" hyp(h) ] -> [ Tactics.intro_move None (MoveAfter h) ]
| [ "intro" "before" hyp(h) ] -> [ Tactics.intro_move None (MoveBefore h) ]
END

(** Move *)

TACTIC EXTEND move
  [ "move" hyp(id) "at" "top" ] -> [ Tactics.move_hyp id MoveFirst ]
| [ "move" hyp(id) "at" "bottom" ] -> [ Tactics.move_hyp id MoveLast ]
| [ "move" hyp(id) "after" hyp(h) ] -> [ Tactics.move_hyp id (MoveAfter h) ]
| [ "move" hyp(id) "before" hyp(h) ] -> [ Tactics.move_hyp id (MoveBefore h) ]
END

(** Rename *)

TACTIC EXTEND rename
| [ "rename" ne_rename_list_sep(ids, ",") ] -> [ Tactics.rename_hyp ids ]
END

(** Revert *)

TACTIC EXTEND revert
  [ "revert" ne_hyp_list(hl) ] -> [ Tactics.revert hl ]
END

(** Simple induction / destruct *)

let simple_induct h =
  Tacticals.New.tclTHEN (Tactics.intros_until h)
    (Tacticals.New.onLastHyp Tactics.simplest_elim)

TACTIC EXTEND simple_induction
  [ "simple" "induction" quantified_hypothesis(h) ] -> [ simple_induct h ]
END

let simple_destruct h =
  Tacticals.New.tclTHEN (Tactics.intros_until h)
    (Tacticals.New.onLastHyp Tactics.simplest_case)

TACTIC EXTEND simple_destruct
  [ "simple" "destruct" quantified_hypothesis(h) ] -> [ simple_destruct h ]
END

(** Double induction *)

TACTIC EXTEND double_induction
  [ "double" "induction" quantified_hypothesis(h1) quantified_hypothesis(h2) ] ->
  [ Elim.h_double_induction h1 h2 ]
END

(* Admit *)

TACTIC EXTEND admit
 [ "admit" ] -> [ Proofview.give_up ]
END

(* Fix *)

TACTIC EXTEND fix
  [ "fix" ident(id) natural(n) ] -> [ Tactics.fix id n ]
END

(* Cofix *)

TACTIC EXTEND cofix
  [ "cofix" ident(id) ] -> [ Tactics.cofix id ]
END

(* Clear *)

TACTIC EXTEND clear
  [ "clear" hyp_list(ids) ] -> [
    if List.is_empty ids then Tactics.keep []
    else Tactics.clear ids
  ]
| [ "clear" "-" ne_hyp_list(ids) ] -> [ Tactics.keep ids ]
END

(* Clearbody *)

TACTIC EXTEND clearbody
  [ "clearbody" ne_hyp_list(ids) ] -> [ Tactics.clear_body ids ]
END

(* Generalize dependent *)

TACTIC EXTEND generalize_dependent
  [ "generalize" "dependent" constr(c) ] -> [ Tactics.generalize_dep c ]
END

(* Table of "pervasives" macros tactics (e.g. auto, simpl, etc.) *)

open Tacexpr

let initial_atomic () =
  let nocl = {onhyps=Some[];concl_occs=AllOccurrences} in
  let iter (s, t) =
    let body = TacAtom (Loc.tag t) in
    Tacenv.register_ltac false false (Names.Id.of_string s) body
  in
  let () = List.iter iter
      [ "red", TacReduce(Red false,nocl);
        "hnf", TacReduce(Hnf,nocl);
        "simpl", TacReduce(Simpl (Redops.all_flags,None),nocl);
        "compute", TacReduce(Cbv Redops.all_flags,nocl);
        "intros", TacIntroPattern (false,[]);
      ]
  in
  let iter (s, t) = Tacenv.register_ltac false false (Names.Id.of_string s) t in
  List.iter iter
      [ "idtac",TacId [];
        "fail", TacFail(TacLocal,ArgArg 0,[]);
        "fresh", TacArg(Loc.tag @@ TacFreshId [])
      ]

let () = Mltop.declare_cache_obj initial_atomic "ltac_plugin"

(* First-class Ltac access to primitive blocks *)

let initial_name s = { mltac_plugin = "ltac_plugin"; mltac_tactic = s; }
let initial_entry s = { mltac_name = initial_name s; mltac_index = 0; }

let register_list_tactical name f =
  let tac args ist = match args with
  | [v] ->
    begin match Tacinterp.Value.to_list v with
    | None -> Tacticals.New.tclZEROMSG (Pp.str "Expected a list")
    | Some tacs ->
      let tacs = List.map (fun tac -> Tacinterp.tactic_of_value ist tac) tacs in
      f tacs
    end
  | _ -> assert false
  in
  Tacenv.register_ml_tactic (initial_name name) [|tac|]

let () = register_list_tactical "first" Tacticals.New.tclFIRST
let () = register_list_tactical "solve" Tacticals.New.tclSOLVE

let initial_tacticals () =
  let idn n = Id.of_string (Printf.sprintf "_%i" n) in
  let varn n = Reference (ArgVar (CAst.make (idn n))) in
  let iter (s, t) = Tacenv.register_ltac false false (Id.of_string s) t in
  List.iter iter [
    "first", TacFun ([Name (idn 0)], TacML (None, (initial_entry "first", [varn 0])));
    "solve", TacFun ([Name (idn 0)], TacML (None, (initial_entry "solve", [varn 0])));
  ]

let () = Mltop.declare_cache_obj initial_tacticals "ltac_plugin"