summaryrefslogtreecommitdiff
path: root/tactics/hipattern.ml4
diff options
context:
space:
mode:
Diffstat (limited to 'tactics/hipattern.ml4')
-rw-r--r--tactics/hipattern.ml4245
1 files changed, 156 insertions, 89 deletions
diff --git a/tactics/hipattern.ml4 b/tactics/hipattern.ml4
index 2e83ac70..9aec0e09 100644
--- a/tactics/hipattern.ml4
+++ b/tactics/hipattern.ml4
@@ -8,7 +8,7 @@
(*i camlp4deps: "parsing/grammar.cma parsing/q_constr.cmo" i*)
-(* $Id: hipattern.ml4 11739 2009-01-02 19:33:19Z herbelin $ *)
+(* $Id$ *)
open Pp
open Util
@@ -32,10 +32,10 @@ open Declarations
is an inductive but non-recursive type, a general conjuction, a
general disjunction, or a type with no constructors.
- They are more general than matching with or_term, and_term, etc,
- since they do not depend on the name of the type. Hence, they
+ They are more general than matching with or_term, and_term, etc,
+ since they do not depend on the name of the type. Hence, they
also work on ad-hoc disjunctions introduced by the user.
-
+
-- Eduardo (6/8/97). *)
type 'a matching_function = constr -> 'a option
@@ -50,16 +50,16 @@ let meta4 = mkmeta 4
let op2bool = function Some _ -> true | None -> false
-let match_with_non_recursive_type t =
- match kind_of_term t with
- | App _ ->
+let match_with_non_recursive_type t =
+ match kind_of_term t with
+ | App _ ->
let (hdapp,args) = decompose_app t in
(match kind_of_term hdapp with
- | Ind ind ->
- if not (Global.lookup_mind (fst ind)).mind_finite then
- Some (hdapp,args)
- else
- None
+ | Ind ind ->
+ if not (Global.lookup_mind (fst ind)).mind_finite then
+ Some (hdapp,args)
+ else
+ None
| _ -> None)
| _ -> None
@@ -69,34 +69,34 @@ let is_non_recursive_type t = op2bool (match_with_non_recursive_type t)
let rec has_nodep_prod_after n c =
match kind_of_term c with
- | Prod (_,_,b) ->
- ( n>0 || not (dependent (mkRel 1) b))
+ | Prod (_,_,b) ->
+ ( n>0 || not (dependent (mkRel 1) b))
&& (has_nodep_prod_after (n-1) b)
| _ -> true
-
+
let has_nodep_prod = has_nodep_prod_after 0
-(* A general conjunctive type is a non-recursive with-no-indices inductive
+(* A general conjunctive type is a non-recursive with-no-indices inductive
type with only one constructor and no dependencies between argument;
- it is strict if it has the form
+ it is strict if it has the form
"Inductive I A1 ... An := C (_:A1) ... (_:An)" *)
(* style: None = record; Some false = conjunction; Some true = strict conj *)
-let match_with_one_constructor style t =
- let (hdapp,args) = decompose_app t in
+let match_with_one_constructor style allow_rec t =
+ let (hdapp,args) = decompose_app t in
match kind_of_term hdapp with
- | Ind ind ->
+ | Ind ind ->
let (mib,mip) = Global.lookup_inductive ind in
if (Array.length mip.mind_consnames = 1)
- && (not (mis_is_recursive (ind,mib,mip)))
+ && (allow_rec or not (mis_is_recursive (ind,mib,mip)))
&& (mip.mind_nrealargs = 0)
then
if style = Some true (* strict conjunction *) then
- let ctx =
- fst (decompose_prod_assum (snd
+ let ctx =
+ (prod_assum (snd
(decompose_prod_n_assum mib.mind_nparams mip.mind_nf_lc.(0)))) in
- if
+ if
List.for_all
(fun (_,b,c) -> b=None && c = mkRel mib.mind_nparams) ctx
then
@@ -104,7 +104,7 @@ let match_with_one_constructor style t =
else None
else
let ctyp = prod_applist mip.mind_nf_lc.(0) args in
- let cargs = List.map pi3 (fst (decompose_prod_assum ctyp)) in
+ let cargs = List.map pi3 ((prod_assum ctyp)) in
if style <> Some false || has_nodep_prod ctyp then
(* Record or non strict conjunction *)
Some (hdapp,List.rev cargs)
@@ -115,10 +115,10 @@ let match_with_one_constructor style t =
| _ -> None
let match_with_conjunction ?(strict=false) t =
- match_with_one_constructor (Some strict) t
+ match_with_one_constructor (Some strict) false t
-let match_with_record t =
- match_with_one_constructor None t
+let match_with_record t =
+ match_with_one_constructor None false t
let is_conjunction ?(strict=false) t =
op2bool (match_with_conjunction ~strict t)
@@ -126,20 +126,30 @@ let is_conjunction ?(strict=false) t =
let is_record t =
op2bool (match_with_record t)
+let match_with_tuple t =
+ let t = match_with_one_constructor None true t in
+ Option.map (fun (hd,l) ->
+ let ind = destInd hd in
+ let (mib,mip) = Global.lookup_inductive ind in
+ let isrec = mis_is_recursive (ind,mib,mip) in
+ (hd,l,isrec)) t
+
+let is_tuple t =
+ op2bool (match_with_tuple t)
-(* A general disjunction type is a non-recursive with-no-indices inductive
+(* A general disjunction type is a non-recursive with-no-indices inductive
type with of which all constructors have a single argument;
- it is strict if it has the form
+ it is strict if it has the form
"Inductive I A1 ... An := C1 (_:A1) | ... | Cn : (_:An)" *)
let test_strict_disjunction n lc =
array_for_all_i (fun i c ->
- match fst (decompose_prod_assum (snd (decompose_prod_n_assum n c))) with
+ match (prod_assum (snd (decompose_prod_n_assum n c))) with
| [_,None,c] -> c = mkRel (n - i)
| _ -> false) 0 lc
let match_with_disjunction ?(strict=false) t =
- let (hdapp,args) = decompose_app t in
+ let (hdapp,args) = decompose_app t in
match kind_of_term hdapp with
| Ind ind ->
let car = mis_constr_nargs ind in
@@ -157,7 +167,7 @@ let match_with_disjunction ?(strict=false) t =
Array.map (fun ar -> pi2 (destProd (prod_applist ar args)))
mip.mind_nf_lc in
Some (hdapp,Array.to_list cargs)
- else
+ else
None
| _ -> None
@@ -170,12 +180,12 @@ let is_disjunction ?(strict=false) t =
let match_with_empty_type t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
- | Ind ind ->
+ | Ind ind ->
let (mib,mip) = Global.lookup_inductive ind in
- let nconstr = Array.length mip.mind_consnames in
+ let nconstr = Array.length mip.mind_consnames in
if nconstr = 0 then Some hdapp else None
| _ -> None
-
+
let is_empty_type t = op2bool (match_with_empty_type t)
(* This filters inductive types with one constructor with no arguments;
@@ -184,21 +194,22 @@ let is_empty_type t = op2bool (match_with_empty_type t)
let match_with_unit_or_eq_type t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
- | Ind ind ->
+ | Ind ind ->
let (mib,mip) = Global.lookup_inductive ind in
- let constr_types = mip.mind_nf_lc in
+ let constr_types = mip.mind_nf_lc in
let nconstr = Array.length mip.mind_consnames in
- let zero_args c = nb_prod c = mib.mind_nparams in
- if nconstr = 1 && zero_args constr_types.(0) then
+ let zero_args c = nb_prod c = mib.mind_nparams in
+ if nconstr = 1 && zero_args constr_types.(0) then
Some hdapp
- else
+ else
None
| _ -> None
let is_unit_or_eq_type t = op2bool (match_with_unit_or_eq_type t)
(* A unit type is an inductive type with no indices but possibly
- (useless) parameters, and that has no constructors *)
+ (useless) parameters, and that has no arguments in its unique
+ constructor *)
let is_unit_type t =
match match_with_conjunction t with
@@ -209,75 +220,94 @@ let is_unit_type t =
inductive binary relation R, so that R has only one constructor
establishing its reflexivity. *)
-let coq_refl_rel1_pattern = PATTERN [ forall A:_, forall x:A, _ A x x ]
-let coq_refl_rel2_pattern = PATTERN [ forall x:_, _ x x ]
-let coq_refl_reljm_pattern = PATTERN [ forall A:_, forall x:A, _ A x A x ]
+type equation_kind =
+ | MonomorphicLeibnizEq of constr * constr
+ | PolymorphicLeibnizEq of constr * constr * constr
+ | HeterogenousEq of constr * constr * constr * constr
+
+exception NoEquationFound
+
+let coq_refl_leibniz1_pattern = PATTERN [ forall x:_, _ x x ]
+let coq_refl_leibniz2_pattern = PATTERN [ forall A:_, forall x:A, _ A x x ]
+let coq_refl_jm_pattern = PATTERN [ forall A:_, forall x:A, _ A x A x ]
+
+open Libnames
let match_with_equation t =
- let (hdapp,args) = decompose_app t in
- match (kind_of_term hdapp) with
- | Ind ind ->
+ if not (isApp t) then raise NoEquationFound;
+ let (hdapp,args) = destApp t in
+ match kind_of_term hdapp with
+ | Ind ind ->
+ if IndRef ind = glob_eq then
+ Some (build_coq_eq_data()),hdapp,
+ PolymorphicLeibnizEq(args.(0),args.(1),args.(2))
+ else if IndRef ind = glob_identity then
+ Some (build_coq_identity_data()),hdapp,
+ PolymorphicLeibnizEq(args.(0),args.(1),args.(2))
+ else if IndRef ind = glob_jmeq then
+ Some (build_coq_jmeq_data()),hdapp,
+ HeterogenousEq(args.(0),args.(1),args.(2),args.(3))
+ else
let (mib,mip) = Global.lookup_inductive ind in
- let constr_types = mip.mind_nf_lc in
+ let constr_types = mip.mind_nf_lc in
let nconstr = Array.length mip.mind_consnames in
- if nconstr = 1 &&
- (is_matching coq_refl_rel1_pattern constr_types.(0) ||
- is_matching coq_refl_rel2_pattern constr_types.(0) ||
- is_matching coq_refl_reljm_pattern constr_types.(0))
- then
- Some (hdapp,args)
- else
- None
- | _ -> None
-
-let is_equation t = op2bool (match_with_equation t)
+ if nconstr = 1 then
+ if is_matching coq_refl_leibniz1_pattern constr_types.(0) then
+ None, hdapp, MonomorphicLeibnizEq(args.(0),args.(1))
+ else if is_matching coq_refl_leibniz2_pattern constr_types.(0) then
+ None, hdapp, PolymorphicLeibnizEq(args.(0),args.(1),args.(2))
+ else if is_matching coq_refl_jm_pattern constr_types.(0) then
+ None, hdapp, HeterogenousEq(args.(0),args.(1),args.(2),args.(3))
+ else raise NoEquationFound
+ else raise NoEquationFound
+ | _ -> raise NoEquationFound
+
+let is_inductive_equality ind =
+ let (mib,mip) = Global.lookup_inductive ind in
+ let nconstr = Array.length mip.mind_consnames in
+ nconstr = 1 && constructor_nrealargs (Global.env()) (ind,1) = 0
let match_with_equality_type t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
- | Ind ind when args <> [] ->
- let (mib,mip) = Global.lookup_inductive ind in
- let nconstr = Array.length mip.mind_consnames in
- if nconstr = 1 && constructor_nrealargs (Global.env()) (ind,1) = 0
- then
- Some (hdapp,args)
- else
- None
- | _ -> None
+ | Ind ind when is_inductive_equality ind -> Some (hdapp,args)
+ | _ -> None
+
+let is_equality_type t = op2bool (match_with_equality_type t)
let coq_arrow_pattern = PATTERN [ ?X1 -> ?X2 ]
let match_arrow_pattern t =
match matches coq_arrow_pattern t with
| [(m1,arg);(m2,mind)] -> assert (m1=meta1 & m2=meta2); (arg, mind)
- | _ -> anomaly "Incorrect pattern matching"
+ | _ -> anomaly "Incorrect pattern matching"
let match_with_nottype t =
try
let (arg,mind) = match_arrow_pattern t in
if is_empty_type mind then Some (mind,arg) else None
- with PatternMatchingFailure -> None
+ with PatternMatchingFailure -> None
let is_nottype t = op2bool (match_with_nottype t)
-
+
let match_with_forall_term c=
match kind_of_term c with
| Prod (nam,a,b) -> Some (nam,a,b)
| _ -> None
-let is_forall_term c = op2bool (match_with_forall_term c)
+let is_forall_term c = op2bool (match_with_forall_term c)
let match_with_imp_term c=
match kind_of_term c with
| Prod (_,a,b) when not (dependent (mkRel 1) b) ->Some (a,b)
| _ -> None
-let is_imp_term c = op2bool (match_with_imp_term c)
+let is_imp_term c = op2bool (match_with_imp_term c)
let match_with_nodep_ind t =
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
- | Ind ind ->
+ | Ind ind ->
let (mib,mip) = Global.lookup_inductive ind in
if Array.length (mib.mind_packets)>1 then None else
let nodep_constr = has_nodep_prod_after mib.mind_nparams in
@@ -286,24 +316,24 @@ let match_with_nodep_ind t =
if mip.mind_nrealargs=0 then args else
fst (list_chop mib.mind_nparams args) in
Some (hdapp,params,mip.mind_nrealargs)
- else
+ else
None
| _ -> None
-
+
let is_nodep_ind t=op2bool (match_with_nodep_ind t)
let match_with_sigma_type t=
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
- | Ind ind ->
+ | Ind ind ->
let (mib,mip) = Global.lookup_inductive ind in
if (Array.length (mib.mind_packets)=1) &&
(mip.mind_nrealargs=0) &&
(Array.length mip.mind_consnames=1) &&
has_nodep_prod_after (mib.mind_nparams+1) mip.mind_nf_lc.(0) then
- (*allowing only 1 existential*)
+ (*allowing only 1 existential*)
Some (hdapp,args)
- else
+ else
None
| _ -> None
@@ -323,21 +353,58 @@ let rec first_match matcher = function
let coq_eq_pattern_gen eq = lazy PATTERN [ %eq ?X1 ?X2 ?X3 ]
let coq_eq_pattern = coq_eq_pattern_gen coq_eq_ref
let coq_identity_pattern = coq_eq_pattern_gen coq_identity_ref
+let coq_jmeq_pattern = lazy PATTERN [ %coq_jmeq_ref ?X1 ?X2 ?X3 ?X4 ]
+let coq_eq_true_pattern = lazy PATTERN [ %coq_eq_true_ref ?X1 ]
let match_eq eqn eq_pat =
- match matches (Lazy.force eq_pat) eqn with
+ let pat = try Lazy.force eq_pat with _ -> raise PatternMatchingFailure in
+ match matches pat eqn with
| [(m1,t);(m2,x);(m3,y)] ->
assert (m1 = meta1 & m2 = meta2 & m3 = meta3);
- (t,x,y)
- | _ -> anomaly "match_eq: an eq pattern should match 3 terms"
+ PolymorphicLeibnizEq (t,x,y)
+ | [(m1,t);(m2,x);(m3,t');(m4,x')] ->
+ assert (m1 = meta1 & m2 = meta2 & m3 = meta3 & m4 = meta4);
+ HeterogenousEq (t,x,t',x')
+ | _ -> anomaly "match_eq: an eq pattern should match 3 or 4 terms"
let equalities =
[coq_eq_pattern, build_coq_eq_data;
+ coq_jmeq_pattern, build_coq_jmeq_data;
coq_identity_pattern, build_coq_identity_data]
-let find_eq_data_decompose eqn = (* fails with PatternMatchingFailure *)
+let find_eq_data eqn = (* fails with PatternMatchingFailure *)
first_match (match_eq eqn) equalities
+let extract_eq_args gl = function
+ | MonomorphicLeibnizEq (e1,e2) ->
+ let t = Tacmach.pf_type_of gl e1 in (t,e1,e2)
+ | PolymorphicLeibnizEq (t,e1,e2) -> (t,e1,e2)
+ | HeterogenousEq (t1,e1,t2,e2) ->
+ if Tacmach.pf_conv_x gl t1 t2 then (t1,e1,e2)
+ else raise PatternMatchingFailure
+
+let find_eq_data_decompose gl eqn =
+ let (lbeq,eq_args) = find_eq_data eqn in
+ (lbeq,extract_eq_args gl eq_args)
+
+let inversible_equalities =
+ [coq_eq_pattern, build_coq_inversion_eq_data;
+ coq_jmeq_pattern, build_coq_inversion_jmeq_data;
+ coq_identity_pattern, build_coq_inversion_identity_data;
+ coq_eq_true_pattern, build_coq_inversion_eq_true_data]
+
+let find_this_eq_data_decompose gl eqn =
+ let (lbeq,eq_args) =
+ try (*first_match (match_eq eqn) inversible_equalities*)
+ find_eq_data eqn
+ with PatternMatchingFailure ->
+ errorlabstrm "" (str "No primitive equality found.") in
+ let eq_args =
+ try extract_eq_args gl eq_args
+ with PatternMatchingFailure ->
+ error "Don't know what to do with JMeq on arguments not of same type." in
+ (lbeq,eq_args)
+
open Tacmach
open Tacticals
@@ -369,7 +436,7 @@ let match_sigma ex ex_pat =
anomaly "match_sigma: a successful sigma pattern should match 4 terms"
let find_sigma_data_decompose ex = (* fails with PatternMatchingFailure *)
- first_match (match_sigma ex)
+ first_match (match_sigma ex)
[coq_existT_pattern, build_sigma_type]
(* Pattern "(sig ?1 ?2)" *)
@@ -407,14 +474,14 @@ let op_sum = coq_sumbool_ref
let match_eqdec t =
let eqonleft,op,subst =
try true,op_sum,matches (Lazy.force coq_eqdec_inf_pattern) t
- with PatternMatchingFailure ->
+ with PatternMatchingFailure ->
try false,op_sum,matches (Lazy.force coq_eqdec_inf_rev_pattern) t
- with PatternMatchingFailure ->
+ with PatternMatchingFailure ->
try true,op_or,matches (Lazy.force coq_eqdec_pattern) t
- with PatternMatchingFailure ->
+ with PatternMatchingFailure ->
false,op_or,matches (Lazy.force coq_eqdec_rev_pattern) t in
match subst with
- | [(_,typ);(_,c1);(_,c2)] ->
+ | [(_,typ);(_,c1);(_,c2)] ->
eqonleft, Libnames.constr_of_global (Lazy.force op), c1, c2, typ
| _ -> anomaly "Unexpected pattern"