-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathreify_Lambda_shell.ml4
More file actions
1594 lines (1472 loc) · 53.1 KB
/
reify_Lambda_shell.ml4
File metadata and controls
1594 lines (1472 loc) · 53.1 KB
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
(*i camlp4deps: "parsing/grammar.cma" i*)
(*i camlp4use: "pa_extend.cmo" i*)
open Plugin_utils
open Reify_Core
open Reify_Monad
let contrib_name = "MirrorCore.Reify"
DECLARE PLUGIN "reify_Lambda_plugin"
module type REIFICATION =
sig
type all_tables
val parse_tables : Term.constr -> map_type list
(** Tables **)
val declare_table : Names.identifier -> Evd.evar_map -> Term.constr -> bool
val declare_typed_table : Names.identifier -> Evd.evar_map -> Term.constr -> Term.constr -> bool
val seed_table : Term.constr -> int -> Term.constr -> bool
val seed_typed_table : Term.constr -> int -> Term.constr -> Term.constr -> bool
(** Patterns **)
val declare_pattern : Names.identifier -> Evd.evar_map -> Term.constr -> unit
val add_pattern : Term.constr -> Term.constr (* rpattern *) -> Term.constr -> Evd.evar_map -> unit
val print_patterns : Term.constr -> Pp.std_ppcmds
(** Functions **)
val declare_syntax : Names.identifier -> Environ.env -> Evd.evar_map -> Term.constr (* command *) -> unit
(** Reification **)
val reify : Environ.env -> Evd.evar_map -> map_type list (* tables *) ->
Term.constr -> Term.constr -> Term.constr * all_tables
val reify_all : Environ.env -> Evd.evar_map -> map_type list (* tables *) ->
(Term.constr * Term.constr) list -> Term.constr list * all_tables
val export_table : Term.constr list -> map_type -> all_tables -> Term.constr
val pose_each : (string * Term.constr) list -> (Term.constr list -> unit Proofview.tactic) -> unit Proofview.tactic
val ic : ?env:Environ.env -> ?sigma:Evd.evar_map -> Constrexpr.constr_expr -> Evd.evar_map * Term.constr
val ics : ?env:Environ.env -> ?sigma:Evd.evar_map -> Constrexpr.constr_expr list -> Evd.evar_map * Term.constr list
val check_inside_section : string -> unit
val error_parse : Term.constr -> string -> 'a
end
module Reification : REIFICATION =
struct
module Std = Reify_Core.Std
let do_debug = false
let rec pr_constrs sep ks =
Pp.prlist_with_sep (fun _ -> sep) Printer.pr_constr ks
let debug_constr s e =
if do_debug then
(Pp.(msg_debug ( (str s) ++ (str ": ") ++ (Printer.pr_constr e))) ;
Printf.eprintf "debug_constr\n" ;
flush stderr)
else
()
let debug_pp p =
if do_debug then
(Pp.(msg_debug p) ; flush stderr)
else ()
let debug s =
if do_debug then
(Pp.(msg_debug ( str s)) ;
Printf.eprintf "%s\n" s ;
flush stderr)
else
()
let resolve_poly_symbol_no_univs path tm =
lazy (
let re = Coqlib.find_reference contrib_name path tm in
fst (Universes.unsafe_constr_of_global re))
type all_tables =
{ tables : (int * Term.constr) environment Cmap.t
}
let get_by_conversion renv (tbl : 'a environment)
(target : Term.constr) : 'a option =
let unifies = Reductionops.is_conv renv.env renv.evm target in
Cmap.fold (fun k v a ->
match a with
None -> if unifies k then Some v else None
| Some k -> Some k) tbl.mappings None
let decl_constant ?typ ?opaque:(opaque=false) (na : Names.identifier) evm (c : Term.constr) =
(** TODO: This looks weird... **)
let (evm, _) = Typing.type_of (Global.env ()) evm c in
let vars = Universes.universes_of_constr c in
let ctx = Universes.restrict_universe_context
(Univ.ContextSet.of_context (snd (Evd.universe_context evm))) vars in
Declare.(Term.mkConst(declare_constant na
(Entries.(DefinitionEntry
(definition_entry ~opaque:opaque
~univs:(Univ.ContextSet.to_context ctx) ~poly:false c)),
Decl_kinds.(IsDefinition Definition))))
let (reify_term, set_reify_term) =
let global_reifier = ref (fun _ -> assert false) in
let reify_term (t : Term.constr) = !global_reifier t in
let set_reify_term rt = global_reifier := rt in
(reify_term, set_reify_term)
let pattern_mod = ["MirrorCore";"Reify";"Patterns"]
module Tables =
struct
type key_type = Nat | Pos
let the_seed_table : (int * Term.constr) environment Cmap.t ref =
ref Cmap.empty
(** Freezing and thawing of state (for backtracking) **)
let _ =
Summary.(declare_summary "reify-lambda-shell-seed-table"
{ freeze_function = (fun _ -> !the_seed_table)
; unfreeze_function = (fun pt -> the_seed_table := pt)
; init_function = (fun () -> the_seed_table := Cmap.empty) })
let check_compatible env evm (e : (int * Term.constr) environment) (i : int)
(target_ty : Term.constr) (target_t : Term.constr) : bool =
Cmap.for_all (fun k (id,ty) ->
if i = id then
Reductionops.is_conv env evm k target_t &&
Reductionops.is_conv env evm ty target_ty
else true) e.mappings
let seed_table (tbl_name : Term.constr) (k : int) (t : Term.constr) (v : Term.constr)
: bool =
let (evm,env) = Lemmas.get_current_context () in
try
let tbl = Cmap.find tbl_name !the_seed_table in
if check_compatible env evm tbl k t v then
let new_tbl = { mappings = Cmap.add v (k,t) tbl.mappings
; next = max (k+1) tbl.next } in
the_seed_table := Cmap.add tbl_name new_tbl !the_seed_table ;
true
else
let _ =
Pp.(msg_warning ( str "Table '"
++ Printer.pr_constr tbl_name
++ str "' already contains a mapping for "
++ int k ++ str "." ++ fnl ()
++ str "This mapping is incompatible with the given mapping."))
in false
with
Not_found ->
let _ = Pp.(msg_warning ( str "Table '"
++ Printer.pr_constr tbl_name
++ str "' does not exist.")) in
false
let declare_table (ls : Term.constr) (kt : key_type) =
if Cmap.mem ls !the_seed_table then
let _ =
Pp.(msg_warning ( str "Table '"
++ Printer.pr_constr ls
++ str "' already exists."))
in false
else
let _ =
the_seed_table := Cmap.add ls { mappings = Cmap.empty
; next = 1
} !the_seed_table
in true
let declare_typed_table (ls : Term.constr) (kt : key_type) =
if Cmap.mem ls !the_seed_table then
let _ =
Pp.(msg_warning ( str "Table '"
++ Printer.pr_constr ls
++ str "' already exists."))
in false
else
let _ =
the_seed_table := Cmap.add ls { mappings = Cmap.empty
; next = 1
} !the_seed_table
in true
end
module Patterns =
struct
(** [rule]s implement the pattern feature **)
type rule =
{ rule_pattern : rpattern
; rule_template : template
; mutable rule_cache :
(((int,int,reify_env) Term_match.pattern) *
(reify_env -> (int, Term.constr) Hashtbl.t -> Term.constr reifier)) CEphemeron.key
}
type 'a ptrn_tree =
{ if_app : 'a IntMap.t
; if_has_type : 'a Cmap.t
; if_exact : 'a Cmap.t
; otherwise : 'a
}
let empty_ptrn_tree default =
{ if_app = IntMap.empty
; if_has_type = Cmap.empty
; if_exact = Cmap.empty
; otherwise = default
}
let rec count_apps = function
| RApp (a,_) -> count_apps a + 1
| RExact t ->
let result =
match Term.kind_of_term t with
| Term.App (_,args) -> Array.length args
| _ -> 0
in result
| _ -> 0
let rec has_open_end = function
| RApp (a,_) -> has_open_end a
| RExact _
| RLam _
| RPi _
| RImpl _ -> false
| _ -> true
let ptrn_tree_add (type a) (p : rpattern)
(v : a option -> a) (t : a ptrn_tree) =
match p with
| RApp (l,r) ->
(* NOTE: This is conservative, if the pattern ends in an open pattern
* (one that could match an application) then it is added
* to 'otherwise' as well
*)
let arity = 1 + count_apps l in
let cur =
try Some (IntMap.find arity t.if_app)
with Not_found -> None
in { t with
if_app = IntMap.add arity (v cur) t.if_app
; otherwise =
if has_open_end l then v (Some t.otherwise)
else t.otherwise }
| RExact trm -> (** Check universes **)
let cur =
try Some (Cmap.find trm t.if_exact)
with Not_found -> None
in { t with
if_exact = Cmap.add trm (v cur) t.if_exact }
| RHasType (typ,_) ->
let cur =
try Some (Cmap.find typ t.if_has_type)
with Not_found -> None
in { t with
if_has_type = Cmap.add typ (v cur) t.if_has_type }
| _ -> { t with
otherwise = v (Some t.otherwise) }
let run_ptrn_tree compile_rule (tr : rule list ptrn_tree) trm gl =
let get_rule rule =
try CEphemeron.get rule.rule_cache
with CEphemeron.InvalidKey ->
let cache = compile_rule rule.rule_pattern rule.rule_template in
let _ = rule.rule_cache <- CEphemeron.create cache in
cache
in
match trm with
Term trm ->
begin
try
Term_match.matches gl
(List.map get_rule (Cmap.find trm tr.if_exact))
trm gl
with Not_found | Term_match.Match_failure ->
try
match Term.kind_of_term trm with
| Term.App (_,args) ->
Term_match.matches gl
(List.map get_rule (IntMap.find (Array.length args) tr.if_app))
trm gl
| _ -> raise Not_found
with Not_found | Term_match.Match_failure ->
try
if not (Cmap.is_empty tr.if_has_type) then
(* get the type *)
let (_,ty) = Typing.type_of gl.env gl.evm trm in
Term_match.matches gl
(List.map get_rule (Cmap.find ty tr.if_has_type)) trm gl
else raise Not_found
with Not_found | Term_match.Match_failure ->
try
Term_match.matches gl (List.map get_rule tr.otherwise) trm gl
with
Term_match.Match_failure -> reifier_fail trm gl
end
| App (trm, args, from) ->
begin
assert false
end
(** State **)
let pattern_table : rule list ptrn_tree Cmap.t ref =
ref Cmap.empty
(** Freezing and thawing of state (for backtracking) **)
let _ =
Summary.(declare_summary "reify-lambda-shell-pattern-table"
{ freeze_function = (fun _ -> !pattern_table)
; unfreeze_function = (fun pt -> pattern_table := pt)
; init_function = (fun () -> pattern_table := Cmap.empty) })
let empty_tree = empty_ptrn_tree []
let add_empty_pattern name =
if Cmap.mem name !pattern_table then
Pp.(
msgnl ( (str "Pattern table '")
++ (Printer.pr_constr name)
++ (str "' already exists.")))
else
pattern_table := Cmap.add name empty_tree !pattern_table
let declare_pattern (obj : Term.constr) =
add_empty_pattern obj
let extend trm key rul =
try
let objs = Cmap.find trm !pattern_table in
let updated = ptrn_tree_add key (function None -> [rul]
| Some xs -> rul :: xs) objs in
pattern_table := Cmap.add trm updated !pattern_table
with
| Not_found ->
let updated = ptrn_tree_add key (fun _ -> [rul]) empty_tree in
pattern_table := Cmap.add trm updated !pattern_table
let pr_paren = Pp.surround
let rec print_pattern ptrn =
Pp.(
match ptrn with
RIgnore -> str "<any>"
| RHasType (t,p) -> pr_paren (print_pattern p ++ str " : " ++ Printer.pr_constr t)
| RConst -> str "<constant>"
| RGet (i, p) -> pr_paren (int i ++ str " <- " ++ print_pattern p)
| RApp (l, r) -> pr_paren (print_pattern l ++ str " @ " ++ print_pattern r)
| RPi (l, _, r) -> pr_paren (str "forall _ : " ++ print_pattern l ++ str ", " ++ print_pattern r)
| RLam (l, r) -> pr_paren (str "fun _ : " ++ print_pattern l ++ str " => " ++ print_pattern r)
| RImpl (l,r) -> pr_paren (print_pattern l ++ str " -> " ++ print_pattern r)
| RExact p -> pr_paren (str "! " ++ Printer.pr_constr p))
let print_rule r = print_pattern r.rule_pattern
let apps = List.fold_right Pp.(++)
let print_patterns (name : Term.constr) : Pp.std_ppcmds =
try
let vals = Cmap.find name !pattern_table in
Pp.pr_vertical_list print_rule
(List.flatten (List.map snd (IntMap.bindings vals.if_app) @
List.map snd (Cmap.bindings vals.if_has_type) @
List.map snd (Cmap.bindings vals.if_exact) @
[vals.otherwise]))
with Not_found ->
Pp.(msg_warning ( (str "Unknown pattern table '")
++ (Printer.pr_constr name)
++ (str "'."))) ;
Pp.mt ()
let reify_patterns compile_rule (i : Term.constr) trm
: Term.constr reifier =
fun gl ->
let tbl =
try Cmap.find i !pattern_table
with Not_found ->
Errors.anomaly Pp.(str "Invariant violation, please report!" ++
fnl () ++
str "pattern table not found:" ++ spc () ++
Printer.pr_constr i)
in
run_ptrn_tree compile_rule tbl trm gl
let add_pattern compile_rule env evd
(name : Term.constr) (ptrn : Term.constr) (template : Term.constr)
: unit =
try
let rule = Reify_Core.parse_pattern env evd ptrn template in
let rptrn = rule.Reify_Core.rule_pattern in
let rtemplate = rule.Reify_Core.rule_template in
extend name rptrn
{ rule_pattern = rptrn
; rule_template = rtemplate
; rule_cache = CEphemeron.create (compile_rule rptrn rtemplate)
}
with
Term_match.Match_failure ->
raise (Failure "match failed, please report")
end
module Syntax =
struct
type syntax_data =
{ reify : lazy_term -> Term.constr reifier
; result_type : unit (* Term.constr *)
}
let reify_table : syntax_data CEphemeron.key Cmap.t ref =
ref Cmap.empty
let find for_var =
let rec find ls i acc meta_offset =
match ls with
[] -> assert false
| l :: ls ->
if i = 0 then
begin
match l with
RBind -> for_var acc
| RSkip -> assert false
| Use -> Term.mkRel meta_offset
end
else
match l with
RBind -> find ls (i - 1) (acc + 1) meta_offset
| RSkip -> find ls (i - 1) acc meta_offset
| Use -> find ls (i - 1) acc (meta_offset + 1)
in
fun ls i -> find ls i 0 1
(** Get the head symbol **)
let rec app_full trm acc =
match Term.kind_of_term trm with
Term.App (f, xs) -> app_full f (Array.to_list xs @ acc)
| _ -> (trm, acc)
type pattern_effect = (int, Term.constr) Hashtbl.t -> reify_env -> reify_env
(* This function compiles an [rpattern] into a [Term_match.pattern] and
* a set of bindings
*)
let rec compile_pattern p =
let fresh = ref (-1) in
let effects : (int, pattern_effect) Hashtbl.t =
Hashtbl.create 1
in
let rec compile_pattern (p : rpattern)
(effect : pattern_effect option)
: (int,int,reify_env) Term_match.pattern =
match p with
RExact g -> Term_match.EGlob_no_univ g
| RIgnore -> Term_match.Ignore
| RGet (i, p) ->
let p = compile_pattern p effect in
let _ =
match effect with
None -> ()
| Some eft -> Hashtbl.add effects i eft
in
Term_match.As (p, i)
| RApp (p1, p2) ->
let p1 = compile_pattern p1 effect in
let p2 = compile_pattern p2 effect in
Term_match.App (p1,p2)
| RConst ->
let filter _ =
let rec filter trm =
(** TODO: This does not support polymorphic types **)
let (f, args) = app_full trm [] in
Term.isConstruct f && List.for_all filter args
in
filter
in
Term_match.Filter (filter, Term_match.Ignore)
| RImpl (p1, p2) ->
let p1 = compile_pattern p1 effect in
let fresh =
let r = !fresh in
fresh := r - 1 ;
r
in
let new_effect =
match effect with
None ->
fun s x ->
let nbindings = RSkip :: x.bindings in
let nenv =
Environ.push_rel (Names.Anonymous, None, Hashtbl.find s fresh)
x.env
in
{ x with bindings = nbindings ; env = nenv }
| Some eft ->
fun s x ->
let x = eft s x in
let nbindings = RSkip :: x.bindings in
let nenv =
Environ.push_rel (Names.Anonymous, None, Hashtbl.find s fresh)
x.env
in
{ x with bindings = nbindings ; env = nenv }
in
let p2 = compile_pattern p2 (Some new_effect) in
Term_match.Impl (Term_match.As (p1,fresh),p2)
| RPi (p1, uob, p2) ->
let p1 = compile_pattern p1 effect in
let fresh =
let r = !fresh in
fresh := r - 1 ;
r
in
let new_effect =
match effect with
None ->
fun s x ->
let nbindings = uob :: x.bindings in
let nenv =
Environ.push_rel (Names.Anonymous, None, Hashtbl.find s fresh)
x.env
in
{ x with bindings = nbindings ; env = nenv }
| Some eft ->
fun s x ->
let x = eft s x in
let nbindings = uob :: x.bindings in
let nenv =
Environ.push_rel (Names.Anonymous, None, Hashtbl.find s fresh)
x.env
in
{ x with bindings = nbindings ; env = nenv }
in
let p2 = compile_pattern p2 (Some new_effect) in
Term_match.Pi (Term_match.As (p1,fresh),p2)
| RHasType (t,p) ->
let p = compile_pattern p effect in
Term_match.Filter
((fun env trm ->
let (_,ty) = Typing.type_of env.env env.evm trm in
Term.eq_constr ty t), p)
| RLam (a,b) -> assert false
in
let ptrn = compile_pattern p None in
(ptrn, effects)
and compile_template stk
(effects : (int, pattern_effect) Hashtbl.t)
tmp =
let rec compile_template (tmp : template) (at : int)
: Term.constr list -> reify_env -> (int, Term.constr) Hashtbl.t ->
Term.constr reifier =
match tmp with
| Return t -> fun ls _ _ -> reifier_ret (Vars.substnl ls 0 t)
| Bind (act, rest) ->
let rest = compile_template rest (at + 1) in
let eft =
try Hashtbl.find effects at
with Not_found -> (fun _ x -> x)
in
match act with
| Func f ->
let reifier = compile_command stk f in
fun vals gl s ->
let cur_val = Hashtbl.find s at in
let rval = reifier_run (reifier_local (eft s) (reifier (Term cur_val))) gl in
rest (rval :: vals) gl s
| Id ->
fun vals gl s ->
let cur_val = Hashtbl.find s at in
reifier_bind
reifier_get_env
(fun env ->
if Vars.noccur_between 1 (List.length env.bindings) cur_val then
rest (cur_val :: vals) gl s
else
reifier_fail cur_val)
in compile_template tmp 0 []
and compile_rule stk rptrn template =
let (ptrn, effects) = compile_pattern rptrn in
let action = compile_template stk effects template in
(ptrn, action)
and compile_patterns stk ptrns =
List.fold_left (fun acc ptrn ->
let rptrn = ptrn.Reify_Core.rule_pattern in
let template = ptrn.Reify_Core.rule_template in
let cptrn =
{ Patterns.rule_pattern = rptrn
; Patterns.rule_template = template
; Patterns.rule_cache =
CEphemeron.create (compile_rule stk rptrn template)
}
in
Patterns.ptrn_tree_add ptrn.rule_pattern
(function None -> [cptrn]
| Some xs -> cptrn :: xs) acc)
(Patterns.empty_ptrn_tree []) ptrns
and compile_command (stk : (lazy_term -> Term.constr reifier) ref list)
(ls : command)
: lazy_term -> Term.constr reifier =
let rec compile_command stk (l : command)
: lazy_term -> Term.constr reifier =
match l with
| Rec n ->
let r = List.nth stk n in
fun trm gl -> !r trm gl
| Fix k ->
let z = ref (fun _ -> assert false) in
let k = compile_command (z :: stk) k in
z := k ;
k
| Call f ->
fun trm gl -> reify_term f trm gl
| Patterns i ->
fun trm gl ->
Patterns.reify_patterns (fun c -> compile_rule [] c) i trm gl
| Pattern ptrns ->
let ptrns = compile_patterns stk ptrns in
fun trm gl -> Patterns.run_ptrn_tree (compile_rule stk) ptrns trm gl
| Abs (ty,body,ctor) ->
let reify_type = compile_command stk ty in
let reify_term = compile_command stk body in
fun trm gl ->
begin
match Term.kind_of_term (get_term trm) with
Term.Lambda (name, lhs, rhs) ->
let ty = reify_type (Term lhs) gl in
let new_gl =
{ gl with
env = Environ.push_rel (name, None, lhs) gl.env
; bindings = RBind :: gl.bindings
}
in
let body = reifier_run (reify_term (Term rhs)) new_gl in
Term.mkApp (ctor, [| ty ; body |])
| _ -> reifier_fail_lazy trm gl
end
| PiMeta (ty,cmd) ->
let reify_body = compile_command stk cmd in
fun trm gl ->
begin
match Term.kind_of_term (get_term trm) with
Term.Prod (name, lhs, rhs) ->
reifier_under_binder ~name Use lhs
(reifier_fmap
(fun b -> Term.mkLambda (Names.Anonymous, ty, b))
(reify_body (Term rhs))) gl
| _ -> reifier_fail_lazy trm gl
end
| Var ctor ->
let mkVar idx = Term.mkApp (ctor, [| Std.Nat.to_nat idx |]) in
fun trm gl ->
begin
match Term.kind_of_term (get_term trm) with
Term.Rel i ->
find mkVar gl.bindings (i-1)
| _ -> reifier_fail_lazy trm gl
end
| App (f,x,ctor) ->
let f = compile_command stk f in
let x = compile_command stk x in
fun trm gl ->
begin
try
Term_match.(matches gl
[ (App (get 0, get 1),
fun gl s ->
let f = f (Term (Hashtbl.find s 0)) gl in
let x = x (Term (Hashtbl.find s 1)) gl in
Term.mkApp (ctor, [| f ; x |]))
])
(get_term trm)
with
Term_match.Match_failure -> reifier_fail_lazy trm gl
end
| Table tbl_name ->
begin
let build = Std.Positive.to_positive in
fun trm renv ->
let tbl =
let tbls = !(renv.typed_tables) in
try
Cmap.find tbl_name tbls
with
Not_found ->
let all_tables = List.map fst (Cmap.bindings tbls) in
let _ =
Pp.(msg_warning
( str "Implicitly adding table '"
++ Printer.pr_constr tbl_name
++ str "'. This will not be returned.\n"
++ str "(available tables are: "
++ pr_constrs (str " , ") all_tables
++ str ")"))
in
{ mappings = Cmap.empty
; next = 1 }
in
let full_term = get_term trm in
try
(** fast path something already in the table **)
build (fst (Cmap.find full_term tbl.mappings))
with
Not_found ->
match get_by_conversion renv tbl full_term with
None ->
let (result, new_tbl) =
let result = tbl.next in
let value = (result, Lazy.force Std.Unit.tt) in
(result,
{ next = result + 1
; mappings = Cmap.add full_term value tbl.mappings })
in
renv.typed_tables :=
Cmap.add tbl_name new_tbl !(renv.typed_tables) ;
build result
| Some k -> build (fst k)
end
| TypedTable (tbl_name, cmd_type) ->
begin
let build = Std.Positive.to_positive in
let reify_type = compile_command stk cmd_type in
fun trm renv ->
let tbls = !(renv.typed_tables) in
let tbl =
try
Cmap.find tbl_name tbls
with
Not_found ->
let all_tables = List.map fst (Cmap.bindings tbls) in
let _ =
Pp.(msg_warning
( str "Implicitly adding table '"
++ Printer.pr_constr tbl_name
++ str "'. This will not be returned.\n"
++ str "(available tables are: "
++ pr_constrs (str " , ") all_tables
++ str ")"))
in
{ mappings = Cmap.empty
; next = 1 }
in
let full_term = get_term trm in
let (_,type_of) = Typing.type_of renv.env renv.evm full_term in
let rtyp = reify_type (Term type_of) renv in
try
(** fast path something already in the table **)
let x = Cmap.find full_term tbl.mappings in
build (fst x)
with
Not_found ->
match get_by_conversion renv tbl full_term with
None ->
let (result, new_tbl) =
let result = tbl.next in
let value = (result, rtyp) in
(result,
{ next = result + 1
; mappings = Cmap.add full_term value tbl.mappings })
in
renv.typed_tables := Cmap.add tbl_name new_tbl !(renv.typed_tables) ;
build result
| Some k -> build (fst k)
end
| Map (f,n) ->
let cmd = compile_command stk n in
begin
fun trm ->
reifier_bind (cmd trm) (fun t -> reifier_ret (Term.mkApp (f, [| t |])))
end
| Or (a,b) ->
let l = compile_command stk a in
let k = compile_command stk b in
begin
fun t gl -> reifier_try (l t) (k t) gl
end
| Fail ->
reifier_fail_lazy
in
let result = compile_command stk ls in
let result =
fun trm gl ->
reifier_try
(fun gl ->
let strm = get_term trm in
match Term.kind_of_term strm with
Term.Rel i ->
find (fun _ ->
raise (ReificationFailure (Lazy.from_val strm)))
gl.bindings (i-1)
| _ -> reifier_fail_lazy trm gl)
(result trm) gl
in
result
(** Freezing and thawing of state (for backtracking) **)
let _ =
Summary.(declare_summary "reify-lambda-shell-syntax-table"
{ freeze_function = (fun _ -> !reify_table);
unfreeze_function = (fun pt -> reify_table := pt);
init_function = (fun () -> reify_table := Cmap.empty) })
let cmd_Command = resolve_poly_symbol_no_univs pattern_mod "Command"
(* let get_Command_type env evm cmd = *)
(* let (_,typ) = *)
(* try Typing.type_of env evm cmd *)
(* with _ -> *)
(* Errors.errorlabstrm "Type error" *)
(* Pp.( str "Reification command is ill-typed" *)
(* ++ fnl () *)
(* ++ Printer.pr_constr_env env evm cmd) *)
(* in *)
(* try *)
(* Term_match.(matches () *)
(* [(apps (Glob_no_univ cmd_Command) [get 0], *)
(* fun _ s -> Hashtbl.find s 0)] *)
(* typ) *)
(* with *)
(* Term_match.Match_failure -> *)
(* Errors.errorlabstrm "Type error" *)
(* Pp.( str "Reification got non-Command" *)
(* ++ fnl () *)
(* ++ Printer.pr_constr_env env evm cmd *)
(* ++ fnl () *)
(* ++ str "has type" ++ fnl () *)
(* ++ Printer.pr_constr_env env evm typ) *)
let compile_name (prg : Term.constr) =
let (evm,env) = Lemmas.get_current_context () in
(* let typ = get_Command_type env evm prg in *)
let reduced = Reductionops.whd_betadeltaiota env evm prg in
let program = parse_command env evm reduced in
try
{ result_type = () (* typ *)
; reify = compile_command [] program }
with
| _ ->
Errors.errorlabstrm "Compilation error"
Pp.( str "Failed to compile" ++ fnl ()
++ Printer.pr_constr prg
++ fnl ()
++ str "(Are your binders correct?)")
let get_entry (name : Term.constr) =
let name = drop_calls name in
try
let key = Cmap.find name !reify_table in
try CEphemeron.get key
with CEphemeron.InvalidKey ->
let data = compile_name name in
reify_table := Cmap.add name (CEphemeron.create data) !reify_table ;
data
with
Not_found ->
if not (Term.isConst name) then
debug_pp Pp.( str "compiling inline reify command (this may impact performance):"
++ spc () ++ Printer.pr_constr name) ;
let data = compile_name name in
reify_table := Cmap.add name (CEphemeron.create data) !reify_table ;
data
let reify_term (name : Term.constr) =
let data = get_entry name in
data.reify
let _ = set_reify_term reify_term
(*
let reify_type (name : Term.constr) =
let data = get_entry name in
data.result_type
*)
let declare_syntax (name : Names.identifier) env evm
(cmd : Term.constr) : unit =
let typ =
let (_,typ) = Typing.type_of env evm cmd in
let open Term_match in
matches ()
[ (apps (Glob_no_univ cmd_Command) [get 0],
fun _ s -> Hashtbl.find s 0)
; (get 0,
fun _ s -> Errors.errorlabstrm "type-error"
Pp.( str "Syntax must have type"
++ Printer.pr_constr (Lazy.force cmd_Command))) ]
typ
in
let program = parse_command env evm cmd in
let _meta_reifier = compile_command [] program in
let data = { result_type = () (* typ *)
; reify = _meta_reifier } in
let obj = decl_constant name evm cmd in
reify_table := Cmap.add obj (CEphemeron.create data) !reify_table
end
let initial_env (env : Environ.env) (evar_map : Evd.evar_map)
(tbls : map_type list) =
let init_table =
let seed_table = !Tables.the_seed_table in
let find_default x =
try Cmap.find x seed_table
with
_ -> (* You can not use an undeclared table **)
raise (Failure "Bad table setup")
in
List.fold_left (fun acc tbl ->
Cmap.add tbl.table_name (find_default tbl.table_name) acc)
Cmap.empty tbls
in
{ env = env
; evm = evar_map
; bindings = []
; typed_tables = ref !Tables.the_seed_table }
let reify (env : Environ.env) (evm : Evd.evar_map) tbls (name : Term.constr)
trm =
let env = initial_env env evm tbls in
let result = Syntax.reify_term name (Term trm) env in
(result, { tables = !(env.typed_tables) })
(*
let rec wrap_lambdas t =
function [] -> t
| typ :: typs ->
wrap_lambdas (Term.mkLambda (Names.Anonymous, typ, t)) typs
let polymorphically k pred =
function [] -> k (Term pred)
| all_ts ->
let pargs = List.length all_ts in
let rec polymorphically n pred =
function [] -> reifier_bind (k (Term pred))
(fun t -> reifier_ret (wrap_lambdas t all_ts))
| t::ts ->
Term_match.matches n
[ (Term_match.Pi (Term_match.get 0, Term_match.get 1),
fun n s ->
let t = Hashtbl.find s 0 in
assert (Term.isSort t) ;
let b = Hashtbl.find s 1 in
reifier_under_binder Use t
(polymorphically (n+1) b ts))
; (Term_match.Ignore,
fun _ _ -> raise (ReificationFailure (lazy pred)))
]
pred
in
polymorphically 0 pred all_ts
let lemma_mod = ["MirrorCore";"Lemma"]
let reify_lemma
~type_fn:typ_rule ~prem_fn:prem_rule ~concl_fn:concl_rule env evm pargs pred =
let build_lemma = Std.resolve_symbol lemma_mod "Build_lemma" in
let ty = Syntax.reify_type typ_rule in
let finish alls prems pred =
let pr = Syntax.reify_type prem_rule in
let co = Syntax.reify_type concl_rule in
let lem = Term.mkApp (Lazy.force build_lemma,
[| ty ; pr ; co
; Std.List.to_list ty alls
; Std.List.to_list pr (List.rev prems)
; pred |]) in
reifier_ret lem
in
let get_prems alls =
let rec get_prems prems pred =
Term_match.matches ()
[ (Term_match.Impl(Term_match.get 0, Term_match.get 1),
fun () s ->
let t = Hashtbl.find s 0 in
let b = Hashtbl.find s 1 in
reifier_bind
(Syntax.reify_term prem_rule (Term t))
(fun pr ->
reifier_under_binder RSkip t
(get_prems (pr :: prems) b)))
; (Term_match.Ignore,
fun () s ->
reifier_bind
(Syntax.reify_term concl_rule (Term pred))
(fun result -> finish alls prems result))
]
pred
in get_prems
in
let rec get_foralls alls pred =