https://github.com/EasyCrypt/easycrypt
Tip revision: f47fb5394d471bb609b84ab7140bc0164d1fa2a3 authored by Cécile BARITEL-RUET on 26 November 2019, 07:51:24 UTC
better with the files
better with the files
Tip revision: f47fb53
ecFMatching.ml
(* -------------------------------------------------------------------- *)
open EcUtils
open EcFol
open EcTypes
open EcPath
open EcIdent
open EcEnv
open EcModules
open EcPattern
open Psubst
open EcGenRegexp
type verbose = {
verbose_match : bool;
verbose_rule : bool;
verbose_type : bool;
verbose_bind_restr : bool;
verbose_add_meta : bool;
verbose_abstract : bool;
verbose_reduce : bool;
verbose_conv : bool;
verbose_show_ignored_or : bool;
verbose_show_or : bool;
verbose_begin_match : bool;
verbose_translate_error : bool;
verbose_subst : bool;
verbose_unienv : bool;
verbose_eta : bool;
verbose_show_match : bool;
verbose_add_reduce : bool;
verbose_saturate : bool;
}
let no_verbose : verbose = {
verbose_match = false;
verbose_rule = false;
verbose_type = false;
verbose_bind_restr = false;
verbose_add_meta = false;
verbose_abstract = false;
verbose_reduce = false;
verbose_conv = false;
verbose_show_ignored_or = false;
verbose_show_or = false;
verbose_begin_match = false;
verbose_translate_error = false;
verbose_subst = false;
verbose_unienv = false;
verbose_eta = false;
verbose_show_match = false;
verbose_add_reduce = false;
verbose_saturate = false;
}
let full_verbose : verbose = {
verbose_match = true;
verbose_rule = true;
verbose_type = true;
verbose_bind_restr = true;
verbose_add_meta = true;
verbose_abstract = true;
verbose_reduce = true;
verbose_conv = true;
verbose_show_ignored_or = true;
verbose_show_or = true;
verbose_begin_match = true;
verbose_translate_error = true;
verbose_subst = true;
verbose_unienv = true;
verbose_eta = true;
verbose_show_match = true;
verbose_add_reduce = true;
verbose_saturate = true;
}
let debug_verbose : verbose = {
verbose_match = true;
verbose_rule = true;
verbose_type = false;
verbose_bind_restr = false;
verbose_add_meta = false;
verbose_abstract = false;
verbose_reduce = false;
verbose_conv = false;
verbose_show_ignored_or = false;
verbose_show_or = false;
verbose_begin_match = true;
verbose_translate_error = false;
verbose_subst = false;
verbose_unienv = false;
verbose_eta = false;
verbose_show_match = false;
verbose_add_reduce = false;
verbose_saturate = false;
}
let env_verbose = no_verbose
(* ---------------------------------------------------------------------- *)
exception Matches
exception NoMatches
exception CannotUnify
exception NoNext
type match_env = {
me_unienv : EcUnify.unienv;
me_meta_vars : ogty Mid.t;
me_matches : pattern Mid.t;
}
type stmt_engine = pattern list Mid.t
type environment = {
env_hyps : EcEnv.LDecl.hyps;
env_match : match_env;
env_red_info_match : EcReduction.reduction_info;
env_red_info_same_meta : EcReduction.reduction_info;
env_red_info_conv : EcReduction.reduction_info;
env_meta_restr_binds : pbindings Mid.t;
env_verbose : verbose;
}
type pat_continuation =
| ZTop
| Znamed of pattern * meta_name * pbindings option * pat_continuation
(* Zor (cont, e_list, ne) :
- cont : the continuation if the matching is correct
- e_list : if not, the reverted sorted list of next engines to try matching with
- ne : if no match at all, then take the nengine to go up *)
| Zor of pat_continuation * eng list * neng
(* Zand (before, after, cont) :
- before : list of couples (pattern, pattern) that has already been checked
- after : list of couples (pattern, pattern) to check in the following
- reductions : list of possible reduction before asking zand
- cont : continuation if all the matches succeed *)
| Zand of (pattern * pattern) list
* (pattern * pattern) list
* pat_continuation
| Zreduce of pat_continuation * eng * neng
| Zconv of pat_continuation * eng * neng
and eng = {
e_pattern1 : pattern;
e_pattern2 : pattern;
e_continuation : pat_continuation;
e_env : environment;
}
and neng = {
ne_continuation : pat_continuation;
ne_env : environment;
}
type ismatch =
| Match
| NoMatch
(* -------------------------------------------------------------------- *)
let menv_copy (me : match_env) =
{ me with me_unienv = EcUnify.UniEnv.copy me.me_unienv }
let env_copy (e : environment) =
{ e with env_match = menv_copy e.env_match }
(* -------------------------------------------------------------------- *)
let menv_of_hyps (hy : LDecl.hyps) =
{ me_unienv = EcProofTyping.unienv_of_hyps hy;
me_meta_vars = Mid.empty;
me_matches = Mid.empty; }
(* -------------------------------------------------------------------- *)
let menv_add_form x ty menv =
assert (not (Mid.mem x menv.me_meta_vars));
{ menv with
me_meta_vars = Mid.add x (OGTty (Some ty)) menv.me_meta_vars; }
(* -------------------------------------------------------------------- *)
let menv_add_mem x menv =
assert (not (Mid.mem x menv.me_meta_vars));
{ menv with
me_meta_vars = Mid.add x (OGTmem None) menv.me_meta_vars; }
(* -------------------------------------------------------------------------- *)
let saturate (me : match_env) =
let ue = me.me_unienv in
let mtch = me.me_matches in
let sty = { EcTypes.ty_subst_id with ts_u = EcUnify.UniEnv.assubst ue } in
let subst = { ps_patloc = mtch; ps_sty = sty } in
let seen = ref Sid.empty in
let rec for_ident id value subst =
if Sid.mem id !seen then subst else begin
seen := Sid.add id !seen;
let subst =
Mid.fold2_inter (fun x bdx _ -> for_ident x bdx)
subst.ps_patloc (pat_fv value) subst in
{ subst with
ps_patloc =
Mid.add id (Psubst.p_subst ~meta:false subst value) subst.ps_patloc }
end
in
let subst = Mid.fold_left (fun acc x bd -> for_ident x bd acc)
subst subst.ps_patloc in
{ me with me_matches = subst.ps_patloc }
let psubst_of_menv env =
let sty = { EcTypes.ty_subst_id with
ts_u = EcUnify.UniEnv.assubst env.me_unienv } in
{ ps_patloc = env.me_matches; ps_sty = sty }
let e_copy e = { e with e_env = env_copy e.e_env }
let zor e = function
| [] -> e
| l ->
match e.e_continuation with
| Zor (c, l1, ne) ->
{ e with e_continuation = Zor (c, l1 @ (List.map e_copy l), ne) }
| c ->
let ne = e_copy e in
let ne = { ne_env = ne.e_env ;
ne_continuation = ne.e_continuation; } in
{ e with e_continuation = Zor (c, List.map e_copy l, ne) }
(* -------------------------------------------------------------------- *)
module Debug : sig
val debug_h_red_strat : environment -> pattern -> pattern -> int -> unit
val debug_h_red_strat_next : environment -> unit
val debug_type : environment -> ty -> ty -> unit
val debug_ogty : environment -> pattern -> pattern -> bool -> unit
val debug_bind_restr : environment -> ident -> unit
val debug_add_match : environment -> bool -> ident -> pattern -> unit
val debug_higher_order_abstract_eq : environment -> bool -> pattern -> pattern -> unit
val debug_higher_order_to_abstract : environment -> pattern -> pattern -> unit
val debug_higher_order_is_abstract : environment -> pattern -> pattern -> unit
val debug_try_match : environment -> pattern -> pattern -> pat_continuation -> unit
val debug_which_rule : environment -> string -> unit
val debug_result_match : environment -> ismatch -> unit
val debug_try_reduce : environment -> pattern -> pattern -> unit
val debug_try_conv : environment -> pattern -> pattern -> unit
val debug_reduce : environment -> pattern -> pattern -> pattern -> pattern -> bool -> unit
val debug_reduce_incorrect : environment -> pattern -> pattern -> unit
val debug_found_match : environment -> unit
val debug_no_match_found : environment -> unit
val debug_ignore_ors : environment -> unit
val debug_another_or : environment -> unit
val debug_different_forms : environment -> form -> form -> unit
val debug_try_translate_higher_order : environment -> pattern -> string -> unit
val debug_begin_match : environment -> pattern -> pattern -> unit
val debug_show_pattern : environment -> pattern -> unit
val debug_translate_error : environment -> string -> unit
val debug_eta_expansion : environment -> meta_name -> ogty -> unit
val debug_unienv : environment -> unit
val debug_subst : environment -> pattern -> pattern -> unit
val debug_no_eta : environment -> pbinding -> pattern -> bool -> unit
val debug_show_matches : environment -> unit
val debug_add_reduce : environment -> int -> unit
val debug_saturate : environment -> bool -> unit
end = struct
let debug_saturate menv is_before =
if menv.env_verbose.verbose_saturate then
let env = LDecl.toenv menv.env_hyps in
if is_before then EcEnv.notify env `Warning "----- try saturate"
else EcEnv.notify env `Warning "----- finish saturate"
let debug_add_reduce menv i =
if menv.env_verbose.verbose_add_reduce then
let env = LDecl.toenv menv.env_hyps in
(* let ppe = EcPrinting.PPEnv.ofenv env in *)
EcEnv.notify env `Warning "--- add_reduce : %i" i
let debug_no_eta menv (_id,_ogty) _p _b =
if menv.env_verbose.verbose_eta then
let env = LDecl.toenv menv.env_hyps in
(* let ppe = EcPrinting.PPEnv.ofenv env in *)
EcEnv.notify env `Warning
"--- eta could not be applied because of type restrictions"
let debug_h_red_strat_next menv =
if menv.env_verbose.verbose_reduce then
let env = LDecl.toenv menv.env_hyps in
EcEnv.notify env `Warning "----- next red"
let debug_h_red_strat menv p1 p2 i =
if menv.env_verbose.verbose_reduce then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
let pcompat =
match oget menv.env_red_info_match.EcReduction.logic
with `Full -> true | `ProductCompat -> false
in
let f op args =
match op_kind op, args with
| Some (`Not), [_] when pcompat ->
EcEnv.notify env `Warning "try to reduce !"
| Some (`Imp), [_;_] when pcompat ->
EcEnv.notify env `Warning "try to reduce =>"
| Some (`Iff), [_;_] when pcompat ->
EcEnv.notify env `Warning "try to reduce <=>"
| Some (`And `Asym), [_;_] ->
EcEnv.notify env `Warning "try to reduce a&&"
| Some (`Or `Asym), [_;_] ->
EcEnv.notify env `Warning "try to reduce a||"
| Some (`And `Sym ), [_;_] ->
EcEnv.notify env `Warning "try to reduce &&"
| Some (`Or `Sym ), [_;_] ->
EcEnv.notify env `Warning "try to reduce ||"
| Some (`Int_le ), [_;_] ->
EcEnv.notify env `Warning "try to reduce i <="
| Some (`Int_lt ), [_;_] ->
EcEnv.notify env `Warning "try to reduce i <"
| Some (`Real_le ), [_;_] ->
EcEnv.notify env `Warning "try to reduce r <="
| Some (`Real_lt ), [_;_] ->
EcEnv.notify env `Warning "try to reduce r <"
| Some (`Int_add ), [f1;f2] ->
EcEnv.notify env `Warning "try to reduce i : (%a) + (%a)"
(EcPrinting.pp_pattern ppe) f1
(EcPrinting.pp_pattern ppe) f2
| Some (`Int_opp ), [_] ->
EcEnv.notify env `Warning "try to reduce i -"
| Some (`Int_mul ), [_;_] ->
EcEnv.notify env `Warning "try to reduce i *"
| Some (`Real_add ), [_;_] ->
EcEnv.notify env `Warning "try to reduce r +"
| Some (`Real_opp ), [_] ->
EcEnv.notify env `Warning "try to reduce r -"
| Some (`Real_mul ), [_;_] ->
EcEnv.notify env `Warning "try to reduce r *"
| Some (`Real_inv ), [_] ->
EcEnv.notify env `Warning "try to reduce inv"
| Some (`Eq ), [_;_] ->
EcEnv.notify env `Warning "try to reduce ="
| _ ->
EcEnv.notify env `Warning "try to reduce other"
in
match i with
| 3 -> begin
match p1.p_node with
| Pat_Fun_Symbol
(Sym_Form_App _, { p_node = Pat_Axiom (Axiom_Op (_, p,_tys,_))} :: args)
when is_some menv.env_red_info_match.EcReduction.logic
&& is_logical_op p ->
f p args;
EcEnv.notify env `Warning "hr- h_red_strat step %i,%i" i 3
| _ ->
EcEnv.notify env `Warning "hr- h_red_strat step %i : %i" i 5;
match p2.p_node with
| Pat_Fun_Symbol
(Sym_Form_App _, { p_node = Pat_Axiom (Axiom_Op (_, p,_tys,_))} :: args)
when is_some menv.env_red_info_match.EcReduction.logic
&& is_logical_op p ->
f p args;
EcEnv.notify env `Warning "hr- h_red_strat step %i,%i" i 4
| _ ->
EcEnv.notify env `Warning "hr- h_red_strat step %i : %i" i 6
end
| _ ->
EcEnv.notify env `Warning "hr- h_red_strat step %i" i
let debug_subst menv p1 p2 =
if menv.env_verbose.verbose_subst then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning "-s- Subst : %a -> %a"
(EcPrinting.pp_pattern ppe) p1
(EcPrinting.pp_pattern ppe) p2
let debug_eta_expansion menv i t =
if menv.env_verbose.verbose_type then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
let p = p_quant Llambda [i,t] (meta_var (EcIdent.create "") None OGTany) in
let f = match t with
| OGTty (Some t) -> f_quant Llambda [i,GTty t] (f_local (EcIdent.create "") t)
| _ -> f_local (EcIdent.create "no type") tbool in
EcEnv.notify env `Warning "--! Eta-expansion with bindings : %a != %a"
(EcPrinting.pp_pattern ppe) p
(EcPrinting.pp_form ppe) f
let debug_translate_error menv s =
if menv.env_verbose.verbose_type then
let env = LDecl.toenv menv.env_hyps in
EcEnv.notify env `Warning "--! Translate error %s" s
let debug_show_pattern menv p =
if menv.env_verbose.verbose_type then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"### pattern is %a"
(EcPrinting.pp_pattern ppe) p
let debug_type menv ty1 ty2 =
if menv.env_verbose.verbose_type then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"-ty %a ?= %a"
(EcPrinting.pp_type ppe) ty1
(EcPrinting.pp_type ppe) ty2
let debug_ogty menv p1 p2 b =
if menv.env_verbose.verbose_type then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
let s = psubst_of_menv menv.env_match in
let s = Psubst.p_subst_init ~sty:s.Psubst.ps_sty () in
let p1 = Psubst.p_subst s p1 in
EcEnv.notify env `Warning
"--- ogty: %a %s %a"
(EcPrinting.pp_ogty ppe) p1.p_ogty
(if b then "=" else "!=")
(EcPrinting.pp_ogty ppe) p2.p_ogty
let debug_bind_restr menv x =
if menv.env_verbose.verbose_bind_restr then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"Binding restrictions prevents using : %a"
(EcPrinting.pp_local ppe) x
let debug_add_match menv b name p =
if menv.env_verbose.verbose_add_meta then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
if b then
EcEnv.notify env `Warning
"--- Name %a binded to %a"
(EcPrinting.pp_local ppe) name
(EcPrinting.pp_pattern ppe) p
else
EcEnv.notify env `Warning
"-!- Name %a already exists and cannot be unified with %a"
(EcPrinting.pp_local ppe) name
(EcPrinting.pp_pattern ppe) p
let debug_higher_order_abstract_eq menv b p1 p2 =
if menv.env_verbose.verbose_abstract then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
if b then
EcEnv.notify env `Warning
"--- %a is convertible to %a\n"
(EcPrinting.pp_pattern ppe) p1
(EcPrinting.pp_pattern ppe) p2
else
EcEnv.notify env `Warning
"-!- %a is not convertible to %a\n"
(EcPrinting.pp_pattern ppe) p1
(EcPrinting.pp_pattern ppe) p2
let debug_unienv menv =
if menv.env_verbose.verbose_unienv then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
let vars = EcUnify.UniEnv.uvars menv.env_match.me_unienv in
let vars = EcUid.Suid.elements vars in
let s = EcUnify.UniEnv.assubst menv.env_match.me_unienv in
let pp_names ppe fmt name =
match s name with
| Some t ->
Format.fprintf fmt "%a <- %a"
(EcPrinting.pp_tyunivar ppe) name
(EcPrinting.pp_type ppe) t
| None ->
Format.fprintf fmt "%a : not unified"
(EcPrinting.pp_tyunivar ppe) name
in
EcEnv.notify env `Warning "Unienv: %a"
(EcPrinting.pp_list "@ and@ " (pp_names ppe)) vars
let debug_show_matches menv =
if menv.env_verbose.verbose_show_match then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
let pp_names ppe fmt (name,p) =
Format.fprintf fmt "%a <- (%a : %a)"
(EcPrinting.pp_local ppe) name
(EcPrinting.pp_pattern ppe) p
(EcPrinting.pp_ogty ppe) p.p_ogty in
EcEnv.notify env `Warning "Current matching: %a"
(EcPrinting.pp_list "@ and@ " (pp_names ppe))
(Mid.bindings menv.env_match.me_matches);
debug_unienv menv
let debug_higher_order_to_abstract menv p1 p2 =
if menv.env_verbose.verbose_abstract then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"try to abstract (%a) in : %a"
(EcPrinting.pp_pattern ppe) p1
(EcPrinting.pp_pattern ppe) p2
let debug_higher_order_is_abstract menv p1 p2 =
if menv.env_verbose.verbose_abstract then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"Abstracted (%a) in : %a"
(EcPrinting.pp_pattern ppe) p1
(EcPrinting.pp_pattern ppe) p2
let debug_try_translate_higher_order menv p s =
if menv.env_verbose.verbose_abstract then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"Try to translate to form (%s) : %a" s
(EcPrinting.pp_pattern ppe) p
let rec compute_zands c = function
| ZTop -> c
| Zor (ct,_,_) -> compute_zands c ct
| Zand (_,l,ct) -> compute_zands (c + List.length l) ct
| Znamed (_,_,_,ct) -> compute_zands c ct
| Zreduce (ct,_,_) -> compute_zands c ct
| Zconv (ct,_,_) -> compute_zands c ct
let debug_try_match menv p a c =
if menv.env_verbose.verbose_match then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"---- (%i) try match : %a : %a"
(compute_zands 0 c)
(EcPrinting.pp_pattern ppe) p
(EcPrinting.pp_ogty ppe) p.p_ogty;
EcEnv.notify env `Warning "---- with %a : %a"
(EcPrinting.pp_pattern ppe) a
(EcPrinting.pp_ogty ppe) a.p_ogty
let debug_which_rule menv s =
if menv.env_verbose.verbose_rule then
let env = LDecl.toenv menv.env_hyps in
EcEnv.notify env `Warning "rule %s" s
let debug_result_match menv m =
if menv.env_verbose.verbose_match then
let env = LDecl.toenv menv.env_hyps in
EcEnv.notify env `Warning (match m with
| Match -> "Match"
| NoMatch -> "No match")
let debug_try_reduce menv p a =
if menv.env_verbose.verbose_reduce then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning "Later : try reduce (%a,%a)"
(EcPrinting.pp_pattern ppe) p
(EcPrinting.pp_pattern ppe) a
let debug_try_conv menv p a =
if menv.env_verbose.verbose_conv then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning "Later : try conv (%a,%a)"
(EcPrinting.pp_pattern ppe) p
(EcPrinting.pp_pattern ppe) a
let debug_reduce menv p1 p2 a1 a2 b =
if menv.env_verbose.verbose_reduce then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
if b then begin
EcEnv.notify env `Warning "Reduction (%s beta, %s delta):"
(if menv.env_red_info_match.EcReduction.beta then "with" else "without")
(if menv.env_red_info_match.EcReduction.delta_p (EcPath.psymbol "toto")
then "with" else "without");
EcEnv.notify env `Warning "***1: before %a"
(EcPrinting.pp_pattern ppe) p1;
EcEnv.notify env `Warning "***1: after %a"
(EcPrinting.pp_pattern ppe) p2;
EcEnv.notify env `Warning "***2: before %a"
(EcPrinting.pp_pattern ppe) a1
end
else begin
EcEnv.notify env `Warning "Ignore reduction (%s beta, %s delta):"
(if menv.env_red_info_match.EcReduction.beta then "with" else "without")
(if menv.env_red_info_match.EcReduction.delta_p (EcPath.psymbol "toto")
then "with" else "without");
EcEnv.notify env `Warning "***1: before %a"
(EcPrinting.pp_pattern ppe) p1
end;
EcEnv.notify env `Warning "***2: after %a"
(EcPrinting.pp_pattern ppe) a2;
debug_show_matches menv
let debug_reduce_incorrect menv p a =
if menv.env_verbose.verbose_reduce then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning "Incorrect reduction for (%a,%a)"
(EcPrinting.pp_pattern ppe) p
(EcPrinting.pp_pattern ppe) a
let debug_found_match menv =
if menv.env_verbose.verbose_match then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
let pp_names ppe fmt (name,p) =
Format.fprintf fmt "%a <- (%a : %a)"
(EcPrinting.pp_local ppe) name
(EcPrinting.pp_pattern ppe) p
(EcPrinting.pp_ogty ppe) p.p_ogty in
EcEnv.notify env `Warning "Matching successful: %a"
(EcPrinting.pp_list "@ and@ " (pp_names ppe))
(Mid.bindings menv.env_match.me_matches);
debug_unienv menv
let debug_no_match_found menv =
if menv.env_verbose.verbose_match then
let env = LDecl.toenv menv.env_hyps in
EcEnv.notify env `Warning
"--- Matching unsuccessful"
let debug_ignore_ors menv =
if menv.env_verbose.verbose_show_ignored_or then
let env = LDecl.toenv menv.env_hyps in
EcEnv.notify env `Warning "Ignore some Or"
let debug_another_or menv =
if menv.env_verbose.verbose_show_or then
let env = LDecl.toenv menv.env_hyps in
EcEnv.notify env `Warning "Another Or's case"
let debug_different_forms menv f1 f2 =
if menv.env_verbose.verbose_match then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning "form(%a : %a) != form(%a : %a)"
(EcPrinting.pp_form ppe) f1
(EcPrinting.pp_type ppe) f1.f_ty
(EcPrinting.pp_form ppe) f2
(EcPrinting.pp_type ppe) f2.f_ty
let debug_begin_match menv p a =
if menv.env_verbose.verbose_begin_match then
let env = LDecl.toenv menv.env_hyps in
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning
"========================= Begin new match ===========================";
EcEnv.notify env `Warning "=== %a"
(EcPrinting.pp_pattern ppe) p;
EcEnv.notify env `Warning "=== %a ==="
(EcPrinting.pp_pattern ppe) a
end
let saturate env =
(* Debug.debug_saturate env true;
* Debug.debug_show_matches env; *)
let env = { env with env_match = saturate env.env_match } in
(* Debug.debug_show_matches env;
* Debug.debug_saturate env false; *)
env
(* -------------------------------------------------------------------------- *)
let my_mem = EcIdent.create "new_mem"
let form_of_expr = EcFol.form_of_expr my_mem
let suffix2 (l1 : 'a list) (l2 : 'b list) : ('a list * 'a list) * ('b list * 'b list) =
let (l12,l11), (l22,l21) = List.prefix2 (List.rev l1) (List.rev l2) in
(List.rev l11,List.rev l12), (List.rev l21,List.rev l22)
let mem_ty_univar (ty : ty) =
try ty_check_uni ty; true
with
| FoundUnivar -> false
let is_modty (env : EcEnv.env) (m : mpath) (mt : module_type) (mr : mod_restr) =
let ms = EcEnv.Mod.by_mpath_opt m env in
match ms with
| None -> false
| Some ms ->
let ms = ms.me_sig in
try EcTyping.check_modtype_with_restrictions env m ms mt mr; true
with EcTyping.TymodCnvFailure _ -> false
(* -------------------------------------------------------------------------- *)
module Translate = struct
exception Invalid_Type of pattern
let invalid env p =
let gstate = EcEnv.gstate env in
let verbose = EcGState.getflag "debug" gstate in
if (if verbose then debug_verbose else env_verbose).verbose_translate_error then
let ppe = EcPrinting.PPEnv.ofenv env in
EcEnv.notify env `Warning "--!-- Invalid translation in : %a"
(EcPrinting.pp_pattern ppe) p
let rec form_of_pattern env (p : pattern) : form =
match p.p_node with
| Pat_Meta_Name (Some p,_,_) -> form_of_pattern env p
| Pat_Meta_Name (_,_,_) -> invalid env p; raise (Invalid_Type p)
| Pat_Sub _ -> invalid env p; raise (Invalid_Type p)
| Pat_Or [p] -> form_of_pattern env p
| Pat_Or _ -> invalid env p; raise (Invalid_Type p)
| Pat_Red_Strat (p,_) -> form_of_pattern env p
| Pat_Axiom (Axiom_Int z) -> f_int z
| Pat_Axiom (Axiom_Local (id,ty)) -> f_local id ty
| Pat_Axiom (Axiom_Op (_, op,lty, Some ty)) -> f_op op lty ty
| Pat_Axiom _ -> invalid env p; raise (Invalid_Type p)
| Pat_Stmt _ -> invalid env p; raise (Invalid_Type p)
| Pat_Fun_Symbol (s, lp) ->
match s, lp with
| Sym_Form_If, [p1;p2;p3] -> f_if (form_of_pattern env p1)
(form_of_pattern env p2)
(form_of_pattern env p3)
| Sym_Form_App _, p::lp -> f_ty_app env (form_of_pattern env p)
(List.map (form_of_pattern env) lp)
| Sym_Form_Tuple, t -> f_tuple (List.map (form_of_pattern env) t)
| Sym_Form_Proj (i,ty), [p] -> f_proj (form_of_pattern env p) i ty
| Sym_Form_Match ty, p::lp -> mk_form (Fmatch (form_of_pattern env p,
List.map (form_of_pattern env) lp,
ty)) ty
| Sym_Form_Let lp, [p1;p2] -> f_let lp (form_of_pattern env p1)
(form_of_pattern env p2)
| Sym_Form_Pvar ty, [pv;pm] -> f_pvar (prog_var_of_pattern env pv) ty
(memory_of_pattern env pm)
| Sym_Form_Prog_var _, _ -> invalid env p; raise (Invalid_Type p)
| Sym_Form_Glob, [mp;mem] -> f_glob (mpath_of_pattern env mp)
(memory_of_pattern env mem)
| Sym_Form_Hoare_F, [pr;xp;po] ->
f_hoareF (form_of_pattern env pr)
(xpath_of_pattern env xp) (form_of_pattern env po)
| Sym_Form_Hoare_S, [pm;pr;s;po] ->
f_hoareS (memenv_of_pattern env pm) (form_of_pattern env pr)
(stmt_of_pattern env s) (form_of_pattern env po)
| Sym_Form_bd_Hoare_F, [pr;xp;po;cmp;bd] ->
f_bdHoareF (form_of_pattern env pr) (xpath_of_pattern env xp)
(form_of_pattern env po) (cmp_of_pattern env cmp)
(form_of_pattern env bd)
| Sym_Form_bd_Hoare_S, [pm;pr;s;po;cmp;bd] ->
f_bdHoareS (memenv_of_pattern env pm) (form_of_pattern env pr) (stmt_of_pattern env s)
(form_of_pattern env po) (cmp_of_pattern env cmp) (form_of_pattern env bd)
| Sym_Form_Equiv_F, [pr;f1;f2;po] ->
f_equivF (form_of_pattern env pr) (xpath_of_pattern env f1) (xpath_of_pattern env f2)
(form_of_pattern env po)
| Sym_Form_Equiv_S, [pm1;pm2;pr;s1;s2;po] ->
f_equivS (memenv_of_pattern env pm1) (memenv_of_pattern env pm2) (form_of_pattern env pr)
(stmt_of_pattern env s1) (stmt_of_pattern env s2) (form_of_pattern env po)
| Sym_Form_Eager_F, [po;s1;f1;f2;s2;pr] ->
f_eagerF (form_of_pattern env po) (stmt_of_pattern env s1) (xpath_of_pattern env f1)
(xpath_of_pattern env f2) (stmt_of_pattern env s2) (form_of_pattern env pr)
| Sym_Form_Pr, [pm;f;args;event] ->
f_pr (memory_of_pattern env pm) (xpath_of_pattern env f) (form_of_pattern env args)
(form_of_pattern env event)
| Sym_Quant (q,pb), [p] ->
let f (id,ogt) = match gty_of_ogty ogt with
| Some gty -> id, gty
| _ -> invalid env p; raise (Invalid_Type p)
in
f_quant q (List.map f pb) (form_of_pattern env p)
| _ -> invalid env p; raise (Invalid_Type p)
and memory_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_Memory m) -> m
| _ -> invalid env p; raise (Invalid_Type p)
and prog_var_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_Prog_Var pv) -> pv
| Pat_Fun_Symbol (Sym_Form_Prog_var k, [xp]) ->
pv (xpath_of_pattern env xp) k
| _ -> invalid env p; raise (Invalid_Type p)
and xpath_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_Xpath xp) -> xp
| Pat_Fun_Symbol (Sym_Xpath, [mp;p]) ->
EcPath.xpath (mpath_of_pattern env mp) (path_of_pattern env p)
| _ -> invalid env p; raise (Invalid_Type p)
and path_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_Op (_, p,[],_)) -> p
| _ -> invalid env p; raise (Invalid_Type p)
and mpath_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_Mpath mp) -> mp
| Pat_Fun_Symbol (Sym_Mpath, mp::margs) ->
mpath (mpath_top_of_pattern env mp) (List.map (mpath_of_pattern env) margs)
| _ -> invalid env p; raise (Invalid_Type p)
and mpath_top_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_Mpath_top m) -> m
| _ -> invalid env p; raise (Invalid_Type p)
and memenv_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_MemEnv m) -> m
| _ -> invalid env p; raise (Invalid_Type p)
and stmt_of_pattern env p = match p.p_node with
| Pat_Stmt g -> stmt (list_of_gen_pattern env g)
| _ -> invalid env p; raise (Invalid_Type p)
and list_of_gen_pattern env g = match g with
| Anchor _ -> []
| Any ->
let p = meta_var (EcIdent.create "any_stmt") None OGTstmt in
invalid env p; raise (Invalid_Type p)
| Base p -> instr_of_pattern env p
| Choice [g] -> list_of_gen_pattern env g
| Choice _ ->
let p = meta_var (EcIdent.create "More or less than one choice") None OGTstmt in
invalid env p; raise (Invalid_Type p)
| Named (Any, name) -> [i_abstract name]
| Named (g, _) -> list_of_gen_pattern env g
| Repeat _ ->
let p = meta_var (EcIdent.create "repeat") None OGTstmt in
invalid env p; raise (Invalid_Type p)
| Seq l -> List.flatten (List.map (list_of_gen_pattern env) l)
and instr_of_pattern env p = match p.p_node with
| Pat_Fun_Symbol (Sym_Instr_Assign, [lv;e]) ->
[i_asgn (lvalue_of_pattern env lv, expr_of_pattern env e)]
| Pat_Fun_Symbol (Sym_Instr_Sample, [lv;e]) ->
[i_rnd (lvalue_of_pattern env lv, expr_of_pattern env e)]
| Pat_Fun_Symbol (Sym_Instr_Call, [f;args]) ->
let args = match args.p_node with
| Pat_Fun_Symbol (Sym_Form_Tuple, lp) -> lp
| _ -> [args] in
[i_call (None, xpath_of_pattern env f, List.map (expr_of_pattern env) args)]
| Pat_Fun_Symbol (Sym_Instr_Call, [{ p_node = Pat_Meta_Name (None, id, None)};f;args])
when EcIdent.name id = "$anything" ->
instr_of_pattern env (p_call None f args)
| Pat_Fun_Symbol (Sym_Instr_Call, [lv;f;args]) ->
let args = match args.p_node with
| Pat_Fun_Symbol (Sym_Form_Tuple, lp) -> lp
| _ -> [args] in
[i_call (Some (lvalue_of_pattern env lv),
xpath_of_pattern env f,
List.map (expr_of_pattern env) args)]
| Pat_Fun_Symbol (Sym_Instr_If, [cond;s1;s2]) ->
[i_if (expr_of_pattern env cond, stmt_of_pattern env s1, stmt_of_pattern env s2)]
| Pat_Fun_Symbol (Sym_Instr_While, [cond;s]) ->
[i_while (expr_of_pattern env cond, stmt_of_pattern env s)]
| Pat_Fun_Symbol (Sym_Instr_Assert, [e]) ->
[i_assert (expr_of_pattern env e)]
| Pat_Stmt g -> list_of_gen_pattern env g
| _ -> invalid env p; raise (Invalid_Type p)
and lvalue_of_pattern env p =
match p.p_node with
| Pat_Axiom (Axiom_Lvalue lv) -> lv
| Pat_Fun_Symbol (Sym_Form_Tuple, t) ->
let t = List.map (lvalue_of_pattern env) t in
let t = List.map (function LvVar (x,t) -> (x,t)
| _ -> invalid env p; raise (Invalid_Type p)) t in
LvTuple t
| _ -> invalid env p; raise (Invalid_Type p)
and expr_of_pattern env p =
try match expr_of_form (form_of_pattern env p) with
| Some e -> e
| None -> invalid env p; raise (Invalid_Type p)
with
| Invalid_Type p -> invalid env p; raise (Invalid_Type p)
and cmp_of_pattern env p = match p.p_node with
| Pat_Axiom (Axiom_Hoarecmp cmp) -> cmp
| _ -> invalid env p; raise (Invalid_Type p)
let form_of_pattern env p =
match p.p_node with
| Pat_Sub p -> form_of_pattern env p
| _ -> form_of_pattern env p
end
(* let simplify env p =
* try pat_form (Translate.form_of_pattern (LDecl.toenv env.env_hyps) p)
* with Translate.Invalid_Type s ->
* Debug.debug_translate_error env s;
* p *)
module EQ : sig
val ty : environment -> ty -> ty -> bool
val memtype : environment -> EcMemory.memtype -> EcMemory.memtype -> bool
val memory : environment -> EcMemory.memory -> EcMemory.memory -> bool
val memenv : environment -> EcMemory.memenv -> EcMemory.memenv -> bool
val mpath : environment -> mpath -> mpath -> bool
val mpath_top : environment -> mpath_top -> mpath_top -> bool
val xpath : environment -> xpath -> xpath -> bool
val name : meta_name -> meta_name -> bool
val instr : environment -> instr -> instr -> bool
val stmt : environment -> stmt -> stmt -> bool
val lvalue : environment -> lvalue -> lvalue -> bool
val op : environment -> path * ty list -> path * ty list -> bool
val prog_var : environment -> prog_var -> prog_var -> bool
val hoarecmp : environment -> hoarecmp -> hoarecmp -> bool
val gty : environment -> gty -> gty -> bool
val ogty : environment -> ogty -> ogty -> bool
val binding : environment -> binding -> binding -> bool
val pbinding : environment -> pbinding -> pbinding -> bool
val symbol : environment -> fun_symbol -> fun_symbol -> bool
(* val form : environment -> EcReduction.reduction_info -> form -> form -> bool *)
val axiom : environment -> EcReduction.reduction_info -> axiom -> axiom -> bool
val pattern : environment -> EcReduction.reduction_info -> pattern -> pattern -> bool
end = struct
let rec ty (env : environment) (ty1 : ty) (ty2 : ty) : bool =
try EcUnify.unify (EcEnv.LDecl.toenv env.env_hyps) env.env_match.me_unienv ty1 ty2;
true
with EcUnify.UnificationFailure _ -> false
let memtype (_env : environment) (m1 : EcMemory.memtype) (m2 : EcMemory.memtype) =
EcMemory.mt_equal m1 m2
let memory (_env : environment) (m1 : EcMemory.memory) (m2 : EcMemory.memory) =
EcMemory.mem_equal m1 m2
let memenv (_env : environment) (m1 : EcMemory.memenv) (m2 : EcMemory.memenv) =
EcMemory.me_equal m1 m2
let mpath (env : environment) (m1 : mpath) (m2 : mpath) : bool =
EcReduction.EqTest.for_mp (EcEnv.LDecl.toenv env.env_hyps) m1 m2
let mpath_top (_env : environment) (mt1 : mpath_top) (mt2 : mpath_top) =
EcPath.mt_equal mt1 mt2
let xpath (env : environment) (x1 : xpath) (x2 : xpath) : bool =
EcReduction.EqTest.for_xp (EcEnv.LDecl.toenv env.env_hyps) x1 x2
let name (n1 : meta_name) (n2 : meta_name) = 0 = id_compare n1 n2
let instr (env : environment) (i1 : EcModules.instr) (i2 : EcModules.instr) =
EcReduction.EqTest.for_instr (EcEnv.LDecl.toenv env.env_hyps) i1 i2
let stmt (env : environment) (s1 : EcModules.stmt) (s2 : EcModules.stmt) =
EcReduction.EqTest.for_stmt (EcEnv.LDecl.toenv env.env_hyps) s1 s2
let lvalue (_env : environment) (lv1 : lvalue) (lv2 :lvalue) : bool =
lv_equal lv1 lv2
let op (env : environment)
((op1, lty1) : EcPath.path * EcTypes.ty list)
((op2, lty2) : EcPath.path * EcTypes.ty list) =
EcPath.p_equal op1 op2 && List.for_all2 (ty env) lty1 lty2
let prog_var (env : environment) (x1 : prog_var) (x2 : prog_var) =
pv_equal x1 x2 || (x1.pv_kind = x2.pv_kind && xpath env x1.pv_name x2.pv_name)
let hoarecmp (_env : environment) (c1 : hoarecmp) (c2 : hoarecmp) : bool =
c1 = c2
let gty (env : environment) (gty1 : gty) (gty2 : gty) : bool =
match gty1, gty2 with
| GTty ty1, GTty ty2 -> ty env ty1 ty2
| _,_ -> EcCoreFol.gty_equal gty1 gty2
let ogty (env : environment) (gty1 : ogty) (gty2 : ogty) : bool =
match gty1, gty2 with
| OGTty (Some ty1), OGTty (Some ty2) -> ty env ty1 ty2
| _,_ -> ogty_equal gty1 gty2
let binding env (id1,gt1) (id2,gt2) =
if not (id_equal id1 id2) then false
else gty env gt1 gt2
let pbinding env (id1,ogt1) (id2,ogt2) =
id_equal id1 id2 && ogty env ogt1 ogt2
let symbol (env : environment) (s1 : fun_symbol) (s2 : fun_symbol) : bool =
match s1,s2 with
| Sym_Form_Proj (i1,t1), Sym_Form_Proj (i2,t2) ->
if not (i1 = i2) then false
else ty env t1 t2
| Sym_Form_Pvar t1, Sym_Form_Pvar t2
| Sym_Form_App (Some t1, _), Sym_Form_App (Some t2, _)
| Sym_Form_Match t1, Sym_Form_Match t2 -> ty env t1 t2
| Sym_Form_Let lp1, Sym_Form_Let lp2 -> lp_equal lp1 lp2
| Sym_Form_Prog_var k1, Sym_Form_Prog_var k2 -> k1 = k2
| Sym_Quant (q1,b1), Sym_Quant (q2,b2) ->
if not (q1 = q2) then false
else List.for_all2 (pbinding env) b1 b2
| _,_ -> s1 = s2
let form (env : environment) ri (f1 : form) (f2 : form) =
if ty env f1.f_ty f2.f_ty then begin
Debug.debug_type env f1.f_ty f2.f_ty;
let sty = { EcTypes.ty_subst_id with
ts_u = EcUnify.UniEnv.assubst env.env_match.me_unienv } in
let sf = Fsubst.f_subst_init ~sty () in
let f1, f2 = Fsubst.f_subst sf f1, Fsubst.f_subst sf f2 in
if EcReduction.is_conv_param ri env.env_hyps f1 f2 then true
else begin Debug.debug_different_forms env f1 f2; false end
end
else false
let rec axiom (env : environment) _ (o1 : axiom) (o2 : axiom) : bool =
let aux o1 o2 =
match o1,o2 with
| Axiom_Int f1, Axiom_Int f2 ->
EcBigInt.equal f1 f2
| Axiom_Memory m1, Axiom_Memory m2 ->
memory env m1 m2
| Axiom_MemEnv m1, Axiom_MemEnv m2 ->
memenv env m1 m2
| Axiom_Prog_Var x1, Axiom_Prog_Var x2 ->
prog_var env x1 x2
| Axiom_Op (_, op1, lty1, Some t1), Axiom_Op (_, op2, lty2, Some t2) ->
ty env t1 t2 && op env (op1,lty1) (op2,lty2)
| Axiom_Mpath_top m1, Axiom_Mpath_top m2 ->
mpath_top env m1 m2
| Axiom_Mpath m1, Axiom_Mpath m2 ->
mpath env m1 m2
| Axiom_Mpath { m_top = mt1 ; m_args = [] }, Axiom_Mpath_top mt2
| Axiom_Mpath_top mt1, Axiom_Mpath { m_top = mt2 ; m_args = [] } ->
mpath_top env mt1 mt2
| Axiom_Lvalue lv1, Axiom_Lvalue lv2 ->
lvalue env lv1 lv2
| Axiom_Xpath x1, Axiom_Xpath x2 ->
xpath env x1 x2
| Axiom_Hoarecmp c1, Axiom_Hoarecmp c2 ->
hoarecmp env c1 c2
| Axiom_Local (id1,ty1), Axiom_Local (id2,ty2) ->
if ty env ty1 ty2 then name id1 id2 else false
| _,_ -> false
in
aux o1 o2
and pattern (env : environment) ri (p1 : pattern) (p2 : pattern) : bool =
let try_translate_eq eq trans p1 p2 =
try eq (trans p1) (trans p2)
with Translate.Invalid_Type _ -> false in
(try_translate_eq (form env ri)
(Translate.form_of_pattern (EcEnv.LDecl.toenv env.env_hyps)) p1 p2)
|| (try_translate_eq (memory env)
(Translate.memory_of_pattern (EcEnv.LDecl.toenv env.env_hyps)) p1 p2)
|| (try_translate_eq (mpath env)
(Translate.mpath_of_pattern (EcEnv.LDecl.toenv env.env_hyps)) p1 p2)
||
match p1.p_node, p2.p_node with
| Pat_Red_Strat (p1,red1), Pat_Red_Strat (p2,red2) ->
if red1 == red2 then pattern env ri p1 p2 else false
| Pat_Or lp1, Pat_Or lp2 ->
List.for_all2 (pattern env ri) lp1 lp2
| Pat_Sub p1, Pat_Sub p2 -> pattern env ri p1 p2
| Pat_Axiom a1, Pat_Axiom a2 ->
axiom env ri a1 a2
| Pat_Fun_Symbol (s1, lp1), Pat_Fun_Symbol (s2, lp2) ->
if symbol env s1 s2 then List.for_all2 (pattern env ri) lp1 lp2
else false
| Pat_Meta_Name (p1,n1,b1), Pat_Meta_Name (p2,n2,b2) ->
if not (name n1 n2) then false
else
let eq = match b1, b2 with
| Some b1, Some b2 -> List.for_all2 (pbinding env) b1 b2
| _ -> true in
if eq then
match p1, p2 with
| Some p1, Some p2 -> pattern env ri p1 p2
| _ -> true
else false
| Pat_Meta_Name (_,n1,_), _ -> begin
match Mid.find_opt n1 (saturate env).env_match.me_matches with
| Some p1' ->
if pattern env ri p1 p1' then false
else pattern env ri p1' p2
| None -> false
end
| _, Pat_Meta_Name (_,n2,_) -> begin
match Mid.find_opt n2 (saturate env).env_match.me_matches with
| Some p2' ->
if pattern env ri p2 p2' then false
else pattern env ri p1 p2'
| None -> false
end
| Pat_Axiom a, Pat_Fun_Symbol (s,lp)
| Pat_Fun_Symbol (s,lp), Pat_Axiom a -> begin
match s, lp, a with
| Sym_Form_Prog_var k1, [p1],
Axiom_Prog_Var { pv_name = xp ; pv_kind = k2 } when k1 = k2 ->
pattern env ri p1 (pat_xpath xp)
| Sym_Xpath, [mp1;p1],
Axiom_Xpath { x_top = mp2; x_sub = p2 } ->
pattern env ri p1 (pat_op p2 [] None)
&& pattern env ri mp1 (pat_mpath mp2)
| Sym_Mpath, [m1], Axiom_Mpath _ ->
pattern env ri m1 p2
| Sym_Mpath, [mtop1], Axiom_Mpath_top _ ->
pattern env ri mtop1 p2
| Sym_Mpath, mtop1::margs1,
Axiom_Mpath { m_top = mtop2; m_args = margs2 } ->
let (margs11,margs12), (margs21,margs22) = suffix2 margs1 margs2 in
let mtop1 = p_mpath mtop1 margs11 in
let mtop2 = if margs21 = [] then pat_mpath_top mtop2
else pat_mpath (EcPath.mpath mtop2 margs21) in
List.for_all2 (pattern env ri) (mtop1::margs12)
(mtop2::(List.map pat_mpath margs22))
| Sym_Mpath, _, _ -> false
| _ -> false
end
| _, _ -> false
end
(* -------------------------------------------------------------------------- *)
let get_ty = function
| OGTty (Some ty) -> ty
| _ -> raise NoMatches
(* --------------------------------------------------------------------- *)
let restr_bds_check (env : environment) (p : pattern) (restr : pbindings) =
let mr = Sid.of_list (List.map fst restr) in
let m = Mid.set_diff (FV.pattern0 p) mr in
let m = Mid.set_diff m (env.env_match.me_meta_vars) in
let check1 (x : ident) =
let aout =
let lookup () =
is_some (EcEnv.Mod.by_mpath_opt
(mpath (`Local x) [])
(LDecl.toenv env.env_hyps)) in
EcIdent.id_equal x mhr ||
LDecl.has_id x env.env_hyps || lookup () in
if not aout then
Debug.debug_bind_restr env x;
aout
in Mid.for_all (fun x _ -> check1 x) m
let e_next (e : eng) : neng =
{ ne_continuation = e.e_continuation;
ne_env = e.e_env;
}
let n_eng (e_pattern1) (e_pattern2 : pattern) (n : neng) =
{ e_pattern1;
e_pattern2;
e_continuation = n.ne_continuation;
e_env = n.ne_env;
}
let sub_engine1 e p f =
e_copy { e with e_pattern2 = f; e_pattern1 = mk_pattern (Pat_Sub p) OGTany; }
let omap_list (default : 'a -> 'b) (f : 'a -> 'b option) (l : 'a list) : 'b list option =
let rec aux acc there_is_Some = function
| [] -> if there_is_Some then Some (List.rev acc) else None
| x::rest when there_is_Some -> aux ((odfl (default x) (f x))::acc) there_is_Some rest
| x::rest -> match f x with
| None -> aux ((default x)::acc) false rest
| Some x -> aux (x::acc) true rest in
aux [] false l
let olist f (l : 'a list) = omap_list (fun x -> x) f l
let ofold_list default (f : 'env -> 'p -> 'a option * 'env) (e : 'env) (lp : 'p list) =
let rec aux e acc there_is_Some = function
| [] -> if there_is_Some then Some (List.rev acc),e else None,e
| x::rest ->
match f e x with
| None,e -> aux e ((default x)::acc) there_is_Some rest
| Some x,e -> aux e (x::acc) true rest
in aux e [] false lp
(* let rec mpath_to_pattern (m : mpath) =
* Pat_Fun_Symbol (Sym_Mpath, (Pat_Axiom (Axiom_Mpath_top m.m_top))
* ::(List.map mpath_to_pattern m.m_args))
*
* let rec pat_of_mpath (m : mpath) =
* let args = List.map pat_of_mpath m.m_args in
* let m = Pat_Axiom (Axiom_Mpath_top m.m_top) in
* Pat_Fun_Symbol (Sym_Mpath, m::args)
*
* let rec pat_of_xpath (x : xpath) =
* Pat_Fun_Symbol (Sym_Xpath, [Pat_Axiom (Axiom_Op (x.x_sub,[])); pat_of_mpath x.x_top]) *)
let rewrite_term e f =
let env = saturate e.e_env in
let subst = psubst_of_menv env.env_match in
let p1 = pat_form f in
let p2 = Psubst.p_subst subst p1 in
Debug.debug_subst env p1 p2;
p2
let rec pattern_contain_meta_var p = match p.p_node with
| Pat_Axiom _ -> false
| Pat_Sub p -> pattern_contain_meta_var p
| Pat_Or lp -> List.exists pattern_contain_meta_var lp
| Pat_Meta_Name _ -> true
| Pat_Red_Strat (p,_) -> pattern_contain_meta_var p
| Pat_Fun_Symbol (_, lp) -> List.exists pattern_contain_meta_var lp
| Pat_Stmt g -> gen_stmt_contain_meta_var g
and gen_stmt_contain_meta_var g = match g with
| Anchor _ | Any -> false
| Base p -> pattern_contain_meta_var p
| Choice l -> List.exists gen_stmt_contain_meta_var l
| Named (_,_) -> true
| Repeat (g,_,_) -> gen_stmt_contain_meta_var g
| Seq l -> List.exists gen_stmt_contain_meta_var l
let all_map2 (f : 'a -> 'b -> 'c -> bool * 'a) (a : 'a) (lb : 'b list)
(lc : 'c list) : bool * 'a =
let rec aux a1 a lb lc =
match lb, lc with
| [], [] -> true, a
| [], _ | _, [] -> raise NoMatches
| b::lb, c::lc ->
match f a b c with
| false, _ -> false, a1
| true, a -> aux a1 a lb lc
in aux a a lb lc
let change_ogty ogty p = mk_pattern p.p_node ogty
let try_reduce (e : eng) : eng =
Debug.debug_try_reduce e.e_env e.e_pattern1 e.e_pattern2;
let copy = e_copy e in
let ne = e_next (e_copy e) in
let e_continuation = Zreduce (e.e_continuation,copy,ne) in
{ e with e_continuation }
let try_conv (e : eng) : eng =
Debug.debug_try_conv e.e_env e.e_pattern1 e.e_pattern2;
let copy = e_copy e in
let ne = e_next (e_copy e) in
let e_continuation = Zconv (e.e_continuation,copy,ne) in
{ e with e_continuation }
let rec check_arrow e b t = match b, t.ty_node with
| [], _ -> true
| (_,OGTty (Some t1)) :: b, Tfun (t2, t) ->
EQ.ty e t1 t2 && check_arrow e b t
| _ -> false
let check_arrow e b o = match o with
| OGTty (Some ty) -> check_arrow e b ty
| _ -> false
let rec parrow (args : pattern list) = function
| None -> None
| Some ty ->
match args with
| [] -> Some ty
| p :: args ->
match p.p_ogty with
| OGTty (Some t1) -> parrow args (Some (tfun t1 ty))
| _ -> None
let parrow args t = parrow (List.rev args) t
let pattern_is_higher_order_decidable pargs =
let eq = (=) in
let different_2by2 l =
let rec aux rest1 rest2 = match rest1, rest2 with
| _, [] -> true
| [], _ :: r2 -> aux rest2 r2
| a1 :: rest1, a2 ::_ ->
not (eq a1 a2) || aux rest1 rest2
in aux l l
in
let rec contain_meta_var p = match p.p_node with
| Pat_Meta_Name (_,_,_) -> true
| _ -> fst (p_fold_map (fun b p -> b || contain_meta_var p, p) false p)
in
not (List.exists contain_meta_var pargs)
&& different_2by2 pargs
let init_match_env ?mtch ?unienv ?metas () =
{ me_matches = odfl Mid.empty mtch;
me_unienv = odfl (EcUnify.UniEnv.create None) unienv;
me_meta_vars = odfl Mid.empty metas;
}
let empty_matches_env () =
{ me_matches = Mid.empty;
me_meta_vars = Mid.empty;
me_unienv = EcUnify.UniEnv.create None; }
let mk_engine ?mtch f pattern hyps rim ris ric =
let gstate = EcEnv.gstate (EcEnv.LDecl.toenv hyps) in
let verbose = EcGState.getflag "debug" gstate in
let env_match = ofdfl empty_matches_env (omap menv_copy mtch) in
let verbose = if verbose then debug_verbose else env_verbose in
let e_env = {
env_hyps = hyps;
env_red_info_match = rim;
env_red_info_same_meta = ris;
env_red_info_conv = ric;
env_meta_restr_binds = Mid.empty;
env_match = env_match;
env_verbose = verbose;
} in
{ e_pattern1 = pattern;
e_pattern2 = f;
e_continuation = ZTop;
e_env = e_env;
}
(* ---------------------------------------------------------------------- *)
type zipath =
| ZipTop
| ZipWhile of pattern * zspath
| ZipIfThen of pattern * zspath * pattern
| ZipIfElse of pattern * pattern * zspath
and zspath = pattern list pair * zipath
type zipper = {
zip_head : pattern list;
zip_tail : pattern list;
zip_path : zipath;
}
type regexp_engine = {
eng_subject : zipper;
eng_envir : environment;
eng_path : int list;
}
module PMatching
(Regexp :
GenRegexp with type subject = pattern list and
type regexp = pattern gen_regexp and
type envir = environment and
type base_engine = regexp_engine and
type matches = pattern list Mid.t)
= struct
type subject = pattern list
type regexp1 = pattern
type engine = regexp_engine
type pos = int
type path = int list
type regexp = pattern gen_regexp
type envir = environment
let zip_top (s : subject) = {
zip_head = [];
zip_tail = s;
zip_path = ZipTop;
}
let mkengine (s : subject) (env : envir) = {
eng_subject = zip_top s;
eng_envir = env_copy env;
eng_path = [];
}
let position (e : engine) = List.length e.eng_subject.zip_head
let path (e : engine) = (position e) :: e.eng_path
let at_end (e : engine) = List.is_empty e.eng_subject.zip_tail
let at_start (e : engine) = List.is_empty e.eng_subject.zip_head
let get_base = function
| Base p -> p
| _ -> raise NoMatches
let is_base = function
| Base _ -> true
| _ -> false
let get_subject p = match p.p_node with
| Pat_Stmt (Base p) -> [p]
| Pat_Stmt (Seq l) when List.for_all is_base l -> List.map get_base l
| Pat_Stmt _ -> raise NoMatches
| _ when p.p_ogty = OGTstmt -> [p]
| _ -> raise NoMatches
let can_get_subject p = match p.p_node with
| Pat_Stmt (Base _) -> true
| Pat_Stmt (Seq l) when List.for_all is_base l -> true
| Pat_Stmt _ -> false
| _ when p.p_ogty = OGTstmt -> true
| _ -> false
let extract (e : engine) ((lo,hi) : pos pair) =
if hi <= lo then [] else
let s = List.rev_append e.eng_subject.zip_head e.eng_subject.zip_tail in
List.of_enum (List.enum s |> Enum.skip lo |> Enum.take (hi-lo))
let zipper s1 s2 path = { zip_head = s1; zip_tail = s2; zip_path = path; }
let rec process (e : eng) : neng =
let eq = EQ.ogty e.e_env e.e_pattern1.p_ogty e.e_pattern2.p_ogty in
Debug.debug_try_match e.e_env e.e_pattern1 e.e_pattern2 e.e_continuation;
Debug.debug_ogty e.e_env e.e_pattern1 e.e_pattern2 eq;
Debug.debug_unienv e.e_env;
if not eq
then next NoMatch e
else
let e = try_conv e in
match e.e_pattern1.p_node, e.e_pattern2.p_node with
| Pat_Meta_Name (None, n1, _), Pat_Meta_Name (None, n2, _) when EQ.name n1 n2 ->
Debug.debug_which_rule e.e_env "same meta variable 1";
next Match e
| Pat_Meta_Name (Some p1, n1, ob), Pat_Meta_Name (None, n2, _) when EQ.name n1 n2 ->
Debug.debug_which_rule e.e_env "same meta variable 2";
next Match { e with e_continuation = Znamed (p1, n1, ob, e.e_continuation) }
| Pat_Meta_Name (None, n2, _), Pat_Meta_Name (Some p1, n1, ob) when EQ.name n1 n2 ->
Debug.debug_which_rule e.e_env "same meta variable 3";
next Match { e with e_continuation = Znamed (p1, n1, ob, e.e_continuation) }
| Pat_Meta_Name (Some p1, n1, _), Pat_Meta_Name (Some p2, n2, ob) when EQ.name n1 n2 ->
Debug.debug_which_rule e.e_env "same meta variable 4";
process { e with e_pattern1 = p1; e_pattern2 = p2;
e_continuation = Znamed (p2, n1, ob, e.e_continuation) }
| Pat_Meta_Name (None, name, ob), _ ->
let env_meta_restr_binds =
odfl e.e_env.env_meta_restr_binds
(omap (fun b -> Mid.add name b e.e_env.env_meta_restr_binds) ob) in
let e_env = { e.e_env with env_meta_restr_binds; } in
let e = { e with e_env } in
Debug.debug_which_rule e.e_env "meta variable : 1 none";
next Match { e with
e_continuation = Znamed (e.e_pattern2, name, ob, e.e_continuation) }
| _ , Pat_Meta_Name (None, name, ob) ->
let env_meta_restr_binds =
odfl e.e_env.env_meta_restr_binds
(omap (fun b -> Mid.add name b e.e_env.env_meta_restr_binds) ob) in
let e_env = { e.e_env with env_meta_restr_binds; } in
let e = { e with e_env } in
Debug.debug_which_rule e.e_env "meta variable : 2 none";
next Match { e with
e_continuation = Znamed (e.e_pattern1, name, ob, e.e_continuation) }
| Pat_Meta_Name (Some p,name,ob), _ ->
let env_meta_restr_binds =
odfl e.e_env.env_meta_restr_binds
(omap (fun b -> Mid.add name b e.e_env.env_meta_restr_binds) ob) in
let e_env = { e.e_env with env_meta_restr_binds; } in
let e = { e with e_env } in
Debug.debug_which_rule e.e_env "meta variable : 1 some";
process { e with
e_pattern1 = p; e_env;
e_continuation = Znamed(e.e_pattern2, name, ob, e.e_continuation);
}
| _, Pat_Meta_Name (Some p,name,ob) ->
let env_meta_restr_binds =
odfl e.e_env.env_meta_restr_binds
(omap (fun b -> Mid.add name b e.e_env.env_meta_restr_binds) ob) in
let e_env = { e.e_env with env_meta_restr_binds; } in
let e = { e with e_env } in
Debug.debug_which_rule e.e_env "meta variable : 2 some";
process { e with
e_pattern2 = p; e_env;
e_continuation = Znamed(e.e_pattern1, name, ob, e.e_continuation);
}
| Pat_Sub p, _ ->
let le = sub_engines1 e p in
Debug.debug_which_rule e.e_env "sub 1";
let e = { e with e_pattern1 = p } in
process (zor e le)
| _, Pat_Sub p ->
let le = sub_engines2 e p in
Debug.debug_which_rule e.e_env "sub 2";
let e = { e with e_pattern2 = p } in
process (zor e le)
| Pat_Or [], _ -> next NoMatch e
| _, Pat_Or [] -> next NoMatch e
| Pat_Or (p::pl), _ ->
Debug.debug_which_rule e.e_env "or 1";
let update_pattern p = { e with e_pattern1 = p; } in
let l = List.map update_pattern pl in
let e = update_pattern p in
process (zor e l)
| _, Pat_Or (p::pl) ->
Debug.debug_which_rule e.e_env "or 2";
let update_pattern p = { e with e_pattern2 = p; } in
let l = List.map update_pattern pl in
let e = update_pattern p in
process (zor e l)
| Pat_Red_Strat (e_pattern1, f),_ ->
Debug.debug_which_rule e.e_env "reduction strategy : 1";
let env_red_info_match, env_red_info_same_meta =
f e.e_env.env_red_info_match e.e_env.env_red_info_same_meta in
let e_env = { e.e_env with env_red_info_match; env_red_info_same_meta } in
process { e with e_pattern1; e_env }
| _, Pat_Red_Strat (e_pattern2, f) ->
Debug.debug_which_rule e.e_env "reduction strategy : 2";
let env_red_info_match, env_red_info_same_meta =
f e.e_env.env_red_info_match e.e_env.env_red_info_same_meta in
let e_env = { e.e_env with env_red_info_match; env_red_info_same_meta } in
process { e with e_pattern2; e_env }
| Pat_Axiom o1, Pat_Axiom o2 ->
Debug.debug_which_rule e.e_env "axiom 1&2";
if EQ.axiom e.e_env e.e_env.env_red_info_match o1 o2
then next Match e
else next NoMatch e
| Pat_Fun_Symbol (Sym_Form_App (t, _),
{ p_node = Pat_Meta_Name(None, name, _)} :: pargs), _
when Mid.mem name e.e_env.env_match.me_matches ->
Debug.debug_which_rule e.e_env "replace in app meta variable 1";
let e_env = saturate e.e_env in
let e_pattern1 = p_app (Mid.find name e_env.env_match.me_matches) pargs t in
process { e with e_env; e_pattern1; }
| _, Pat_Fun_Symbol (Sym_Form_App (t, _),
{ p_node = Pat_Meta_Name(None, name, _)} :: pargs)
when Mid.mem name e.e_env.env_match.me_matches ->
Debug.debug_which_rule e.e_env "replace in app meta variable 2";
let e_env = saturate e.e_env in
let e_pattern2 = p_app (Mid.find name e_env.env_match.me_matches) pargs t in
process { e with e_env; e_pattern2; }
| Pat_Fun_Symbol (Sym_Form_App (_, MaybeHO), pop :: pargs), _ ->
Debug.debug_which_rule e.e_env
"application 1 : test both without and with higher order";
let e_pattern1 = pat_fun_symbol (Sym_Form_App (None, HO)) (pop::pargs) in
let e_or = { e with e_pattern1; } in
let e_pattern1 = pat_fun_symbol (Sym_Form_App (None, NoHO)) (pop::pargs) in
let e = { e with e_pattern1; } in
process (zor e [e_or])
| _ ,Pat_Fun_Symbol (Sym_Form_App (_, MaybeHO), pop :: pargs) ->
Debug.debug_which_rule e.e_env
"application 2 : test both without and with higher order";
let e_pattern2 = pat_fun_symbol (Sym_Form_App (None, HO)) (pop::pargs) in
let e_or = { e with e_pattern2; } in
let e_pattern2 = pat_fun_symbol (Sym_Form_App (None, NoHO)) (pop::pargs) in
let e = { e with e_pattern2; } in
process (zor e [e_or])
| Pat_Fun_Symbol (Sym_Form_App (ot1, NoHO), op1 :: args1),
Pat_Fun_Symbol (Sym_Form_App (ot2, NoHO), op2 :: args2) ->
Debug.debug_which_rule e.e_env
"application 1&2 : without higher order";
let e = try_reduce e in
let (args11,args12),(args21,args22) = suffix2 args1 args2 in
if args12 = [] && args22 = [] then assert false;
let zand = List.combine args12 args22 in
let op1 = p_app op1 args11 (parrow args12 ot1) in
let op2 = p_app op2 args21 (parrow args22 ot2) in
let e_pattern1, e_pattern2, zand = op1, op2, zand in
let e_continuation =
Zand ([e_pattern1,e_pattern2],zand,e.e_continuation) in
process { e with e_pattern1; e_pattern2; e_continuation; }
(* FIXME *)
| Pat_Fun_Symbol (Sym_Form_App (_, HO),
{ p_node = Pat_Meta_Name(None, name, ob)}
::pargs), _ ->
begin
try
Debug.debug_which_rule e.e_env "form : application : with higher order";
let e = try_reduce e in
(* higher order *)
let env = saturate e.e_env in
let s = psubst_of_menv env.env_match in
let p_subst s p =
let p2 = Psubst.p_subst s p in
Debug.debug_subst env p p2;
p2 in
let pargs = List.map (p_subst s) pargs in
(* if not(pattern_is_higher_order_decidable pargs)
* then raise NoMatches
* else *)
let pargs, env =
(* let meta_pargs = List.filter pattern_contain_meta_var pargs in *)
let find_sub env p =
try
let ne = process
{ e_env = env_copy env;
e_pattern1 = mk_pattern (Pat_Sub p) OGTany;
e_pattern2 = e.e_pattern2;
e_continuation = ZTop; } in
ne.ne_env
with NoMatches -> env
in
let env = List.fold_left find_sub env pargs in
let s = psubst_of_menv env.env_match in
let env_match = { e.e_env.env_match with
me_matches = e.e_env.env_match.me_matches } in
List.map (Psubst.p_subst s) pargs, { env with env_match } in
if not(pattern_is_higher_order_decidable pargs)
then raise NoMatches
else
let add_ident i x =
EcIdent.create (String.concat "" ["t";string_of_int i]), x in
let args = List.mapi add_ident pargs in
(* let args = List.map (fun (i,p) -> i, pat_meta p i ob) args in *)
let env_meta_restr_binds =
odfl env.env_meta_restr_binds
(omap (fun b -> Mid.add name b env.env_meta_restr_binds) ob) in
let e = { e with e_env = { env with env_meta_restr_binds } } in
let abstract (e, p) arg =
Debug.debug_higher_order_to_abstract e.e_env (snd arg) p;
let env, p = abstract_opt e p ob arg in
{ e with e_env = env }, p
in
let e', pat =
(* FIXME : add strategies to adapt the order of the arguments *)
List.fold_left abstract (e, e.e_pattern2) args in
EcUnify.UniEnv.restore ~src:e'.e_env.env_match.me_unienv
~dst:e.e_env.env_match.me_unienv;
let f (name,p) = (name,p.p_ogty) in
let args = List.map f args in
let pat = p_quant Llambda args pat in
let s = psubst_of_menv { e.e_env.env_match with me_matches = Mid.empty } in
let pat = p_subst s pat in
let m,e =
try
let e = add_match e name pat ob in
let me_matches =
List.fold_left (fun m (id,_) -> Mid.remove id m)
e.e_env.env_match.me_matches args in
let env_match = { e.e_env.env_match with me_matches } in
let e_env = { e.e_env with env_match } in
let e = { e with e_env } in
Match, e
with CannotUnify -> raise NoMatches
in next m e
with
| NoMatches -> next NoMatch e
end
| Pat_Fun_Symbol (Sym_Quant (q1,bs1), [p1]),
Pat_Fun_Symbol (Sym_Quant (q2,bs2), [p2]) when q1 = q2 ->
begin
Debug.debug_which_rule e.e_env "quantif 1&2";
let e = try_reduce e in
let (b11,b12), (b21,b22) = List.prefix2 bs1 bs2 in
if not (List.for_all2
(EQ.ogty e.e_env) (List.map snd b21) (List.map snd b11))
then next NoMatch e
else
let f s (id1,_) (id2,gty1) = Psubst.p_bind_ogty s id1 id2 gty1 in
let e_env = saturate e.e_env in
let subst = psubst_of_menv { e.e_env.env_match with me_matches = Mid.empty }in
let s = List.fold_left2 f subst b11 b21 in
let e_pattern1 = Psubst.p_subst s p1 in
let e_pattern1 = p_quant q1 b12 e_pattern1 in
Debug.debug_subst e_env p1 e_pattern1;
let e_pattern2 = p_quant q2 b22 (Psubst.p_subst subst p2) in
process { e with e_pattern1; e_pattern2; e_env; }
end
| Pat_Fun_Symbol (Sym_Mpath, p1 :: args1),
Pat_Fun_Symbol (Sym_Mpath, p2 :: args2) ->
begin Debug.debug_which_rule e.e_env "mpath 1&2";
let e = try_reduce e in
let (args11,args12),(args21,args22) = suffix2 args1 args2 in
let zand = List.combine args12 args22 in
let e_continuation = match zand with
| [] -> e.e_continuation
| _ -> Zand ([],zand,e.e_continuation) in
let e_pattern1 = p_mpath p1 args11 in
let e_pattern2 = p_mpath p2 args21 in
process { e with e_pattern1; e_pattern2; e_continuation; }
end
| Pat_Fun_Symbol (s1, lp1), Pat_Fun_Symbol (s2, lp2)
when EQ.symbol e.e_env s1 s2 && 0 = List.compare_lengths lp1 lp2 ->
Debug.debug_which_rule e.e_env "same fun symbol";
let e_continuation = Zand ([], List.combine lp1 lp2, e.e_continuation) in
next Match { e with e_continuation }
| Pat_Fun_Symbol (Sym_Instr_Call, [{p_node = Pat_Meta_Name (None,id,None)};
f1;args1]),
Pat_Fun_Symbol (Sym_Instr_Call, [f2;args2])
when EcIdent.name id = "$anything"
(* $anything : same name as in ecTransMatching in function pat_anything *)->
let e_continuation = Zand ([], List.combine [f1;args1] [f2;args2],
e.e_continuation) in
next Match { e with e_continuation }
| Pat_Fun_Symbol (Sym_Instr_Call, [f1;args1]),
Pat_Fun_Symbol (Sym_Instr_Call, [{p_node = Pat_Meta_Name (None,id,None)};
f2;args2])
when EcIdent.name id = "$anything"
(* $anything : same name as in ecTransMatching in function pat_anything *)->
let e_continuation = Zand ([], List.combine [f1;args1] [f2;args2],
e.e_continuation) in
next Match { e with e_continuation }
(* Pattern / Axiom *)
| Pat_Fun_Symbol (Sym_Mpath, p::rest), Pat_Axiom (Axiom_Mpath m) ->
begin Debug.debug_which_rule e.e_env "mpath : pat ax";
let e = try_reduce e in
let (pargs1,pargs2),(margs1,margs2) = suffix2 rest m.m_args in
let zand = List.map2 (fun x y -> (pat_mpath x),y) margs2 pargs2 in
let e_continuation = match zand with
| [] -> e.e_continuation
| _ -> Zand ([],zand,e.e_continuation) in
let m = match margs1 with
| [] -> pat_mpath_top m.m_top
| _ -> if margs2 = [] then pat_mpath m
else pat_mpath (mpath m.m_top margs1)
in
let p = match pargs1 with
| [] -> p
| _ -> p_mpath p pargs1
in
process { e with e_pattern1 = p; e_pattern2 = m; e_continuation; }
end
| Pat_Axiom (Axiom_Mpath m), Pat_Fun_Symbol (Sym_Mpath, p::rest) ->
begin Debug.debug_which_rule e.e_env "mpath : ax pat";
let e = try_reduce e in
let (pargs1,pargs2),(margs1,margs2) = suffix2 rest m.m_args in
let zand = List.map2 (fun x y -> (pat_mpath x),y) margs2 pargs2 in
let e_continuation = match zand with
| [] -> e.e_continuation
| _ -> Zand ([],zand,e.e_continuation) in
let m = match margs1 with
| [] -> pat_mpath_top m.m_top
| _ -> if margs2 = [] then pat_mpath m
else pat_mpath (mpath m.m_top margs1)
in
let p = match pargs1 with
| [] -> p
| _ -> p_mpath p pargs1
in
process { e with e_pattern2 = p; e_pattern1 = m; e_continuation; }
end
| Pat_Fun_Symbol (Sym_Mpath, [p]),
Pat_Axiom (Axiom_Mpath_top _) ->
begin Debug.debug_which_rule e.e_env "mpath_top : 1";
let e = try_reduce e in
process { e with e_pattern1 = p }
end
| Pat_Axiom (Axiom_Mpath_top _),
Pat_Fun_Symbol (Sym_Mpath, [p]) ->
begin Debug.debug_which_rule e.e_env "mpath_top : 2";
let e = try_reduce e in
process { e with e_pattern2 = p }
end
| Pat_Fun_Symbol (Sym_Form_Prog_var k, [p]),
Pat_Axiom (Axiom_Prog_Var x2)
when k = x2.pv_kind -> begin
Debug.debug_which_rule e.e_env "form : prog_var 1";
process { e with e_pattern1 = p; e_pattern2 = pat_xpath x2.pv_name; }
end
| Pat_Axiom (Axiom_Prog_Var x2),
Pat_Fun_Symbol (Sym_Form_Prog_var k, [p])
when k = x2.pv_kind -> begin
Debug.debug_which_rule e.e_env "form : prog_var 2";
process { e with e_pattern2 = p; e_pattern1 = pat_xpath x2.pv_name; }
end
| Pat_Fun_Symbol (Sym_Xpath, [pm;pf]),
Pat_Axiom (Axiom_Xpath x) ->
begin Debug.debug_which_rule e.e_env "xpath 1";
let zand = [pat_mpath x.x_top,pm] in
process { e with
e_pattern1 = pf;
e_pattern2 = pat_op x.x_sub [] None;
e_continuation = Zand ([],zand,e.e_continuation); }
end
| Pat_Axiom (Axiom_Xpath x),
Pat_Fun_Symbol (Sym_Xpath, [pm;pf]) ->
begin Debug.debug_which_rule e.e_env "xpath 2";
let zand = [pat_mpath x.x_top,pm] in
process { e with
e_pattern2 = pf;
e_pattern1 = pat_op x.x_sub [] None;
e_continuation = Zand ([],zand,e.e_continuation); }
end
| Pat_Fun_Symbol
(Sym_Form_App _,
{ p_node = Pat_Fun_Symbol (Sym_Quant (Llambda,_),[_])}::_), _
when e.e_env.env_red_info_match.EcReduction.beta -> begin
match p_betared_opt e.e_pattern1 with
| Some e_pattern1 ->
process { e with e_pattern1 }
| None -> next NoMatch e
end
| _, Pat_Fun_Symbol
(Sym_Form_App _,
{ p_node = Pat_Fun_Symbol (Sym_Quant (Llambda,_),[_])}::_)
when e.e_env.env_red_info_match.EcReduction.beta -> begin
match p_betared_opt e.e_pattern2 with
| Some e_pattern2 ->
process { e with e_pattern2 }
| None -> next NoMatch e
end
| _, Pat_Stmt regexp when can_get_subject e.e_pattern1 -> begin
match Regexp.search regexp (get_subject e.e_pattern1) (env_copy e.e_env) with
| None -> raise NoMatches
| Some (base_engine, matches) ->
let envir = merge_matches base_engine matches in
let ne = { ne_continuation = e.e_continuation;
ne_env = envir;
} in
next_n Match ne
end
| Pat_Stmt regexp, _ when can_get_subject e.e_pattern2 -> begin
match Regexp.search regexp (get_subject e.e_pattern2) (env_copy e.e_env) with
| None -> raise NoMatches
| Some (base_engine, matches) ->
let envir = merge_matches base_engine matches in
let ne = { ne_continuation = e.e_continuation;
ne_env = envir;
} in
next_n Match ne
end
| Pat_Stmt (Base p), Pat_Stmt regexp -> begin
match Regexp.search regexp [p] (env_copy e.e_env) with
| None -> raise NoMatches
| Some (base_engine, matches) ->
let envir = merge_matches base_engine matches in
let ne = { ne_continuation = e.e_continuation;
ne_env = envir;
} in
next_n Match ne
end
| _ -> begin
Debug.debug_which_rule e.e_env "default";
let e = try_reduce e in
next NoMatch e
end
and next (m : ismatch) (e : eng) : neng =
Debug.debug_result_match e.e_env m;
next_n m (e_next e)
and next_n (m : ismatch) (e : neng) : neng =
match m,e.ne_continuation with
| NoMatch, ZTop -> raise NoMatches
| NoMatch, Zreduce (_, e',ne) -> begin
Debug.debug_show_matches e.ne_env;
Debug.debug_which_rule e.ne_env "next : no match, then try to reduce";
Debug.debug_show_matches e'.e_env;
match h_red_strat e'.e_env e'.e_pattern1 e'.e_pattern2 with
| None -> Debug.debug_reduce e'.e_env e'.e_pattern1 e'.e_pattern1
e'.e_pattern2 e'.e_pattern2 false;
next_n NoMatch ne
| Some (e_pattern1, e_pattern2) ->
Debug.debug_reduce e'.e_env e'.e_pattern1 e_pattern1
e'.e_pattern2 e_pattern2 true;
let e = { e' with e_pattern1; e_pattern2 } in
process e
end
| NoMatch, Zconv (_, e',ne) -> begin
Debug.debug_show_matches e.ne_env;
Debug.debug_which_rule e.ne_env "next : no match, then try to convert";
Debug.debug_show_matches e'.e_env;
let env = saturate e'.e_env in
let s = psubst_of_menv env.env_match in
let r = env.env_red_info_conv in
let p1 = Psubst.p_subst s e'.e_pattern1 in
let p2 = Psubst.p_subst s e'.e_pattern2 in
try
let f1 = Translate.form_of_pattern (EcEnv.LDecl.toenv env.env_hyps) p1 in
let f2 = Translate.form_of_pattern (EcEnv.LDecl.toenv env.env_hyps) p2 in
if EcReduction.is_conv_param r env.env_hyps f1 f2 then
next Match e'
else next_n NoMatch ne
with Translate.Invalid_Type _ ->
next_n NoMatch ne
end
| NoMatch, Znamed (_f, _name, _ob, ne_continuation) ->
Debug.debug_which_rule e.ne_env "next : no match in named";
next_n NoMatch { e with ne_continuation; }
| NoMatch, Zand (_,_,ne_continuation) ->
Debug.debug_which_rule e.ne_env "next : no match in zand";
next_n NoMatch { e with ne_continuation; }
| NoMatch, Zor (_, [], ne) ->
Debug.debug_which_rule e.ne_env "next : no match in zor, no more matches";
next_n NoMatch ne
| NoMatch, Zor (_, e'::engs, ne) ->
Debug.debug_another_or e.ne_env;
EcUnify.UniEnv.restore
~src:ne.ne_env.env_match.me_unienv
~dst: e.ne_env.env_match.me_unienv;
process { e' with e_continuation = Zor (e'.e_continuation, engs, ne); }
| Match, ZTop ->
Debug.debug_found_match e.ne_env;
let ne_env = saturate e.ne_env in
{ e with ne_env }
| Match, Zreduce (ne_continuation, _, _) ->
Debug.debug_which_rule e.ne_env "next : skip reduce";
next_n Match { e with ne_continuation }
| Match, Zconv (ne_continuation, _, _) ->
Debug.debug_which_rule e.ne_env "next : skip conv";
next_n Match { e with ne_continuation }
| Match, Znamed (f, name, ob, ne_continuation) ->
let m,e =
try
let ne = nadd_match e name f ob in
Match, { ne with ne_continuation; }
with
| CannotUnify ->
Debug.debug_which_rule e.ne_env "next : cannot unify in named";
NoMatch, { e with ne_continuation; } in
next_n m e
| Match, Zand (_,[],ne_continuation) ->
Debug.debug_which_rule e.ne_env "next : all match in zand";
next_n Match { e with ne_continuation; }
| Match, Zand (before,(f,p)::after,z) ->
Debug.debug_which_rule e.ne_env "next : next match in zand";
let ne_env = saturate e.ne_env in
let e = { e with ne_env } in
(* let s = psubst_of_menv e.ne_env.env_match in
* let f, p = Psubst.p_subst s f, Psubst.p_subst s p in *)
process (n_eng f p
{ e with ne_continuation = Zand ((f,p)::before,after,z);})
| Match, Zor (ne_continuation, _, _) ->
Debug.debug_which_rule e.ne_env "next : match in zor";
Debug.debug_ignore_ors e.ne_env;
next_n Match { e with ne_continuation }
and sub_engines2 e p =
let f e = { e with e_pattern1 = e.e_pattern2; e_pattern2 = e.e_pattern1; } in
let e = f e in
let l = sub_engines1 e p in
List.map f l
and sub_engines1 (e : eng) (p : pattern) : eng list =
match e.e_pattern2.p_node, p.p_node with
| Pat_Meta_Name (_, _, _) , _ -> []
| Pat_Sub _ , _ -> []
| Pat_Or _ , _ -> []
| Pat_Red_Strat (_,_) , _ -> []
| Pat_Axiom (Axiom_Local (id1, { ty_node = Ttuple lt })),
Pat_Fun_Symbol (Sym_Form_Proj _, [{ p_node = Pat_Axiom (Axiom_Local (id2, _))}])
when EQ.name id1 id2 ->
List.mapi (fun i t -> sub_engine1 e p (p_proj e.e_pattern2 i t)) lt
| Pat_Fun_Symbol (Sym_Form_Proj _, [{ p_node = Pat_Axiom (Axiom_Local (id1, _))}]),
Pat_Fun_Symbol (Sym_Form_Proj _, [{ p_node = Pat_Axiom (Axiom_Local (id2, _))}])
when EQ.name id1 id2 -> []
| Pat_Axiom _ , _ -> []
| Pat_Fun_Symbol (_, lp) , _ -> List.map (sub_engine1 e p) lp
| Pat_Stmt g , _ -> sub_engines_gen e g
and sub_engines_gen e g = match g with
| Anchor _ | Any -> []
| Base p -> sub_engines1 e p
| Choice l -> List.flatten (List.map (sub_engines_gen e) l)
| Named (g, _) -> sub_engines_gen e g
| Repeat (g, _, _) -> sub_engines_gen e g
| Seq l -> List.flatten (List.map (sub_engines_gen e) l)
(* add_match can raise the exception : CannotUnify *)
and nadd_match (e : neng) (name : meta_name) (p : pattern)
(orb : pbindings option) : neng =
let env = e.ne_env in
let env = saturate env in
let subst = psubst_of_menv env.env_match in
let p' = Psubst.p_subst subst p in
Debug.debug_subst env p p';
let p = p' in
let p_fv = FV.pattern0 p in
Debug.debug_subst env p p';
if Mid.mem name p_fv then
raise CannotUnify
else if odfl true (omap (fun r -> restr_bds_check env p r) orb)
then
let me_matches =
match Mid.find_opt name e.ne_env.env_match.me_matches with
| None ->
Debug.debug_which_rule e.ne_env "nadd_match for the first time";
Debug.debug_add_match e.ne_env true name p;
Mid.add name p e.ne_env.env_match.me_matches
| Some p' ->
(* raise CannotUnify *)
Debug.debug_which_rule e.ne_env "start new unification";
let eng_try_unification =
let env = env_copy e.ne_env in
let env = { env with env_red_info_match = env.env_red_info_same_meta } in
n_eng p p' { e with ne_env = env; ne_continuation = ZTop } in
try
let ne_unification = process eng_try_unification in
ne_unification.ne_env.env_match.me_matches
with
| NoMatches ->
Debug.debug_add_match e.ne_env false name p;
raise CannotUnify
in
{ e with ne_env = { env with env_match = { env.env_match with me_matches; }; }; }
else raise CannotUnify
and add_match (e : eng) n p b =
n_eng e.e_pattern1 e.e_pattern2 (nadd_match (e_next e) n p b)
and merge_matches (engine : regexp_engine) (m : subject Mid.t) : environment =
let env = engine.eng_envir in
let ne = { ne_env = env; ne_continuation = ZTop; } in
let f id p ne = nadd_match ne id (p_stmt p) None in
let ne = Mid.fold f m ne in
ne.ne_env
and abstract_opt (e : eng) (p : pattern) (ob : pbindings option)
((arg,parg) : Name.t * pattern) : environment * pattern =
match parg.p_node with
| Pat_Axiom (Axiom_Local (id,ty)) ->
let s = psubst_of_menv { e.e_env.env_match with me_matches = Mid.empty } in
let s = p_bind_rename s id arg (ty_subst s.ps_sty ty) in
let p2 = Psubst.p_subst s p in
Debug.debug_subst e.e_env p p2;
e.e_env, p2
| Pat_Fun_Symbol (Sym_Form_Proj (i, { ty_node = Ttuple lt }), [parg']) ->
let name = EcIdent.create "" in
let env, p = abstract_opt e p ob (name,parg') in
let replace_name =
p_tuple (List.mapi (fun j t -> if i = j
then meta_var arg ob (OGTty (Some t))
else p_proj parg j t) lt) in
let s = Psubst.p_bind_local Psubst.p_subst_id name replace_name in
let p = Psubst.p_subst s p in
env, p
| _ ->
let rec f env p = try
let eng_unif = e_copy { e_env = env; e_continuation = ZTop;
e_pattern1 = parg; e_pattern2 = p; } in
let ne = process eng_unif in
let env = ne.ne_env in
let s = psubst_of_menv
(saturate { env with
env_match = { env.env_match with
me_matches = Mid.empty }}).env_match in
let p = meta_var arg ob p.p_ogty in
let p = Psubst.p_subst s p in
let p = match p.p_ogty with
| OGTty (Some ty) -> pat_local arg ty
| _ -> p in
env, p
with NoMatches -> p_fold_map f env p
in
f e.e_env p
and h_red_strat env p1 p2 =
let env = saturate env in
let s = psubst_of_menv env.env_match in
let h = env.env_hyps in
let r = env.env_red_info_match in
let eq h r p1 p2 =
let eng = mk_engine ~mtch:env.env_match p1 p2 h r
env.env_red_info_same_meta env.env_red_info_conv in
let env = eng.e_env in
EQ.pattern env r p1 p2 in
match EcPReduction.h_red_pattern_opt ~verbose:env.env_verbose.verbose_reduce
eq h r s p1 with
| Some p1 ->
Debug.debug_h_red_strat env p1 p2 1;
Some (p1, p2)
| None ->
Debug.debug_h_red_strat_next env;
match EcPReduction.h_red_pattern_opt ~verbose:env.env_verbose.verbose_reduce
eq h r s p2 with
| Some p2 ->
Debug.debug_h_red_strat env p1 p2 2;
Some (p1, p2)
| None ->
match p1.p_node, p2.p_node with
(* eta-expansion in the case where the types of e_pattern2 is some tarrow *)
| Pat_Fun_Symbol (Sym_Quant (Llambda, (id, OGTty (Some ty) as b1)::bs), [_]), _
when check_arrow env [b1] p2.p_ogty ->
Debug.debug_which_rule env "eta-expansion 1";
let x = pat_local (EcIdent.create (EcIdent.tostring id)) ty in
let codom = toarrow (List.map (get_ty |- snd) bs) (get_ty p1.p_ogty) in
let p1 = p_app_simpl p1 [x] (Some codom) in
let p2 = p_app_simpl p2 [x] (Some codom) in
Some (p1,p2)
(* eta-expansion in the case where the types of e_pattern1 is some tarrow *)
| _, Pat_Fun_Symbol (Sym_Quant (Llambda, (id, OGTty (Some ty) as b2)::bs), [_])
when check_arrow env [b2] p1.p_ogty ->
Debug.debug_which_rule env "eta-expansion 1";
let x = pat_local (EcIdent.create (EcIdent.tostring id)) ty in
let codom = toarrow (List.map (get_ty |- snd) bs) (get_ty p2.p_ogty) in
let p1 = p_app_simpl p1 [x] (Some codom) in
let p2 = p_app_simpl p2 [x] (Some codom) in
Some (p1,p2)
| _ ->
Debug.debug_h_red_strat env p1 p2 3;
None
and search_eng e =
let s = psubst_of_menv e.e_env.env_match in
let e_pattern1 = Psubst.p_subst s e.e_pattern1 in
let e_pattern2 = Psubst.p_subst s e.e_pattern2 in
let e = { e with e_pattern1; e_pattern2; } in
Debug.debug_begin_match e.e_env e.e_pattern1 e.e_pattern2;
Debug.debug_show_matches e.e_env;
Debug.debug_reduce e.e_env e.e_pattern1 e.e_pattern1 e.e_pattern2
e.e_pattern2 false;
try
let unienv = e.e_env.env_match.me_unienv in
let e' = process (e_copy e) in
EcUnify.UniEnv.restore ~src:e'.ne_env.env_match.me_unienv ~dst:unienv;
Debug.debug_unienv e'.ne_env;
Debug.debug_show_matches e'.ne_env;
Debug.debug_unienv {e'.ne_env with env_match = { e'.ne_env.env_match with me_unienv = unienv } };
Some e'
with
| NoMatches ->
None
let rec next_zipper (z : zipper) =
match z.zip_tail with
| i :: tail ->
begin match i.p_node with
| Pat_Fun_Symbol (Sym_Instr_If, [e; stmttrue; stmtfalse]) ->
let z = (i::z.zip_head, tail), z.zip_path in
let path = ZipIfThen (e, z, stmtfalse) in
let z' = zipper [] (get_subject stmttrue) path in
Some z'
| Pat_Fun_Symbol (Sym_Instr_While, [e; block]) ->
let z = (i::z.zip_head, tail), z.zip_path in
let path = ZipWhile (e, z) in
let z' = zipper [] (get_subject block) path in
Some z'
| Pat_Fun_Symbol (Sym_Instr_Assign, _)
| Pat_Fun_Symbol (Sym_Instr_Assert, _)
| Pat_Fun_Symbol (Sym_Instr_Sample, _)
| Pat_Fun_Symbol (Sym_Instr_Call, _) ->
Some { z with zip_head = i :: z.zip_head ; zip_tail = tail }
| _ -> None
end
| [] ->
match z.zip_path with
| ZipTop -> None
| ZipWhile (_e, ((head, tail), path)) ->
let z' = zipper head tail path in
next_zipper z'
| ZipIfThen (e, father, stmtfalse) ->
let stmttrue = p_stmt (List.rev z.zip_head) in
let z' = zipper [] (get_subject stmtfalse)
(ZipIfElse (e, stmttrue, father)) in
next_zipper z'
| ZipIfElse (_e, _stmttrue, ((head, tail), path)) ->
let z' = zipper head tail path in
next_zipper z'
let next (e : engine) =
next_zipper e.eng_subject |> omap (fun z -> { e with eng_subject = z })
let eat_subject s = match s.zip_tail with
| [] -> raise NoMatch
| p :: tail -> zipper (p :: s.zip_head) tail s.zip_path
let eat (e : engine) =
{ e with eng_subject = eat_subject e.eng_subject; }
let eat_base (e : engine) (r : regexp1) =
match e.eng_subject.zip_tail with
| [] -> raise NoMatch
| i :: _tail ->
let e' = { e_pattern1 = i;
e_pattern2 = r;
e_env = env_copy e.eng_envir;
e_continuation = ZTop } in
match search_eng e' with
| None -> raise NoMatch
| Some ne -> (eat { e with eng_envir = ne.ne_env }, [])
end
let no_delta p = match p.p_node with
| Pat_Fun_Symbol (Sym_Form_App (t1,ho),
{ p_node = Pat_Axiom (Axiom_Op (_,p,lt,t))} :: lp) ->
p_app ~ho (pat_op ~delta:false p lt t) lp t1
| _ -> p
module
rec PMatch : sig include IRegexpBase
val search_eng : eng -> neng option
end
= PMatching(PRegexp)
and PRegexp : GenRegexp with type subject = pattern list and
type regexp = pattern gen_regexp and
type base_engine = regexp_engine and
type envir = environment and
type matches = pattern list Mid.t
= Regexp(PMatch)
let search_eng = PMatch.search_eng
let search_eng_head_no_delta e =
search_eng { e with e_pattern1 = no_delta e.e_pattern1 }
let get_matches (e : eng) : match_env = (saturate e.e_env).env_match
let get_n_matches (e : neng) : match_env = (saturate e.ne_env).env_match
let abstract_pattern (sbd: ogty Mid.t) (p : pattern) =
let s = Mid.fold (fun name gty s ->
Psubst.p_bind_local s name (meta_var name None gty)) sbd
Psubst.p_subst_id in
Psubst.p_subst s p
let rec prefix_binds bs1 bs2 =
let rec aux acc bs1 bs2 = match bs1,bs2 with
| (x,ty1)::r1, (y,ty2)::r2 when EQ.name x y && gty_equal ty1 ty2 ->
aux ((x,ty1)::acc) r1 r2
| _ -> List.rev acc
in aux [] bs1 bs2
let rec prefix_pbinds bs1 bs2 =
let rec aux acc bs1 bs2 = match bs1,bs2 with
| (x,OGTty (Some ty1))::r1, (y,OGTty (Some ty2))::r2
when EQ.name x y && gty_equal (GTty ty1) (GTty ty2) ->
aux ((x,OGTty (Some ty1))::acc) r1 r2
| (x,OGTty t1)::r1, (y,OGTty t2)::r2 when EQ.name x y ->
let t = match t1 with
| Some _ -> t1
| None ->
match t2 with
| Some _ -> t2
| None -> None in
aux ((x,OGTty t)::acc) r1 r2
| (x,OGTmem (Some ty1))::r1, (y,OGTmem (Some ty2))::r2
when EQ.name x y && gty_equal (GTmem ty1) (GTmem ty2) ->
aux ((x,OGTmem (Some ty1))::acc) r1 r2
| (x,OGTmem t1)::r1, (y,OGTmem t2)::r2 when EQ.name x y ->
let t = match t1 with
| Some _ -> t1
| None ->
match t2 with
| Some _ -> t2
| None -> None in
aux ((x,OGTmem t)::acc) r1 r2
| (x,OGTmodty (Some (t1,mr1)))::r1, (y,OGTmodty (Some (t2,mr2)))::r2
when EQ.name x y && gty_equal (GTmodty (t1,mr1)) (GTmodty (t2,mr2)) ->
aux ((x,OGTmodty (Some (t1,mr1)))::acc) r1 r2
| (x,OGTmodty t1)::r1, (y,OGTmodty t2)::r2 when EQ.name x y ->
let t = match t1 with
| Some _ -> t1
| None ->
match t2 with
| Some _ -> t2
| None -> None in
aux ((x,OGTmodty t)::acc) r1 r2
| _ -> List.rev acc
in aux [] bs1 bs2
let add_meta_bindings (name : meta_name) (b : pbindings)
(mbs : pbindings Mid.t) =
match Mid.find_opt name mbs with
| None -> Mid.add name b mbs
| Some b' -> Mid.add name (prefix_pbinds b' b) mbs
let get_meta_bindings (p : pattern) : pbindings Mid.t =
let rec aux current_bds meta_bds p = match p.p_node with
| Pat_Meta_Name (None, n, _) -> add_meta_bindings n current_bds meta_bds
| Pat_Meta_Name (Some p, n, _) ->
aux current_bds (add_meta_bindings n current_bds meta_bds) p
| Pat_Sub p -> aux current_bds meta_bds p
| Pat_Or lp -> List.fold_left (aux current_bds) meta_bds lp
| Pat_Red_Strat (p,_) -> aux current_bds meta_bds p
| Pat_Axiom _ -> meta_bds
| Pat_Fun_Symbol (Sym_Quant (_,b),[p]) ->
aux (current_bds @ b) meta_bds p
| Pat_Fun_Symbol (Sym_Form_Let lp, [p1;p2]) ->
let m = aux current_bds meta_bds p1 in
let current_bds = match lp with
| LSymbol (id,ty) -> (id, OGTty (Some ty)) :: current_bds
| LTuple l -> (List.map (snd_map (fun t -> OGTty (Some t))) l) @ current_bds
| _ -> current_bds in
aux current_bds m p2
(* | Pat_Fun_Symbol (Sym_Form_Pr, [p1;p2;p3;p4]) ->
* let m = aux ((mhr,OGTmem None)::current_bds) meta_bds p4 in
* List.fold_left (aux current_bds) m [p1;p2;p3]
* | Pat_Fun_Symbol (Sym_Form_Hoare_F, [p1;p2;p3]) ->
* let m = List.fold_left (aux ((mhr,OGTmem None)::current_bds)) meta_bds [p1;p3] in
* aux current_bds m p2
* | Pat_Fun_Symbol (Sym_Form_bd_Hoare_F, [p1;p2;p3;p4;p5]) ->
* let m = List.fold_left (aux ((mhr,OGTmem None)::current_bds)) meta_bds [p1;p3;p5] in
* List.fold_left (aux current_bds) m [p2;p4]
* | Pat_Fun_Symbol (Sym_Form_Equiv_F, [p1;p2;p3;p4]) ->
* let m = List.fold_left
* (aux ((mleft,OGTmem None)::(mright,OGTmem None)::current_bds))
* meta_bds [p1;p4] in
* List.fold_left (aux current_bds) m [p2;p3] *)
| Pat_Fun_Symbol (_,lp) -> List.fold_left (aux current_bds) meta_bds lp
| Pat_Stmt g -> aux_gen current_bds meta_bds g
and aux_gen cb mb g = match g with
| Anchor _ | Any -> mb
| Base p -> aux cb mb p
| Choice l -> List.fold_left (aux_gen cb) mb l
| Named (g, n) -> aux_gen cb (add_meta_bindings n cb mb) g
| Repeat (g, _, _) -> aux_gen cb mb g
| Seq l -> List.fold_left (aux_gen cb) mb l
in aux [] Mid.empty p
let rec write_meta_bindings (m : pbindings Mid.t) (p : pattern) =
let aux = write_meta_bindings m in
match p.p_node with
| Pat_Meta_Name (None, n, _) -> meta_var n (Mid.find_opt n m) p.p_ogty
| Pat_Meta_Name (Some p,n,_) -> pat_meta (aux p) n (Mid.find_opt n m)
| Pat_Sub p -> mk_pattern (Pat_Sub (aux p)) OGTany
| Pat_Or lp -> mk_pattern (Pat_Or (List.map aux lp)) OGTany
| Pat_Red_Strat (p,f) -> let p = aux p in
mk_pattern (Pat_Red_Strat (p,f)) p.p_ogty
| Pat_Axiom _ -> p
| Pat_Fun_Symbol
(Sym_Form_App (ty,_),
({ p_node = Pat_Meta_Name (None, _, _) } :: _ as args)) ->
pat_fun_symbol (Sym_Form_App (ty,MaybeHO)) args
| Pat_Fun_Symbol (s,lp) -> pat_fun_symbol s (List.map aux lp)
| Pat_Stmt g -> p_gen_stmt (write_mb_gen m g)
and write_mb_gen m g = match g with
| Anchor _ | Any -> g
| Base p -> Base (write_meta_bindings m p)
| Choice l -> Choice (List.map (write_mb_gen m) l)
| Named (g, n) -> Named (write_mb_gen m g, n)
| Repeat (g, o, a) -> Repeat (write_mb_gen m g, o, a)
| Seq l -> Seq (List.map (write_mb_gen m) l)
let abstract_pattern b a =
let p = abstract_pattern b a in
let m = get_meta_bindings p in
write_meta_bindings m p
let pattern_of_form me f = abstract_pattern me.me_meta_vars (pat_form f)
let pattern_of_memory me m =
abstract_pattern me.me_meta_vars (pat_memory m)
(* -------------------------------------------------------------------- *)
let menv_is_full (e : match_env) =
let matches = e.me_matches in
let meta_vars = e.me_meta_vars in
let f n _ = match Mid.find_opt n matches with
| None -> false
| Some p -> let fv = FV.pattern0 p in
Mid.for_all (fun n _ -> not (Mid.mem n meta_vars)) fv in
Mid.for_all f meta_vars && EcUnify.UniEnv.closed e.me_unienv
(* -------------------------------------------------------------------- *)
let fsubst_of_menv (me : match_env) (env : env) =
let ps = psubst_of_menv me in
let fs = Fsubst.f_subst_init ~sty:ps.ps_sty () in
let bind_pattern id p s =
try Fsubst.f_bind_local s id (Translate.form_of_pattern env p)
with Translate.Invalid_Type _ ->
try Fsubst.f_bind_mem s id (Translate.memory_of_pattern env p)
with Translate.Invalid_Type _ ->
try Fsubst.f_bind_mod s id (Translate.mpath_of_pattern env p)
with Translate.Invalid_Type _ -> s in
Mid.fold bind_pattern me.me_matches fs
(* -------------------------------------------------------------------- *)
let menv_get_form x env menv =
obind
(fun p ->
try Some (Translate.form_of_pattern env p)
with Translate.Invalid_Type _ -> None)
(Mid.find_opt x menv.me_matches)
(* -------------------------------------------------------------------- *)
let menv_has_form x menv =
match Mid.find_opt x menv.me_meta_vars with
| Some (OGTty _) -> true | _ -> false
(* -------------------------------------------------------------------- *)
let menv_has_memory x menv =
match Mid.find_opt x menv.me_meta_vars with
| Some (OGTmem _) -> true | _ -> false
(* -------------------------------------------------------------------------- *)
let copy_environment = env_copy