123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161(** Scoping environment for variables. *)openLplibopenBaseopenTermopenCommonopenExtraopenNameopenPrint(** Type of an environment, used in scoping to associate names to
corresponding variables and types. Note that it cannot be
implemented by a map as the order is important. The structure is similar
to {!type:Term.ctxt}, a tuple [(x,a,t)] is a variable [x], its type [a]
and possibly its definition [t]. The typing environment [x1:A1,..,xn:An]
is represented by the list [xn:An;..;x1:A1] in reverse order (last added
variable comes first). *)typeenv=(string*(var*term*termoption))listtypet=env(** [pp ppf env] prints the environment [env] on the formatter [ppf] (for
debug). *)letpp:envpp=letdefppft=outppf" ≔ %a"termtinleteltppf(s,(_,a,t))=outppf"%s: %a%a"sterma(Option.ppdef)tinCommon.Debug.D.listelt(** [empty] is the empty environment. *)letempty:env=[](** [add n v a t env] extends the environment [env] by mapping the string
[n] to [(v,a,t)]. *)letadd:string->var->term->termoption->env->env=funnvatenv->(n,(v,a,t))::env(** [find n env] returns the variable associated to the variable name
[n] in the environment [env]. If none is found, [Not_found] is raised. *)letfind:string->env->var=funnenv->let(x,_,_)=List.assocnenvinx(** [mem n env] returns [true] iff [n] is mapped to a variable in [env]. *)letmem:string->env->bool=List.mem_assoc(** [to_prod env t] builds a sequence of products/lets whose domains are the
variables of the environment [env] (from left to right), and whose body is
the term [t]. By calling [to_prod [(xn,an,None);⋯;(x1,a1,None)] t] you
obtain a term of the form [Πx1:a1,..,Πxn:an,t]. *)letto_prod:env->term->term=funenvt->letadd_prodt(_,(x,a,d))=letb=bind_varxtinmatchdwith|None->mk_Prod(a,b)|Somed->mk_LLet(a,d,b)inList.fold_leftadd_prodtenv(** [to_abst env t] builds a sequence of abstractions or let bindings,
depending on the definition of the elements in the environment whose
domains are the variables of the environment [env] (from left to right),
and which body is the term [t]:
[to_abst [(xn,an,None);..;(x1,a1,None)] t = λx1:a1,..,λxn:an,t]. *)letto_abst:env->term->term=funenvt->letadd_abstt(_,(x,a,d))=letb=bind_varxtinmatchdwith|None->mk_Abst(a,b)|Somed->mk_LLet(a,d,b)inList.fold_leftadd_absttenv(** [vars env] extracts the array of variables in [env]. Note that the order
is reversed: [vars [(xn,an);..;(x1,a1)] = [|x1;..;xn|]]. *)letvars:env->vararray=funenv->Array.of_list(List.rev_map(fun(_,(x,_,_))->x)env)(** [appl t env] applies [t] to the variables of [env]. *)letappl:term->env->term=funtenv->List.fold_right(fun(_,(x,_,_))t->mk_Appl(t,mk_Varix))envt(** [to_terms env] extracts the array of the variables in [env] and injects
them in [tbox]. This is the same as [Array.map mk_Vari (vars env)]. Note
that the order is reversed: [to_tbox [(xn,an);..;(x1,a1)] =
[|x1;..;xn|]]. *)letto_terms:env->termarray=funenv->Array.of_list(List.rev_map(fun(_,(x,_,_))->mk_Varix)env)(** [to_ctxt e] converts an environment into a context. *)letto_ctxt:env->ctxt=List.mapsnd(** [match_prod c t f] returns [f a None b] if [t] matches [Prod(a,b)],
and [f a d b] if [t] matches [LLet(a,d,b)], possibly after reduction.
@raise [Invalid_argument] if the whnf of [t] is not a product. *)letmatch_prod:ctxt->term->(term->termoption->binder->'a)->'a=functf->matchunfoldtwith|Prod(a,b)->faNoneb|LLet(a,d,b)->fa(Somed)b|_->matchEval.whnfctwith|Prod(a,b)->faNoneb|_->invalid_arg__LOC__(** [of_prod c s t] returns a tuple [(env,b)] where [b] is constructed from
the term [t] by unbinding as much dependent products as possible in the
head of [t]. The free variables created by this process, prefixed by [s],
are given (with their types) in the environment [env] (in reverse
order). For instance, if [t] is of the form [Πx1:a1, ⋯, Πxn:an, b], then
the function returns [b] and the environment [(xn,an); ⋯;(x1,a1)]. *)letof_prod:ctxt->string->term->env*term=funcst->leti=Stdlib.ref(-1)inletrecbuild_envenvt=trymatch_prodct(funadb->letname=Stdlib.(incri;s^string_of_int!i)inletx,b=unbind~namebinbuild_env(addnamexadenv)b)withInvalid_argument_->env,tinbuild_env[]t(** [of_prod_nth c n t] returns a tuple [(env,b)] where [b] is constructed
from the term [t] by unbinding [n] dependent products. The free variables
created by this process are given (with their types) in the environment
[env] (in reverse order). For instance, if [t] is of the form [Πx1:a1, ⋯,
Πxn:an, b] then the function returns [b] and the environment [(xn,an);
⋯;(x1,a1)]. [n] must be non-negative.
@raise [Invalid_argument] if [t] does not evaluate to a series of (at least)
[n] products. *)letof_prod_nth:ctxt->int->term->env*term=funcnt->letrecbuild_envienvt=ifi>=nthenenv,telsematch_prodct(funadb->letx,b=unbindbinbuild_env(i+1)(add(base_namex)xadenv)b)inbuild_env0[]t(** [of_prod_using c xs t] is similar to [of_prod s c n t] where [n =
Array.length xs] except that it replaces unbound variables by those of
[xs].
@raise [Invalid_argument] if [t] does not evaluate to a series of (at least)
[n] products. *)letof_prod_using:ctxt->vararray->term->env*term=funcxst->letn=Array.lengthxsinletrecbuild_envienvt=ifi>=nthenenv,telsematch_prodct(funadb->letxi=xs.(i)inletname=base_namexiinletenv=addnamexiadenvinbuild_env(i+1)env(substb(mk_Varixi)))inbuild_env0[]t(** [names env] returns the set of names in [env]. *)letnames:env->intStrMap.t=letadd_declidmap(s,_)=add_namesidmapinList.fold_leftadd_declStrMap.empty(** [gen_valid_idopts env ids] generates a list of pairwise distinct
identifiers distinct from those of [env] to replace [ids]. *)letgen_valid_idopts(env:env)(ids:stringlist):Pos.strlocoptionlist=letfid(idopts,idmap)=letid,idmap=get_safe_prefixididmapinSome(Pos.noneid)::idopts,idmapinfst(List.fold_rightfids([],namesenv))