123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111(** Functions to manipulate metavariables. *)openTermopenTimedletmeta_counter:intStdlib.ref=Stdlib.ref(-1)(** [reset_meta_counter ()] resets the counter used to produce meta keys. *)letreset_meta_counter()=Stdlib.(meta_counter:=-1)(** [fresh p ?name a n] creates a fresh metavariable of type [a] and arity [n]
with the optional name [name], and adds it to [p]. *)letfresh:problem->?name:string->term->int->meta=funp?namean->letm={meta_key=Stdlib.(incrmeta_counter;!meta_counter);meta_name=name;meta_type=refa;meta_arity=n;meta_value=refNone}inp:={!pwithmetas=MetaSet.addm!p.metas};m(** [fresh_box p ?name a n] is the boxed counterpart of [fresh_meta]. It is
only useful in the rare cases where the type of a metavariable contains a
free term variable environment. This should only happens when scoping the
rewriting rules, use this function with care. The metavariable is created
immediately with a dummy type, and the type becomes valid at unboxing. The
boxed metavariable should be unboxed at most once, otherwise its type may
be rendered invalid in some contexts. *)letfresh_box:problem->?name:string->tbox->int->metaBindlib.box=funp?namean->letm=freshp?namemk_KindninBindlib.box_apply(funa->m.meta_type:=a;m)a(** [set p m v] sets the metavariable [m] of [p] to [v]. WARNING: No specific
check is performed, so this function may lead to cyclic terms. To use with
care. *)letset:problem->meta->tmbinder->unit=funpmv->m.meta_type:=mk_Kind;(* to save memory *)m.meta_value:=Somev;p:={!pwithmetas=MetaSet.removem!p.metas}(** [name m] returns a string representation of [m]. *)letname:meta->string=funm->matchm.meta_namewith|Somen->n|None->string_of_intm.meta_key(** [of_name p n] returns [Some m] if [m] is an element of the set of metas of
[p] with name [n], and [None] otherwise. *)letof_name:string->problem->metaoption=funnp->letexceptionFoundofmetainletfm=ifm.meta_name=Somenthenraise(Foundm)intryMetaSet.iterf!p.metas;NonewithFoundm->Somem(** [make p ctx a] creates a fresh metavariable term of type [a] in the
context [ctx], and adds it to [p]. *)letmake:problem->ctxt->term->term=funpctxa->leta,k=Ctxt.to_prodctxainletm=freshpakinletget_var(x,_,_)=mk_Varixinmk_Meta(m,Array.of_list(List.rev_mapget_varctx))(** [make_codomain p ctx a] creates a fresh metavariable term of type [Type]
in the context [ctx] extended with a fresh variable of type [a], and
updates [p] with generated metavariables. *)letmake_codomain:problem->ctxt->term->tbinder=funpctxa->letx=new_tvar"x"inletb=makep((x,a,None)::ctx)mk_TypeinBindlib.unbox(Bindlib.bind_varx(liftb))(* Possible improvement: avoid lift by defining a function _Meta.make
returning a tbox. *)(** [iter b f c t] applies the function [f] to every metavariable of [t] and,
if [x] is a variable of [t] mapped to [v] in the context [c], then to every
metavariable of [v], and to the type of every metavariable recursively if
[b] is true. *)letiter:bool->(meta->unit)->ctxt->term->unit=funbfc->(* Convert the context into a map. *)letvm=letfvm(x,_,v)=matchvwith|Somev->VarMap.addxvvm|None->vminStdlib.ref(List.fold_leftfVarMap.emptyc)in(*TODO: make iter tail recursive. *)letrecitert=matchunfoldtwith|Patt_|TEnv_|Wild|TRef_|Type|Kind|Symb_->()|Varix->beginmatchVarMap.find_optxStdlib.(!vm)with|Somev->Stdlib.(vm:=VarMap.removex!vm);iterv|None->()end|Prod(a,b)|Abst(a,b)->itera;iter(Bindlib.substbmk_Kind)|Appl(t,u)->itert;iteru|Meta(m,ts)->fm;Array.iteriterts;ifbtheniter!(m.meta_type)|LLet(a,t,u)->itera;itert;iter(Bindlib.substumk_Kind)initer(** [occurs m c t] tests whether the metavariable [m] occurs in the term [t]
when variables defined in the context [c] are unfolded. *)letoccurs:meta->ctxt->term->bool=letexceptionFoundinfunmct->letfp=ifm==pthenraiseFoundintryiterfalsefct;falsewithFound->true