1
(* This file contains an ml version of drag-and-drop. *)
3
(* #use "/net/home/bertot/experiments/pcoq/src/dad/dad.ml" *)
34
(* In a first approximation, drag-and-drop rules are like in CtCoq
36
2,3/ Two paths: start and end positions,
37
4/ the degree: the number of steps the algorithm should go up from the
38
longest common prefix,
39
5/ the tail path: the suffix of the longest common prefix of length the
41
6/ the command pattern, where meta variables are represented by objects
42
of the form Node(_,"META"; [Num(_,i)])
47
constr_expr * int list * int list * int * int list
48
* raw_atomic_tactic_expr;;
50
(* This value will be used systematically when constructing objects *)
52
let zz = Util.dummy_loc;;
54
(* This function receives a length n, a path p, and a term and returns a
55
couple whose first component is the subterm designated by the prefix
56
of p of length n, and the second component is the rest of the path *)
58
let rec get_subterm (depth:int) (path: int list) (constr:constr) =
59
match depth, path, kind_of_term constr with
61
| n, 2::a::tl, App(func,arr) ->
62
get_subterm (n - 2) tl arr.(a-1)
63
| _,l,_ -> failwith (int_list_to_string
64
"wrong path or wrong form of term"
67
(* This function maps a substitution on an abstract syntax tree. The
68
first argument, an object of type env, is necessary to
69
transform constr terms into abstract syntax trees. The second argument is
70
the substitution, a list of pairs linking an integer and a constr term. *)
72
let rec map_subst (env :env) (subst:patvar_map) = function
73
| CPatVar (_,(_,i)) ->
74
let constr = List.assoc i subst in
75
extern_constr false env constr
76
| x -> map_constr_expr_with_binders (fun _ x -> x) (map_subst env) subst x;;
78
let map_subst_tactic env subst = function
79
| TacExtend (loc,("Rewrite" as x),[b;cbl]) ->
80
let c,bl = out_gen rawwit_constr_with_bindings cbl in
81
assert (bl = NoBindings);
82
let c = (map_subst env subst c,NoBindings) in
83
TacExtend (loc,x,[b;in_gen rawwit_constr_with_bindings c])
84
| _ -> failwith "map_subst_tactic: unsupported tactic"
86
(* This function is really the one that is important. *)
87
let rec find_cmd (l:(string * dad_rule) list) env constr p p1 p2 =
89
[] -> failwith "nothing happens"
90
| (name, (pat, p_f, p_l, deg, p_r, cmd))::tl ->
91
let length = List.length p in
96
let term_to_match, p_r =
98
get_subterm (length - deg) p constr
100
Failure s -> failwith "internal" in
102
intern_constr_pattern Evd.empty (Global.env())
103
((*ct_to_ast*) pat) in
104
let subst = matches constr_pat term_to_match in
105
if (is_prefix p_f (p_r@p1)) & (is_prefix p_l (p_r@p2)) then
106
TacAtom (zz, map_subst_tactic env subst cmd)
110
Failure "internal" -> find_cmd tl env constr p p1 p2
111
| PatternMatchingFailure -> find_cmd tl env constr p p1 p2;;
114
let dad_rule_list = ref ([]: (string * dad_rule) list);;
117
(* \\ This function is also used in pbp. *)
118
let rec tactic_args_to_ints = function
120
| (Integer n)::l -> n::(tactic_args_to_ints l)
121
| _ -> failwith "expecting only numbers";;
123
(* We assume that the two lists of integers for the tactic are simply
124
given in one list, separated by a dummy tactic. *)
125
let rec part_tac_args l = function
127
| (Tacexp a)::tl -> l, (tactic_args_to_ints tl)
128
| (Integer n)::tl -> part_tac_args (n::l) tl
129
| _ -> failwith "expecting only numbers and the word \"to\"";;
132
(* The dad_tac tactic takes a display_function as argument. This makes
133
it possible to use it in pcoq, but also in other contexts, just by
134
changing the output routine. *)
135
let dad_tac display_function = function
136
l -> let p1, p2 = part_tac_args [] l in
138
let (p_a, p1prime, p2prime) = decompose_path (List.rev p1,p2) in
140
(find_cmd (!dad_rule_list) (pf_env g)
141
(pf_concl g) p_a p1prime p2prime));
144
let dad_tac display_function p1 p2 g =
145
let (p_a, p1prime, p2prime) = decompose_path (p1,p2) in
147
(find_cmd (!dad_rule_list) (pf_env g) (pf_concl g) p_a p1prime p2prime));
150
(* Now we enter dad rule list management. *)
152
let add_dad_rule name patt p1 p2 depth pr command =
153
dad_rule_list := (name,
154
(patt, p1, p2, depth, pr, command))::!dad_rule_list;;
156
let rec remove_if_exists name = function
158
| ((a,b) as rule1)::tl -> if a = name then
159
let result1, l = (remove_if_exists name tl) in
162
let result1, l = remove_if_exists name tl in
163
result1, (rule1::l);;
165
let remove_dad_rule name =
166
let result1, result2 = remove_if_exists name !dad_rule_list in
168
failwith("No such name among the drag and drop rules " ^ name)
170
dad_rule_list := result2;;
172
let dad_rule_names () =
173
List.map (function (s,_) -> s) !dad_rule_list;;
175
(* this function is inspired from matches_core in pattern.ml *)
176
let constrain ((n : patvar),(pat : constr_pattern)) sigma =
177
if List.mem_assoc n sigma then
178
if pat = (List.assoc n sigma) then sigma
179
else failwith "internal"
183
(* This function is inspired from matches_core in pattern.ml *)
184
let more_general_pat pat1 pat2 =
185
let rec match_rec sigma p1 p2 =
187
| PMeta (Some n), m -> constrain (n,m) sigma
189
| PMeta None, m -> sigma
191
| PRef (VarRef sp1), PRef(VarRef sp2) when sp1 = sp2 -> sigma
193
| PVar v1, PVar v2 when v1 = v2 -> sigma
195
| PRef ref1, PRef ref2 when ref1 = ref2 -> sigma
197
| PRel n1, PRel n2 when n1 = n2 -> sigma
199
| PSort (RProp c1), PSort (RProp c2) when c1 = c2 -> sigma
201
| PSort (RType _), PSort (RType _) -> sigma
203
| PApp (c1,arg1), PApp (c2,arg2) ->
204
(try array_fold_left2 match_rec (match_rec sigma c1 c2) arg1 arg2
205
with Invalid_argument _ -> failwith "internal")
206
| _ -> failwith "unexpected case in more_general_pat" in
207
try let _ = match_rec [] pat1 pat2 in true
208
with Failure "internal" -> false;;
210
let more_general r1 r2 =
212
(_,(patt1,p11,p12,_,_,_)),
213
(_,(patt2,p21,p22,_,_,_)) ->
214
(more_general_pat patt1 patt2) &
215
(is_prefix p11 p21) & (is_prefix p12 p22);;
217
let not_less_general r1 r2 =
218
not (match r1,r2 with
219
(_,(patt1,p11,p12,_,_,_)),
220
(_,(patt2,p21,p22,_,_,_)) ->
221
(more_general_pat patt1 patt2) &
222
(is_prefix p21 p11) & (is_prefix p22 p12));;
224
let rec add_in_list_sorting rule1 = function
226
| (b::tl) as this_list ->
227
if more_general rule1 b then
228
b::(add_in_list_sorting rule1 tl)
229
else if not_less_general rule1 b then
230
let tl2 = add_in_list_sorting_aux rule1 tl in
232
[] -> rule1::this_list
236
and add_in_list_sorting_aux rule1 = function
239
if more_general rule1 b then
240
b::(add_in_list_sorting rule1 tl)
242
let tl2 = add_in_list_sorting_aux rule1 tl in
247
let rec sort_list = function
249
| a::l -> add_in_list_sorting a (sort_list l);;
251
let mk_dad_meta n = CPatVar (zz,(true,Nameops.make_ident "DAD" (Some n)));;
252
let mk_rewrite lr ast =
253
let b = in_gen rawwit_bool lr in
254
let cb = in_gen rawwit_constr_with_bindings (ast,NoBindings) in
255
TacExtend (zz,"Rewrite",[b;cb])
259
let dad_status = ref false;;
261
let start_dad () = dad_status := true;;
263
let add_dad_rule_fn name pat p1 p2 tac =
264
let pr = match decompose_path (p1, p2) with pr, _, _ -> pr in
265
add_dad_rule name pat p1 p2 (List.length pr) pr tac;;
267
(* To be parsed by camlp4
269
(*i camlp4deps: "parsing/grammar.cma" i*)
271
VERNAC COMMAND EXTEND AddDadRule
272
[ "Add" "Dad" "Rule" string(name) constr(pat)
273
"From" natural_list(p1) "To" natural_list(p2) tactic(tac) ] ->
274
[ add_dad_rule_fn name pat p1 p2 tac ]
279
let mk_id s = mkIdentC (id_of_string s);;
280
let mkMetaC = mk_dad_meta;;
282
add_dad_rule "distributivity-inv"
283
(mkAppC(mk_id("mult"),[mkAppC(mk_id("plus"),[mkMetaC(4);mkMetaC(3)]);mkMetaC(2)]))
288
(mk_rewrite true (mkAppC(mk_id( "mult_plus_distr"),[(mk_dad_meta 4) ;(mk_dad_meta 3) ;(mk_dad_meta 2) ])));
290
add_dad_rule "distributivity1-r"
291
(mkAppC(mk_id("plus"),[mkAppC(mk_id("mult"),[mkMetaC(4);mkMetaC(2)]);mkAppC(mk_id("mult"),[mkMetaC(3);mkMetaC(2)])]))
296
(mk_rewrite false (mkAppC(mk_id("mult_plus_distr"),[(mk_dad_meta 4) ;(mk_dad_meta 3) ;(mk_dad_meta 2) ])));
298
add_dad_rule "distributivity1-l"
299
(mkAppC(mk_id("plus"),[mkAppC(mk_id("mult"),[mkMetaC(4);mkMetaC(2)]);mkAppC(mk_id("mult"),[mkMetaC(3);mkMetaC(2)])]))
304
(mk_rewrite false (mkAppC(mk_id( "mult_plus_distr"),[(mk_dad_meta 4) ;(mk_dad_meta 3) ;(mk_dad_meta 2) ])));
306
add_dad_rule "associativity"
307
(mkAppC(mk_id("plus"),[mkAppC(mk_id("plus"),[mkMetaC(4);mkMetaC(3)]);mkMetaC(2)]))
312
(mk_rewrite true (mkAppC(mk_id( "plus_assoc_r"),[(mk_dad_meta 4) ;(mk_dad_meta 3) ;(mk_dad_meta 2) ])));
314
add_dad_rule "minus-identity-lr"
315
(mkAppC(mk_id("minus"),[mkMetaC(2);mkMetaC(2)]))
320
(mk_rewrite false (mkAppC(mk_id( "minus_n_n"),[(mk_dad_meta 2) ])));
322
add_dad_rule "minus-identity-rl"
323
(mkAppC(mk_id("minus"),[mkMetaC(2);mkMetaC(2)]))
328
(mk_rewrite false (mkAppC(mk_id( "minus_n_n"),[(mk_dad_meta 2) ])));
330
add_dad_rule "plus-sym-rl"
331
(mkAppC(mk_id("plus"),[mkMetaC(3);mkMetaC(2)]))
336
(mk_rewrite true (mkAppC(mk_id( "plus_sym"),[(mk_dad_meta 3) ;(mk_dad_meta 2) ])));
338
add_dad_rule "plus-sym-lr"
339
(mkAppC(mk_id("plus"),[mkMetaC(3);mkMetaC(2)]))
344
(mk_rewrite true (mkAppC(mk_id( "plus_sym"),[(mk_dad_meta 3) ;(mk_dad_meta 2) ])));
346
add_dad_rule "absorb-0-r-rl"
347
(mkAppC(mk_id("plus"),[mkMetaC(2);mk_id("O")]))
352
(mk_rewrite false (mkAppC(mk_id( "plus_n_O"),[(mk_dad_meta 2) ])));
354
add_dad_rule "absorb-0-r-lr"
355
(mkAppC(mk_id("plus"),[mkMetaC(2);mk_id("O")]))
360
(mk_rewrite false (mkAppC(mk_id( "plus_n_O"),[(mk_dad_meta 2) ])));
362
add_dad_rule "plus-permute-lr"
363
(mkAppC(mk_id("plus"),[mkMetaC(4);mkAppC(mk_id("plus"),[mkMetaC(3);mkMetaC(2)])]))
368
(mk_rewrite true (mkAppC(mk_id( "plus_permute"),[(mk_dad_meta 4) ;(mk_dad_meta 3) ;(mk_dad_meta 2) ])));
370
add_dad_rule "plus-permute-rl"
371
(mkAppC(mk_id("plus"),[mkMetaC(4);mkAppC(mk_id("plus"),[mkMetaC(3);mkMetaC(2)])]))
376
(mk_rewrite true (mkAppC(mk_id( "plus_permute"),[(mk_dad_meta 4) ;(mk_dad_meta 3) ;(mk_dad_meta 2) ])));;
378
vinterp_add "StartDad"
381
(function () -> start_dad())
382
| _ -> errorlabstrm "StartDad" (mt()));;