forked from coq/coq
-
Notifications
You must be signed in to change notification settings - Fork 2
/
tac2core.ml
2322 lines (2024 loc) · 74.8 KB
/
tac2core.ml
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
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(************************************************************************)
(* * The Coq Proof Assistant / The Coq Development Team *)
(* v * Copyright INRIA, CNRS and contributors *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(* \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 Pp
open Names
open Genarg
open Tac2env
open Tac2expr
open Tac2entries.Pltac
open Proofview.Notations
let ltac2_plugin = "coq-core.plugins.ltac2"
let constr_flags =
let open Pretyping in
{
use_coercions = true;
use_typeclasses = Pretyping.UseTC;
solve_unification_constraints = true;
fail_evar = true;
expand_evars = true;
program_mode = false;
polymorphic = false;
}
let open_constr_no_classes_flags =
let open Pretyping in
{
use_coercions = true;
use_typeclasses = Pretyping.NoUseTC;
solve_unification_constraints = true;
fail_evar = false;
expand_evars = true;
program_mode = false;
polymorphic = false;
}
(** Standard values *)
module Value = Tac2ffi
open Value
let val_format = Tac2print.val_format
let format = repr_ext val_format
let core_prefix path n = KerName.make path (Label.of_id (Id.of_string_soft n))
let std_core n = core_prefix Tac2env.std_prefix n
let coq_core n = core_prefix Tac2env.coq_prefix n
let ltac1_core n = core_prefix Tac2env.ltac1_prefix n
module Core =
struct
let t_int = coq_core "int"
let t_string = coq_core "string"
let t_array = coq_core "array"
let t_unit = coq_core "unit"
let t_list = coq_core "list"
let t_constr = coq_core "constr"
let t_preterm = coq_core "preterm"
let t_pattern = coq_core "pattern"
let t_ident = coq_core "ident"
let t_option = coq_core "option"
let t_exn = coq_core "exn"
let t_reference = std_core "reference"
let t_ltac1 = ltac1_core "t"
let c_nil = coq_core "[]"
let c_cons = coq_core "::"
let c_none = coq_core "None"
let c_some = coq_core "Some"
let c_true = coq_core "true"
let c_false = coq_core "false"
end
open Core
let v_unit = Value.of_unit ()
let v_blk = Valexpr.make_block
let of_relevance = function
| Sorts.Relevant -> ValInt 0
| Sorts.Irrelevant -> ValInt 1
| Sorts.RelevanceVar q -> ValInt 0 (* FIXME ? *)
let to_relevance = function
| ValInt 0 -> Sorts.Relevant
| ValInt 1 -> Sorts.Irrelevant
| _ -> assert false
let relevance = make_repr of_relevance to_relevance
let of_binder b =
Value.of_ext Value.val_binder b
let to_binder b =
Value.to_ext Value.val_binder b
let of_instance u =
let u = Univ.Instance.to_array (EConstr.Unsafe.to_instance u) in
Value.of_array (fun v -> Value.of_ext Value.val_univ v) u
let to_instance u =
let u = Value.to_array (fun v -> Value.to_ext Value.val_univ v) u in
EConstr.EInstance.make (Univ.Instance.of_array u)
let of_rec_declaration (nas, ts, cs) =
let binders = Array.map2 (fun na t -> (na, t)) nas ts in
(Value.of_array of_binder binders,
Value.of_array Value.of_constr cs)
let to_rec_declaration (nas, cs) =
let nas = Value.to_array to_binder nas in
(Array.map fst nas,
Array.map snd nas,
Value.to_array Value.to_constr cs)
let of_case_invert = let open Constr in function
| NoInvert -> ValInt 0
| CaseInvert {indices} ->
v_blk 0 [|of_array of_constr indices|]
let to_case_invert = let open Constr in function
| ValInt 0 -> NoInvert
| ValBlk (0, [|indices|]) ->
let indices = to_array to_constr indices in
CaseInvert {indices}
| _ -> CErrors.anomaly Pp.(str "unexpected value shape")
let of_result f = function
| Inl c -> v_blk 0 [|f c|]
| Inr e -> v_blk 1 [|Value.of_exn e|]
(** Stdlib exceptions *)
let err_notfocussed =
Tac2interp.LtacError (coq_core "Not_focussed", [||])
let err_outofbounds =
Tac2interp.LtacError (coq_core "Out_of_bounds", [||])
let err_notfound =
Tac2interp.LtacError (coq_core "Not_found", [||])
let err_matchfailure =
Tac2interp.LtacError (coq_core "Match_failure", [||])
let err_division_by_zero =
Tac2interp.LtacError (coq_core "Division_by_zero", [||])
(** Helper functions *)
let thaw f = Tac2ffi.apply f [v_unit]
let fatal_flag : unit Exninfo.t = Exninfo.make ()
let has_fatal_flag info = match Exninfo.get info fatal_flag with
| None -> false
| Some () -> true
let set_bt info =
if !Tac2bt.print_ltac2_backtrace then
Tac2bt.get_backtrace >>= fun bt ->
Proofview.tclUNIT (Exninfo.add info Tac2entries.backtrace bt)
else Proofview.tclUNIT info
let throw ?(info = Exninfo.null) e =
set_bt info >>= fun info ->
let info = Exninfo.add info fatal_flag () in
Proofview.tclLIFT (Proofview.NonLogical.raise (e, info))
let fail ?(info = Exninfo.null) e =
set_bt info >>= fun info ->
Proofview.tclZERO ~info e
let return x = Proofview.tclUNIT x
let pname ?(plugin=ltac2_plugin) s = { mltac_plugin = plugin; mltac_tactic = s }
let wrap f =
return () >>= fun () -> return (f ())
let wrap_unit f =
return () >>= fun () -> f (); return v_unit
let catchable_exception = function
| Logic_monad.Exception _ -> false
| e -> CErrors.noncritical e
(* Adds ltac2 backtrace
With [passthrough:false], acts like [Proofview.wrap_exceptions] + Ltac2 backtrace handling
*)
let wrap_exceptions ?(passthrough=false) f =
try f ()
with e ->
let e, info = Exninfo.capture e in
set_bt info >>= fun info ->
if not passthrough && catchable_exception e
then begin if has_fatal_flag info
then Proofview.tclLIFT (Proofview.NonLogical.raise (e, info))
else Proofview.tclZERO ~info e
end
else Exninfo.iraise (e, info)
let assert_focussed =
Proofview.Goal.goals >>= fun gls ->
match gls with
| [_] -> Proofview.tclUNIT ()
| [] | _ :: _ :: _ -> throw err_notfocussed
let pf_apply ?(catch_exceptions=false) f =
let f env sigma = wrap_exceptions ~passthrough:(not catch_exceptions) (fun () -> f env sigma) in
Proofview.Goal.goals >>= function
| [] ->
Proofview.tclENV >>= fun env ->
Proofview.tclEVARMAP >>= fun sigma ->
f env sigma
| [gl] ->
gl >>= fun gl ->
f (Proofview.Goal.env gl) (Tacmach.project gl)
| _ :: _ :: _ ->
throw err_notfocussed
(** Primitives *)
let define_primitive ?plugin name arity f =
Tac2env.define_primitive (pname ?plugin name) (mk_closure_val arity f)
let defineval ?plugin name v = Tac2env.define_primitive (pname ?plugin name) v
let define0 ?plugin name f = define_primitive ?plugin name arity_one (fun _ -> f)
let define1 name r0 f = define_primitive name arity_one begin fun x ->
f (Value.repr_to r0 x)
end
let define2 name r0 r1 f = define_primitive name (arity_suc arity_one) begin fun x y ->
f (Value.repr_to r0 x) (Value.repr_to r1 y)
end
let define_equality name r eq = define2 name r r begin fun x y ->
return (Value.of_bool (eq x y))
end
let define3 name r0 r1 r2 f = define_primitive name (arity_suc (arity_suc arity_one)) begin fun x y z ->
f (Value.repr_to r0 x) (Value.repr_to r1 y) (Value.repr_to r2 z)
end
let define4 name r0 r1 r2 r3 f = define_primitive name (arity_suc (arity_suc (arity_suc arity_one))) begin fun x0 x1 x2 x3 ->
f (Value.repr_to r0 x0) (Value.repr_to r1 x1) (Value.repr_to r2 x2) (Value.repr_to r3 x3)
end
let define5 name r0 r1 r2 r3 r4 f = define_primitive name (arity_suc (arity_suc (arity_suc (arity_suc arity_one)))) begin fun x0 x1 x2 x3 x4 ->
f (Value.repr_to r0 x0) (Value.repr_to r1 x1) (Value.repr_to r2 x2) (Value.repr_to r3 x3) (Value.repr_to r4 x4)
end
(** Printing *)
let () = define1 "print" pp begin fun pp ->
wrap_unit (fun () -> Feedback.msg_notice pp)
end
let () = define1 "message_of_int" int begin fun n ->
return (Value.of_pp (Pp.int n))
end
let () = define1 "message_of_string" string begin fun s ->
return (Value.of_pp (str s))
end
let () = define1 "message_to_string" pp begin fun pp ->
return (Value.of_string (Pp.string_of_ppcmds pp))
end
let () = define1 "message_of_constr" constr begin fun c ->
pf_apply begin fun env sigma ->
let pp = Printer.pr_econstr_env env sigma c in
return (Value.of_pp pp)
end
end
let () = define1 "message_of_ident" ident begin fun c ->
let pp = Id.print c in
return (Value.of_pp pp)
end
let () = define1 "message_of_exn" valexpr begin fun v ->
Proofview.tclENV >>= fun env ->
Proofview.tclEVARMAP >>= fun sigma ->
let pp = Tac2print.pr_valexpr env sigma v (GTypRef (Other Core.t_exn, [])) in
return (Value.of_pp pp)
end
let () = define2 "message_concat" pp pp begin fun m1 m2 ->
return (Value.of_pp (Pp.app m1 m2))
end
let () = define0 "format_stop" begin
return (Value.of_ext val_format [])
end
let () = define1 "format_string" format begin fun s ->
return (Value.of_ext val_format (Tac2print.FmtString :: s))
end
let () = define1 "format_int" format begin fun s ->
return (Value.of_ext val_format (Tac2print.FmtInt :: s))
end
let () = define1 "format_constr" format begin fun s ->
return (Value.of_ext val_format (Tac2print.FmtConstr :: s))
end
let () = define1 "format_ident" format begin fun s ->
return (Value.of_ext val_format (Tac2print.FmtIdent :: s))
end
let () = define2 "format_literal" string format begin fun lit s ->
return (Value.of_ext val_format (Tac2print.FmtLiteral lit :: s))
end
let () = define1 "format_alpha" format begin fun s ->
return (Value.of_ext val_format (Tac2print.FmtAlpha :: s))
end
let () = define2 "format_kfprintf" closure format begin fun k fmt ->
let open Tac2print in
let fold accu = function
| FmtLiteral _ -> accu
| FmtString | FmtInt | FmtConstr | FmtIdent -> 1 + accu
| FmtAlpha -> 2 + accu
in
let pop1 l = match l with [] -> assert false | x :: l -> (x, l) in
let pop2 l = match l with [] | [_] -> assert false | x :: y :: l -> (x, y, l) in
let arity = List.fold_left fold 0 fmt in
let rec eval accu args fmt = match fmt with
| [] -> apply k [of_pp accu]
| tag :: fmt ->
match tag with
| FmtLiteral s ->
eval (Pp.app accu (Pp.str s)) args fmt
| FmtString ->
let (s, args) = pop1 args in
let pp = Pp.str (to_string s) in
eval (Pp.app accu pp) args fmt
| FmtInt ->
let (i, args) = pop1 args in
let pp = Pp.int (to_int i) in
eval (Pp.app accu pp) args fmt
| FmtConstr ->
let (c, args) = pop1 args in
let c = to_constr c in
pf_apply begin fun env sigma ->
let pp = Printer.pr_econstr_env env sigma c in
eval (Pp.app accu pp) args fmt
end
| FmtIdent ->
let (i, args) = pop1 args in
let pp = Id.print (to_ident i) in
eval (Pp.app accu pp) args fmt
| FmtAlpha ->
let (f, x, args) = pop2 args in
Tac2ffi.apply (to_closure f) [of_unit (); x] >>= fun pp ->
eval (Pp.app accu (to_pp pp)) args fmt
in
let eval v = eval (Pp.mt ()) v fmt in
if Int.equal arity 0 then eval []
else return (Tac2ffi.of_closure (Tac2ffi.abstract arity eval))
end
(** Array *)
let () = define0 "array_empty" begin
return (v_blk 0 (Array.of_list []))
end
let () = define2 "array_make" int valexpr begin fun n x ->
if n < 0 || n > Sys.max_array_length then throw err_outofbounds
else wrap (fun () -> v_blk 0 (Array.make n x))
end
let () = define1 "array_length" block begin fun (_, v) ->
return (Value.of_int (Array.length v))
end
let () = define3 "array_set" block int valexpr begin fun (_, v) n x ->
if n < 0 || n >= Array.length v then throw err_outofbounds
else wrap_unit (fun () -> v.(n) <- x)
end
let () = define2 "array_get" block int begin fun (_, v) n ->
if n < 0 || n >= Array.length v then throw err_outofbounds
else wrap (fun () -> v.(n))
end
let () = define5 "array_blit" block int block int int begin fun (_, v0) s0 (_, v1) s1 l ->
if s0 < 0 || s0+l > Array.length v0 || s1 < 0 || s1+l > Array.length v1 || l<0 then throw err_outofbounds
else wrap_unit (fun () -> Array.blit v0 s0 v1 s1 l)
end
let () = define4 "array_fill" block int int valexpr begin fun (_, d) s l v ->
if s < 0 || s+l > Array.length d || l<0 then throw err_outofbounds
else wrap_unit (fun () -> Array.fill d s l v)
end
let () = define1 "array_concat" (list block) begin fun l ->
wrap (fun () -> v_blk 0 (Array.concat (List.map snd l)))
end
(** Ident *)
let () = define2 "ident_equal" ident ident begin fun id1 id2 ->
return (Value.of_bool (Id.equal id1 id2))
end
let () = define1 "ident_to_string" ident begin fun id ->
return (Value.of_string (Id.to_string id))
end
let () = define1 "ident_of_string" string begin fun s ->
let id = try Some (Id.of_string s) with _ -> None in
return (Value.of_option Value.of_ident id)
end
(** Int *)
let () = define2 "int_equal" int int begin fun m n ->
return (Value.of_bool (m == n))
end
let unop n f = define1 n int begin fun m ->
return (Value.of_int (f m))
end
let binop n f = define2 n int int begin fun m n ->
return (Value.of_int (f m n))
end
let () = binop "int_compare" Int.compare
let () = binop "int_add" (+)
let () = binop "int_sub" (-)
let () = binop "int_mul" ( * )
let () = define2 "int_div" int int begin fun m n ->
if n == 0 then throw err_division_by_zero
else return (Value.of_int (m / n))
end
let () = define2 "int_mod" int int begin fun m n ->
if n == 0 then throw err_division_by_zero
else return (Value.of_int (m mod n))
end
let () = unop "int_neg" (~-)
let () = unop "int_abs" abs
let () = binop "int_asr" (asr)
let () = binop "int_lsl" (lsl)
let () = binop "int_lsr" (lsr)
let () = binop "int_land" (land)
let () = binop "int_lor" (lor)
let () = binop "int_lxor" (lxor)
let () = unop "int_lnot" lnot
(** Char *)
let () = define1 "char_of_int" int begin fun n ->
wrap (fun () -> Value.of_char (Char.chr n))
end
let () = define1 "char_to_int" char begin fun n ->
wrap (fun () -> Value.of_int (Char.code n))
end
(** String *)
let () = define2 "string_make" int char begin fun n c ->
if n < 0 || n > Sys.max_string_length then throw err_outofbounds
else wrap (fun () -> Value.of_bytes (Bytes.make n c))
end
let () = define1 "string_length" bytes begin fun s ->
return (Value.of_int (Bytes.length s))
end
let () = define3 "string_set" bytes int char begin fun s n c ->
if n < 0 || n >= Bytes.length s then throw err_outofbounds
else wrap_unit (fun () -> Bytes.set s n c)
end
let () = define2 "string_get" bytes int begin fun s n ->
if n < 0 || n >= Bytes.length s then throw err_outofbounds
else wrap (fun () -> Value.of_char (Bytes.get s n))
end
let () = define2 "string_concat" bytes (list bytes) begin fun sep l ->
return (Value.of_bytes (Bytes.concat sep l))
end
let () = define2 "string_app" bytes bytes begin fun a b ->
return (Value.of_bytes (Bytes.concat Bytes.empty [a; b]))
end
let () = define2 "string_equal" bytes bytes begin fun a b ->
return (Value.of_bool (Bytes.equal a b))
end
let () = define2 "string_compare" bytes bytes begin fun a b ->
return (Value.of_int (Bytes.compare a b))
end
(** Terms *)
(** constr -> constr *)
let () = define1 "constr_type" constr begin fun c ->
let get_type env sigma =
let (sigma, t) = Typing.type_of env sigma c in
let t = Value.of_constr t in
Proofview.Unsafe.tclEVARS sigma <*> Proofview.tclUNIT t
in
pf_apply ~catch_exceptions:true get_type
end
(** constr -> constr *)
let () = define2 "constr_equal" constr constr begin fun c1 c2 ->
Proofview.tclEVARMAP >>= fun sigma ->
let b = EConstr.eq_constr sigma c1 c2 in
Proofview.tclUNIT (Value.of_bool b)
end
let () = define1 "constr_kind" constr begin fun c ->
let open Constr in
Proofview.tclEVARMAP >>= fun sigma ->
Proofview.tclENV >>= fun env ->
return begin match EConstr.kind sigma c with
| Rel n ->
v_blk 0 [|Value.of_int n|]
| Var id ->
v_blk 1 [|Value.of_ident id|]
| Meta n ->
v_blk 2 [|Value.of_int n|]
| Evar (evk, args) ->
let args = Evd.expand_existential sigma (evk, args) in
v_blk 3 [|
Value.of_evar evk;
Value.of_array Value.of_constr (Array.of_list args);
|]
| Sort s ->
v_blk 4 [|Value.of_ext Value.val_sort s|]
| Cast (c, k, t) ->
v_blk 5 [|
Value.of_constr c;
Value.of_ext Value.val_cast k;
Value.of_constr t;
|]
| Prod (na, t, u) ->
v_blk 6 [|
of_binder (na, t);
Value.of_constr u;
|]
| Lambda (na, t, c) ->
v_blk 7 [|
of_binder (na, t);
Value.of_constr c;
|]
| LetIn (na, b, t, c) ->
v_blk 8 [|
of_binder (na, t);
Value.of_constr b;
Value.of_constr c;
|]
| App (c, cl) ->
v_blk 9 [|
Value.of_constr c;
Value.of_array Value.of_constr cl;
|]
| Const (cst, u) ->
v_blk 10 [|
Value.of_constant cst;
of_instance u;
|]
| Ind (ind, u) ->
v_blk 11 [|
Value.of_ext Value.val_inductive ind;
of_instance u;
|]
| Construct (cstr, u) ->
v_blk 12 [|
Value.of_ext Value.val_constructor cstr;
of_instance u;
|]
| Case (ci, u, pms, c, iv, t, bl) ->
(* FIXME: also change representation Ltac2-side? *)
let (ci, c, iv, t, bl) = EConstr.expand_case env sigma (ci, u, pms, c, iv, t, bl) in
v_blk 13 [|
Value.of_ext Value.val_case ci;
Value.of_constr c;
of_case_invert iv;
Value.of_constr t;
Value.of_array Value.of_constr bl;
|]
| Fix ((recs, i), def) ->
let (nas, cs) = of_rec_declaration def in
v_blk 14 [|
Value.of_array Value.of_int recs;
Value.of_int i;
nas;
cs;
|]
| CoFix (i, def) ->
let (nas, cs) = of_rec_declaration def in
v_blk 15 [|
Value.of_int i;
nas;
cs;
|]
| Proj (p, c) ->
v_blk 16 [|
Value.of_ext Value.val_projection p;
Value.of_constr c;
|]
| Int n ->
v_blk 17 [|Value.of_uint63 n|]
| Float f ->
v_blk 18 [|Value.of_float f|]
| Array(u,t,def,ty) ->
v_blk 19 [|of_instance u; Value.of_array Value.of_constr t; Value.of_constr def; Value.of_constr ty|]
end
end
let () = define1 "constr_make" valexpr begin fun knd ->
Proofview.tclEVARMAP >>= fun sigma ->
Proofview.tclENV >>= fun env ->
let c = match Tac2ffi.to_block knd with
| (0, [|n|]) ->
let n = Value.to_int n in
EConstr.mkRel n
| (1, [|id|]) ->
let id = Value.to_ident id in
EConstr.mkVar id
| (2, [|n|]) ->
let n = Value.to_int n in
EConstr.mkMeta n
| (3, [|evk; args|]) ->
let evk = to_evar evk in
let args = Value.to_array Value.to_constr args in
EConstr.mkLEvar sigma (evk, Array.to_list args)
| (4, [|s|]) ->
let s = Value.to_ext Value.val_sort s in
EConstr.mkSort s
| (5, [|c; k; t|]) ->
let c = Value.to_constr c in
let k = Value.to_ext Value.val_cast k in
let t = Value.to_constr t in
EConstr.mkCast (c, k, t)
| (6, [|na; u|]) ->
let (na, t) = to_binder na in
let u = Value.to_constr u in
EConstr.mkProd (na, t, u)
| (7, [|na; c|]) ->
let (na, t) = to_binder na in
let u = Value.to_constr c in
EConstr.mkLambda (na, t, u)
| (8, [|na; b; c|]) ->
let (na, t) = to_binder na in
let b = Value.to_constr b in
let c = Value.to_constr c in
EConstr.mkLetIn (na, b, t, c)
| (9, [|c; cl|]) ->
let c = Value.to_constr c in
let cl = Value.to_array Value.to_constr cl in
EConstr.mkApp (c, cl)
| (10, [|cst; u|]) ->
let cst = Value.to_constant cst in
let u = to_instance u in
EConstr.mkConstU (cst, u)
| (11, [|ind; u|]) ->
let ind = Value.to_ext Value.val_inductive ind in
let u = to_instance u in
EConstr.mkIndU (ind, u)
| (12, [|cstr; u|]) ->
let cstr = Value.to_ext Value.val_constructor cstr in
let u = to_instance u in
EConstr.mkConstructU (cstr, u)
| (13, [|ci; c; iv; t; bl|]) ->
let ci = Value.to_ext Value.val_case ci in
let c = Value.to_constr c in
let iv = to_case_invert iv in
let t = Value.to_constr t in
let bl = Value.to_array Value.to_constr bl in
EConstr.mkCase (EConstr.contract_case env sigma (ci, c, iv, t, bl))
| (14, [|recs; i; nas; cs|]) ->
let recs = Value.to_array Value.to_int recs in
let i = Value.to_int i in
let def = to_rec_declaration (nas, cs) in
EConstr.mkFix ((recs, i), def)
| (15, [|i; nas; cs|]) ->
let i = Value.to_int i in
let def = to_rec_declaration (nas, cs) in
EConstr.mkCoFix (i, def)
| (16, [|p; c|]) ->
let p = Value.to_ext Value.val_projection p in
let c = Value.to_constr c in
EConstr.mkProj (p, c)
| (17, [|n|]) ->
let n = Value.to_uint63 n in
EConstr.mkInt n
| (18, [|f|]) ->
let f = Value.to_float f in
EConstr.mkFloat f
| (19, [|u;t;def;ty|]) ->
let t = Value.to_array Value.to_constr t in
let def = Value.to_constr def in
let ty = Value.to_constr ty in
let u = to_instance u in
EConstr.mkArray(u,t,def,ty)
| _ -> assert false
in
return (Value.of_constr c)
end
let () = define1 "constr_check" constr begin fun c ->
pf_apply begin fun env sigma ->
try
let (sigma, _) = Typing.type_of env sigma c in
Proofview.Unsafe.tclEVARS sigma >>= fun () ->
return (of_result Value.of_constr (Inl c))
with e when CErrors.noncritical e ->
let e = Exninfo.capture e in
return (of_result Value.of_constr (Inr e))
end
end
let () = define3 "constr_liftn" int int constr begin fun n k c ->
let ans = EConstr.Vars.liftn n k c in
return (Value.of_constr ans)
end
let () = define3 "constr_substnl" (list constr) int constr begin fun subst k c ->
let ans = EConstr.Vars.substnl subst k c in
return (Value.of_constr ans)
end
let () = define3 "constr_closenl" (list ident) int constr begin fun ids k c ->
Proofview.tclEVARMAP >>= fun sigma ->
let ans = EConstr.Vars.substn_vars sigma k ids c in
return (Value.of_constr ans)
end
let () = define2 "constr_closedn" int constr begin fun n c ->
Proofview.tclEVARMAP >>= fun sigma ->
let ans = EConstr.Vars.closedn sigma n c in
return (Value.of_bool ans)
end
let () = define3 "constr_occur_between" int int constr begin fun n m c ->
Proofview.tclEVARMAP >>= fun sigma ->
let ans = EConstr.Vars.noccur_between sigma n m c in
return (Value.of_bool (not ans))
end
let () = define1 "constr_case" (repr_ext val_inductive) begin fun ind ->
Proofview.tclENV >>= fun env ->
try
let ans = Inductiveops.make_case_info env ind Sorts.Relevant Constr.RegularStyle in
return (Value.of_ext Value.val_case ans)
with e when CErrors.noncritical e ->
throw err_notfound
end
let () = defineval "constr_cast_default" (of_cast DEFAULTcast)
let () = defineval "constr_cast_vm" (of_cast VMcast)
let () = defineval "constr_cast_native" (of_cast NATIVEcast)
let () = define2 "constr_constructor" (repr_ext val_inductive) int begin fun (ind, i) k ->
Proofview.tclENV >>= fun env ->
try
let open Declarations in
let ans = Environ.lookup_mind ind env in
let _ = ans.mind_packets.(i).mind_consnames.(k) in
return (Value.of_ext val_constructor ((ind, i), (k + 1)))
with e when CErrors.noncritical e ->
throw err_notfound
end
let () = define3 "constr_in_context" ident constr closure begin fun id t c ->
Proofview.Goal.goals >>= function
| [gl] ->
gl >>= fun gl ->
let env = Proofview.Goal.env gl in
let sigma = Proofview.Goal.sigma gl in
let has_var =
try
let _ = Environ.lookup_named id env in
true
with Not_found -> false
in
if has_var then
Tacticals.tclZEROMSG (str "Variable already exists")
else
let open Context.Named.Declaration in
let sigma, t_rel =
let t_ty = Retyping.get_type_of env sigma t in
(* If the user passed eg ['_] for the type we force it to indeed be a type *)
let sigma, j = Typing.type_judgment env sigma {uj_val=t; uj_type=t_ty} in
sigma, EConstr.ESorts.relevance_of_sort sigma j.utj_type
in
let nenv = EConstr.push_named (LocalAssum (Context.make_annot id t_rel, t)) env in
let (sigma, (evt, _)) = Evarutil.new_type_evar nenv sigma Evd.univ_flexible in
let (sigma, evk) = Evarutil.new_pure_evar (Environ.named_context_val nenv) sigma evt in
Proofview.Unsafe.tclEVARS sigma >>= fun () ->
Proofview.Unsafe.tclSETGOALS [Proofview.with_empty_state evk] >>= fun () ->
thaw c >>= fun _ ->
Proofview.Unsafe.tclSETGOALS [Proofview.with_empty_state (Proofview.Goal.goal gl)] >>= fun () ->
let args = EConstr.identity_subst_val (Environ.named_context_val env) in
let args = SList.cons (EConstr.mkRel 1) args in
let ans = EConstr.mkEvar (evk, args) in
let ans = EConstr.mkLambda (Context.make_annot (Name id) t_rel, t, ans) in
return (Value.of_constr ans)
| _ ->
throw err_notfocussed
end
(** preterm -> constr *)
let () = define1 "constr_pretype" (repr_ext val_preterm) begin fun c ->
let open Pretyping in
let open Ltac_pretype in
let pretype env sigma =
(* For now there are no primitives to create preterms with a non-empty
closure. I do not know whether [closed_glob_constr] is really the type
we want but it does not hurt in the meantime. *)
let { closure; term } = c in
let vars = {
ltac_constrs = closure.typed;
ltac_uconstrs = closure.untyped;
ltac_idents = closure.idents;
ltac_genargs = closure.genargs;
} in
let flags = constr_flags in
let sigma, t = understand_ltac flags env sigma vars WithoutTypeConstraint term in
let t = Value.of_constr t in
Proofview.Unsafe.tclEVARS sigma <*> Proofview.tclUNIT t
in
pf_apply ~catch_exceptions:true pretype
end
let () = define2 "constr_binder_make" (option ident) constr begin fun na ty ->
pf_apply begin fun env sigma ->
match Retyping.relevance_of_type env sigma ty with
| rel ->
let na = match na with None -> Anonymous | Some id -> Name id in
return (Value.of_ext val_binder (Context.make_annot na rel, ty))
| exception (Retyping.RetypeError _ as e) ->
let e, info = Exninfo.capture e in
fail ~info (CErrors.UserError Pp.(str "Not a type."))
end
end
let () = define3 "constr_binder_unsafe_make" (option ident) relevance constr begin fun na rel ty ->
let na = match na with None -> Anonymous | Some id -> Name id in
return (Value.of_ext val_binder (Context.make_annot na rel, ty))
end
let () = define1 "constr_binder_name" (repr_ext val_binder) begin fun (bnd, _) ->
let na = match bnd.Context.binder_name with Anonymous -> None | Name id -> Some id in
return (Value.of_option Value.of_ident na)
end
let () = define1 "constr_binder_type" (repr_ext val_binder) begin fun (bnd, ty) ->
return (of_constr ty)
end
let () = define1 "constr_has_evar" constr begin fun c ->
Proofview.tclEVARMAP >>= fun sigma ->
let b = Evarutil.has_undefined_evars sigma c in
Proofview.tclUNIT (Value.of_bool b)
end
(** Extra equalities *)
let () = define_equality "evar_equal" evar Evar.equal
let () = define_equality "float_equal" float Float64.equal
let () = define_equality "uint63_equal" uint63 Uint63.equal
let () = define_equality "meta_equal" int Int.equal
let () = define_equality "constr_cast_equal" cast Glob_ops.cast_kind_eq
let () = define_equality "constant_equal" constant Constant.UserOrd.equal
let () = define_equality "constr_case_equal" (repr_ext val_case) begin fun x y ->
Ind.UserOrd.equal x.ci_ind y.ci_ind && Sorts.relevance_equal x.ci_relevance y.ci_relevance
end
let () = define_equality "constructor_equal" (repr_ext val_constructor) Construct.UserOrd.equal
let () = define_equality "projection_equal" (repr_ext val_projection) Projection.UserOrd.equal
(** Patterns *)
let empty_context = Constr_matching.empty_context
let () = define0 "pattern_empty_context" begin
return (Value.of_ext val_matching_context empty_context)
end
let () = define2 "pattern_matches" pattern constr begin fun pat c ->
pf_apply begin fun env sigma ->
let ans =
try Some (Constr_matching.matches env sigma pat c)
with Constr_matching.PatternMatchingFailure -> None
in
begin match ans with
| None -> fail err_matchfailure
| Some ans ->
let ans = Id.Map.bindings ans in
let of_pair (id, c) = Value.of_tuple [| Value.of_ident id; Value.of_constr c |] in
return (Value.of_list of_pair ans)
end
end
end
let () = define2 "pattern_matches_subterm" pattern constr begin fun pat c ->
let open Constr_matching in
let rec of_ans s = match IStream.peek s with
| IStream.Nil -> fail err_matchfailure
| IStream.Cons ({ m_sub = (_, sub); m_ctx }, s) ->
let ans = Id.Map.bindings sub in
let of_pair (id, c) = Value.of_tuple [| Value.of_ident id; Value.of_constr c |] in
let ans = Value.of_tuple [| Value.of_ext val_matching_context m_ctx; Value.of_list of_pair ans |] in
Proofview.tclOR (return ans) (fun _ -> of_ans s)
in
pf_apply begin fun env sigma ->
let pat = Constr_matching.instantiate_pattern env sigma Id.Map.empty pat in
let ans = Constr_matching.match_subterm env sigma (Id.Set.empty,pat) c in
of_ans ans
end
end
let () = define2 "pattern_matches_vect" pattern constr begin fun pat c ->
pf_apply begin fun env sigma ->
let ans =
try Some (Constr_matching.matches env sigma pat c)
with Constr_matching.PatternMatchingFailure -> None
in
begin match ans with
| None -> fail err_matchfailure
| Some ans ->
let ans = Id.Map.bindings ans in
let ans = Array.map_of_list snd ans in
return (Value.of_array Value.of_constr ans)
end
end
end
let () = define2 "pattern_matches_subterm_vect" pattern constr begin fun pat c ->
let open Constr_matching in
let rec of_ans s = match IStream.peek s with
| IStream.Nil -> fail err_matchfailure
| IStream.Cons ({ m_sub = (_, sub); m_ctx }, s) ->
let ans = Id.Map.bindings sub in
let ans = Array.map_of_list snd ans in
let ans = Value.of_tuple [| Value.of_ext val_matching_context m_ctx; Value.of_array Value.of_constr ans |] in
Proofview.tclOR (return ans) (fun _ -> of_ans s)
in
pf_apply begin fun env sigma ->
let pat = Constr_matching.instantiate_pattern env sigma Id.Map.empty pat in
let ans = Constr_matching.match_subterm env sigma (Id.Set.empty,pat) c in
of_ans ans
end
end
let match_pattern = map_repr
(fun (b,pat) -> if b then Tac2match.MatchPattern pat else Tac2match.MatchContext pat)
(function Tac2match.MatchPattern pat -> (true, pat) | MatchContext pat -> (false, pat))
(pair bool pattern)
let () = define3 "pattern_matches_goal" bool
(list (pair (option match_pattern) match_pattern))
match_pattern
begin fun rev hp cp ->
assert_focussed >>= fun () ->
Proofview.Goal.enter_one begin fun gl ->
let env = Proofview.Goal.env gl in
let sigma = Proofview.Goal.sigma gl in
let concl = Proofview.Goal.concl gl in
Tac2match.match_goal env sigma concl ~rev (hp, cp) >>= fun (hyps, ctx, subst) ->
let of_ctxopt ctx = Value.of_ext val_matching_context (Option.default empty_context ctx) in
let hids = Value.of_array Value.of_ident (Array.map_of_list pi1 hyps) in
let hbctx = Value.of_array of_ctxopt
(Array.of_list (CList.filter_map (fun (_,bctx,_) -> bctx) hyps))
in
let hctx = Value.of_array of_ctxopt (Array.map_of_list pi3 hyps) in
let subs = Value.of_array Value.of_constr (Array.map_of_list snd (Id.Map.bindings subst)) in