123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711(** Scoping. Convert parsed terms in core terms by finding out which
identifiers are bound variables or function symbol declared in open
modules. *)openLplibopenCommonopenErroropenPosopenDebugopenSyntaxopenCoreopenTermopenEnvopenSig_stateopenPrint(** Logging function for term scoping. *)letlog_scop=Logger.make'o'"scop""term scoping"letlog_scop=log_scop.pp(** [find_qid prt prv ss env qid] returns a boxed term corresponding to a
variable of the environment [env] (or to a symbol) which name corresponds
to [qid]. In the case where the module path [fst qid.elt] is empty, we
first search for the name [snd qid.elt] in the environment, and if it is
not mapped we also search in the opened modules. The exception [Fatal] is
raised if an error occurs (e.g., when the name cannot be found). If [prt]
is true, protected symbols from external modules are allowed (protected
symbols from current modules are always allowed). If [prv] is true, private
symbols are allowed. *)letfind_qid:bool->bool->sig_state->env->p_qident->tbox=funprtprvssenvqid->ifLogger.log_enabled()thenlog_scop"find_qid %a"Pretty.qidentqid;let(mp,s)=qid.eltin(* Check for variables in the environment first. *)tryifmp<>[]thenraiseNot_found;(* Variables cannot be qualified. *)_Vari(Env.findsenv)withNot_found->(* Check for symbols. *)_Symb(find_sym~prt~prvssqid)(** [get_root ss env t] returns the symbol at the root of the term [t]. *)letget_root:sig_state->Env.t->p_term->sym=funssenvt->letrecget_roott=matcht.eltwith|P_Iden(qid,_)->find_sym~prt:true~prv:truessqid|P_Appl(t,_)->get_roott|P_Wrap(t)->get_root(Pratt.parsessenvt)|_->assertfalsein(* Pratt parse to order terms correctly. *)get_root(Pratt.parsessenvt)(** Representation of the different scoping modes. Note that the constructors
hold specific information for the given mode. *)typelhs_data={m_lhs_prv:bool(** True if private symbols are allowed. *);m_lhs_indices:(string,int)Hashtbl.t(** Stores index reserved for a pattern variable of the given name. *);m_lhs_arities:(int,int)Hashtbl.t(** Stores the arity of the pattern variable at the given index. *);m_lhs_names:(int,string)Hashtbl.t(** Stores the name of the pattern variable at given index (if any). *);mutablem_lhs_size:int(** Stores the current known size of the environment of the RHS. *);m_lhs_in_env:stringlist(** Pattern variables definitely needed in the RHS environment. *)}typemode=|M_Termof{m_term_meta_of_key:int->metaoption(** Allows to retrieve generated metas by their key. *);m_term_prv:bool(** Indicate if private symbols are allowed. *)}(** Standard scoping mode for terms, holding a map for metavariables
introduced by the user, a map for metavariables generated by the system,
and a boolean indicating whether private symbols are allowed. *)|M_Patt(** Scoping mode for patterns in the rewrite tactic. *)|M_LHSoflhs_data(** Scoping mode for rewriting rule left-hand sides. *)|M_RHSof{m_rhs_prv:bool(** True if private symbols are allowed. *);m_rhs_data:(string,tevar)Hashtbl.t(** Environment for variables that we know to be bound in the RHS. *);mutablem_rhs_new_metas:problem(** Metavariables generated during scoping. *)}(** Scoping mode for rewriting rule right-hand sides. *)|M_URHSof{mutablem_urhs_vars_nb:int(** Number of distinct variables in the rewriting rule, including
variables only in the RHS. It is initialised to the number of
(distinct) variables in the LHS and incremented each time a variable
of the RHS that was not in the LHS is scoped. *);mutablem_urhs_xvars:(string*tevar)list(** Variables scoped that were not in the LHS. This field is only used
in unification rules and is updated imperatively for each new
variable scoped. A couple [(n, v)] is the name of the variable with
the variable itself. The name is needed to ensure that two variables
with the same name are scoped as the same variable. *);m_urhs_data:(string,tevar)Hashtbl.t}(** Scoping mode for unification rule right-hand sides. During scoping, we
always have [m_urhs_vars_nb = m_lhs_size + length m_urhs_xvars]. *)(** [scope_iden md ss env qid] scopes [qid] as a symbol. *)letscope_iden:mode->sig_state->env->p_qident->tbox=funmdssenvqid->letprt=matchmdwithM_LHS_->true|_->falseandprv=matchmdwith|M_LHS(d)->d.m_lhs_prv|M_Term(d)->d.m_term_prv|M_RHS(d)->d.m_rhs_prv|_->falseinfind_qidprtprvssenvqid(** [fresh_patt name ts] creates a unique pattern variable applied to
[ts]. [name] is used as suffix if distinct from [None]. *)letfresh_patt:lhs_data->stringoption->tboxarray->tbox=fundatanoptts->letfresh_index()=leti=data.m_lhs_sizeindata.m_lhs_size<-i+1;letarity=Array.lengthtsinHashtbl.adddata.m_lhs_aritiesiarity;iinmatchnoptwith|Somename->leti=tryHashtbl.finddata.m_lhs_indicesnamewithNot_found->leti=fresh_index()inHashtbl.adddata.m_lhs_indicesnamei;Hashtbl.adddata.m_lhs_namesiname;iin_Patt(Somei)(string_of_inti)ts|None->leti=fresh_index()in_Patt(Somei)(string_of_inti)ts(** [is_invalid_bindlib_id s] says whether [s] can be safely used as variable
name in Bindlib. Indeed, because Bindlib converts any suffix consisting of
a sequence of digits into an integer, and increment it, we cannot use as
bound variable names escaped identifiers or regular identifiers ending with
a non-negative integer with leading zeros. *)letis_invalid_bindlib_id:string->bool=letreclast_digitsk=letl=k-1inifl<0then0elsematchs.[l]with|'0'..'9'->last_digitsl|_->kinfuns->letn=String.lengths-1inn>=0&&matchs.[n]with|'0'..'9'->letk=last_digitsnins.[k]='0'&&k<n|'}'->true|_->false(* unit tests *)let_=letinvalid=is_invalid_bindlib_idinletvalids=not(invalids)inassert(invalid"00");assert(invalid"01");assert(invalid"a01");assert(invalid"{|:|}");assert(valid"_x_100");assert(valid"_z1002");assert(valid"case_ex2_intro");assert(valid"case_ex02_intro");assert(valid"case_ex02_intro0");assert(valid"case_ex02_intro1");assert(valid"case_ex02_intro10")(** [scope ~typ md ss env t] turns a parser-level term [t] into an actual
term. The variables of the environment [env] may appear in [t],
and the scoping mode [md] changes the behaviour related to certain
constructors. The signature state [ss] is used to convert identifiers
into symbols according to [find_qid]. If [typ] is true, then [t]
must be a type (defaults to false). *)letrecscope:?typ:bool->int->mode->sig_state->env->p_term->tbox=fun?(typ=false)kmdssenvt->scope_parsed~typkmdssenv(Pratt.parsessenvt)(** [scope_parsed ~typ md ss env t] turns a parser-level, Pratt-parsed
term [t] into an actual term. *)andscope_parsed:?typ:bool->int->mode->sig_state->env->p_term->tbox=fun?(typ=false)kmdssenvt->ifLogger.log_enabled()thenlog_scop"%a%a"D.depthkPretty.termt;(* Extract the spine. *)letp_head,args=Syntax.p_get_argstin(* Check that LHS pattern variables are applied to no argument. *)beginmatchp_head.elt,mdwith|P_Patt_,M_LHS_whenargs<>[]->beginmatchargswith|[{elt=P_Expl_;_}]->fatalt.pos"Explicit terms are forbidden in rule LHS. \
You perhaps forgot to write a dot before?"|_->fatalt.pos"Pattern variables cannot be applied."end|_->()end;(* Scope the head and obtain the implicitness of arguments. *)leth=scope_head~typkmdssenvp_headin(* Find out whether [h] has implicit arguments. *)letrecget_implp_head=matchp_head.eltwith|P_Wrape->get_imple|P_Iden(_,false)->(* We avoid unboxing if [h] is not closed (and hence not a symbol). *)ifBindlib.is_closedhthenmatchBindlib.unboxhwith|Symbs->s.sym_impl|_->[]else[]|P_Abst(params_list,t)->Syntax.get_impl_params_listparams_list@get_implt|_->[]inletimpl=matchp_head.elt,argswith|P_Abst_,[]->[]|_->minimize_impl(get_implp_head)in(* Scope and insert the (implicit) arguments. *)add_implkmdssenvt.poshimplargs|>D.log_and_return(fune->log_scop"%agot %a"D.depthkterm(Bindlib.unboxe))(** [add_impl md ss env loc h impl args] scopes [args] and returns the
application of [h] to the scoped arguments. [impl] is a boolean list
described the implicit arguments. Implicit arguments are added as
underscores before scoping. *)andadd_impl:int->mode->sig_state->Env.t->popt->tbox->boollist->p_termlist->tbox=funkmdssenvlochimplargs->letappl=matchmdwithM_LHS_->_Appl_not_canonical|_->_Applinletappl_p_termtu=applt(scope_parsed(k+1)mdssenvu)inletappl_metat=applt(scope_head(k+1)mdssenvP.wild)inmatchimpl,argswith(* The remaining arguments are all explicit. *)|[],_->List.fold_leftappl_p_termhargs(* Only implicit arguments remain. *)|true::impl,[]->add_implkmdssenvloc(appl_metah)impl[](* The first argument is implicit (could be [a] if made explicit). *)|true::impl,a::args->beginmatcha.eltwith|P_Explb->add_implkmdssenvloc(appl_p_termh{awithelt=P_Wrapb})implargs|_->add_implkmdssenvloc(appl_metah)impl(a::args)end(* The first argument [a] is explicit. *)|false::impl,a::args->beginmatcha.eltwith|P_Expl_->fatala.pos"Unexpected explicit argument."|_->add_implkmdssenvloc(appl_p_termha)implargsend(* The application is too "partial" to insert all implicit arguments. *)|false::_,[]->(* NOTE this could be improved with more general implicits. *)fatalloc"More arguments are required to instantiate implicits."(** [scope_domain md ss env t] scopes [t] as the domain of an abstraction or
product. *)andscope_domain:int->mode->sig_state->env->p_termoption->tbox=funkmdssenva->matcha,mdwith|(Some{elt=P_Wild;_}|None),M_LHSdata->fresh_pattdataNone(Env.to_tboxenv)|(Some{elt=P_Wild;_}|None),_->_Plactrue|Somea,_->scope~typ:truekmdssenva(** [scope_binder ~typ mode ss cons env params_list t] scopes [t] in
mode [md], signature state [ss] and environment [env]. [params_list] is a
list of paramters to abstract on. For each parameter, a tbox is built using
[cons] (either [_Abst] or [_Prod]). If [warn] is true (the default), a
warning is printed when the variable that is bound by the binder does not
appear in the body. [typ] indicates if we scope a type (default is
false). *)andscope_binder:?typ:bool->int->mode->sig_state->(tbox->tbinderBindlib.box->tbox)->Env.t->p_paramslist->p_termoption->tbox=fun?(typ=false)kmdssconsenvparams_listt->letrecscope_params_listenvparams_list=matchparams_listwith|[]->beginmatchtwith|Somet->scope~typ(k+1)mdssenvt|None->_Plactrueend|(idopts,typopt,_implicit)::params_list->letdom=scope_domain(k+1)mdssenvtypoptinscope_paramsenvidoptsdomparams_listandscope_paramsenvidoptsaparams_list=letrecauxenvidopts=matchidoptswith|[]->scope_params_listenvparams_list|None::idopts->letv=new_tvar"_"inlett=auxenvidoptsinconsa(Bindlib.bind_varvt)|Some{elt=id;pos}::idopts->ifis_invalid_bindlib_ididthenfatalpos"\"%s\": Escaped identifiers or regular identifiers \
having an integer suffix with leading zeros \
are not allowed for bound variable names."id;letv=new_tvaridinletenv=Env.addvaNoneenvinlett=auxenvidoptsinconsa(Bindlib.bind_varvt)inauxenvidoptsinscope_params_listenvparams_list(** [scope_head ~typ md ss env t] scopes [t] as term head. *)andscope_head:?typ:bool->int->mode->sig_state->env->p_term->tbox=fun?(typ=false)kmdssenvt->match(t.elt,md)with|(P_Type,M_LHS(_))->fatalt.pos"TYPE is not allowed in a LHS."|(P_Type,_)->_Type|(P_Iden(qid,_),_)->scope_idenmdssenvqid|(P_NLit(0),_)->beginmatchBuiltin.get_optss"0"with|Somes->_Symbs|None->scope_idenmdssenv{twithelt=([],"0")}end|(P_NLit(n),_)->beginmatchBuiltin.get_optss"0"with|None->scope_idenmdssenv{twithelt=([],string_of_intn)}|Somesym_z->matchBuiltin.get_optss"+1"with|Somesym_s->letz=_Symbsym_zands=_Symbsym_sinletrecunsugar_nat_litaccn=ifn<=0thenaccelseunsugar_nat_lit(_Applsacc)(n-1)inunsugar_nat_litzn|None->scope_idenmdssenv{twithelt=([],string_of_intn)}end|(P_Wild,M_URHS(data))->letx=letname=string_of_intdata.m_urhs_vars_nbinletx=new_tevarnameindata.m_urhs_vars_nb<-data.m_urhs_vars_nb+1;data.m_urhs_xvars<-(name,x)::data.m_urhs_xvars;xin_TEnv(_TE_Varix)(Env.to_tboxenv)|(P_Wild,M_LHSdata)->fresh_pattdataNone(Env.to_tboxenv)|(P_Wild,M_Patt)->_Wild|(P_Wild,(M_RHS_|M_Term_))->_Plactyp|(P_Meta({elt;pos}asmk,ts),M_Term{m_term_meta_of_key;_})->(matchm_term_meta_of_keyeltwith|None->fatalpos"Metavariable %a not found among generated variables: \
metavariables can only be created by the system."Pretty.meta_identmk|Somem->_Metam(Array.map(scope(k+1)mdssenv)ts))|(P_Meta(_),_)->fatalt.pos"Metavariables are not allowed here."|(P_Patt(id,ts),M_LHS(d))->(* Check that [ts] are variables. *)letscope_vart=matchunfold(Bindlib.unbox(scope(k+1)mdssenvt))with|Vari(x)->x|_->fatalt.pos"Only bound variables are allowed in the \
environment of pattern variables."inletts=matchtswith|None->ifenv=[]then[||](* $M stands for $M[] *)elsefatalt.pos"Missing square brackets under binder."|Somets->letvs=Array.mapscope_vartsin(* Check that [vs] are distinct variables. *)fori=0toArray.lengthvs-2doforj=i+1toArray.lengthvs-1doifBindlib.eq_varsvs.(i)vs.(j)thenfatalts.(j).pos"Variable %a appears more than once \
in the environment of a pattern variable."varvs.(j)donedone;Array.map_Varivsinbeginmatchidwith|NonewhenList.lengthenv=Array.lengthts->wrnt.pos"Pattern [%a] could be replaced by [_]."Pretty.termt;|Some{elt=id;pos}whennot(List.memidd.m_lhs_in_env)->ifList.lengthenv=Array.lengthtsthenwrnpos"Pattern variable %s can be replaced by a '_'."idelsewrnpos"Pattern variable %s doesn't need to be named."id|_->()end;fresh_pattd(Option.map(funid->id.elt)id)ts|(P_Patt(id,ts),M_URHS(r))->letx=matchidwith|None->fatalt.pos"Wildcard pattern not allowed in a URHS."|Some{elt=id;_}->(* Search in variables declared in LHS. *)tryHashtbl.findr.m_urhs_dataidwithNot_found->(* Search in variables already declared in RHS. *)tryList.associdr.m_urhs_xvarswithNot_found->letname=string_of_intr.m_urhs_vars_nbinletx=new_tevarnameinr.m_urhs_vars_nb<-r.m_urhs_vars_nb+1;r.m_urhs_xvars<-(id,x)::r.m_urhs_xvars;xinletts=matchtswith|None->[||](* $M stands for $M[] *)|Somets->Array.map(scope(k+1)mdssenv)tsin_TEnv(_TE_Varix)ts|(P_Patt(id,ts),M_RHS(r))->letx=matchidwith|None->fatalt.pos"Wildcard pattern not allowed in a RHS."|Some(id)->(* Search in variables declared in LHS. *)tryHashtbl.findr.m_rhs_dataid.eltwithNot_found->fatalt.pos"Variable must be in LHS."inletts=matchtswith|None->[||](* $M stands for $M[] *)|Somets->Array.map(scope(k+1)mdssenv)tsin_TEnv(_TE_Varix)ts|(P_Patt(_,_),_)->fatalt.pos"Pattern variables are only allowed in rewriting rules."|(P_Appl(_,_),_)->assertfalse(* Unreachable. *)|(P_Arro(_,_),M_Patt)->fatalt.pos"Arrows are not allowed in patterns."|(P_Arro(a,b),_)->_Impl(scope~typ:true(k+1)mdssenva)(scope~typ:true(k+1)mdssenvb)|(P_Abst(_,_),M_Patt)->fatalt.pos"Abstractions are not allowed in patterns."|(P_Abst(xs,t),_)->scope_binderkmdss_Abstenvxs(Some(t))|(P_Prod(_,_),M_Patt)->fatalt.pos"Dependent products are not allowed in patterns."|(P_Prod(xs,b),_)->scope_binder~typ:truekmdss_Prodenvxs(Some(b))|(P_LLet(x,xs,a,t,u),(M_Term_|M_URHS_|M_RHS_))->leta=scope_binder~typ:true(k+1)mdss_Prodenvxsainlett=scope_binder(k+1)mdss_Abstenvxs(Some(t))inletv=new_tvarx.eltinletu=scope~typ(k+1)mdss(Env.addva(Some(t))env)uinifnot(Bindlib.occurvu)thenwrnx.pos"Useless let-binding (%s is not bound)."x.elt;_LLetat(Bindlib.bind_varvu)|(P_LLet(_),M_LHS(_))->fatalt.pos"Let-bindings are not allowed in a LHS."|(P_LLet(_),M_Patt)->fatalt.pos"Let-bindings are not allowed in patterns."(* Evade the addition of implicit arguments inside the wrap *)|(P_Wrap({elt=(P_Iden_|P_Abst_);_}asid),_)->scope_head~typ(k+1)mdssenvid|(P_Wrapt,_)->scope~typ(k+1)mdssenvt|(P_Expl(_),_)->fatalt.pos"Explicit argument not allowed here."letscope=letopenStdlibinletr=ref_Kindinfun?(typ=false)kmdssenvt->Debug.(record_timeScoping(fun()->r:=scope~typkmdssenvt));!r(** [scope ~typ ~mok prv expo ss env p t] turns a pterm [t] into a term in
the signature state [ss] and environment [env] (for bound
variables). If [expo] is {!constructor:Public}, then the term must not
contain any private subterms. If [~typ] is [true], then [t] must be
a type (defaults to [false]). No {b new} metavariables may appear in
[t], but metavariables in the image of [mok] may be used. The function
[mok] defaults to the function constant to [None] *)letscope_term:?typ:bool->?mok:(int->metaoption)->bool->sig_state->env->p_term->term=fun?(typ=false)?(mok=fun_->None)m_term_prvssenvt->letmd=M_Term{m_term_meta_of_key=mok;m_term_prv}inBindlib.unbox(scope~typ0mdssenvt)(** [patt_vars t] returns a couple [(pvs,nl)]. The first compoment [pvs] is an
association list giving the arity of all the “pattern variables” appearing
in the parser-level term [t]. The second component [nl] contains the names
of the “pattern variables” that appear non-linearly. If a given “pattern
variable” occurs with different arities the program fails gracefully. *)letpatt_vars:p_term->(string*int)list*stringlist=letrecpatt_varsacct=matcht.eltwith|P_Type->acc|P_Iden(_)->acc|P_Wild->acc|P_Meta(_,ts)->Array.fold_leftpatt_varsaccts|P_Patt(id,ts)->add_pattaccidts|P_Appl(t,u)->patt_vars(patt_varsacct)u|P_Arro(a,b)->patt_vars(patt_varsacca)b|P_Abst(args,t)->patt_vars(patt_vars_argsaccargs)t|P_Prod(args,b)->patt_vars(patt_vars_argsaccargs)b|P_LLet(_,args,a,t,u)->letpvs=patt_vars(patt_vars(patt_vars_argsaccargs)t)uinbeginmatchawith|None->pvs|Some(a)->patt_varspvsaend|P_NLit(_)->acc|P_Wrap(t)->patt_varsacct|P_Expl(t)->patt_varsacctandadd_patt((pvs,nl)asacc)idts=letacc,arity=matchtswith|None->(acc,0)|Some(ts)->(Array.fold_leftpatt_varsaccts,Array.lengthts)inmatchidwith|None->acc|Some{elt=id;pos}->begintryifList.associdpvs<>aritythenfatalpos"Arity mismatch for pattern variable %s."id;ifList.memidnlthenaccelse(pvs,id::nl)withNot_found->((id,arity)::pvs,nl)endandpatt_vars_argsaccargs=matchargswith|[]->acc|(_,a,_)::args->letacc=matchawithNone->acc|Somea->patt_varsaccainpatt_vars_argsaccargsinpatt_vars([],[])(** Representation of a rewriting rule prior to SR-checking. *)typepre_rule={pr_sym:sym(** Head symbol of the LHS. *);pr_lhs:termlist(** Arguments of the LHS. *);pr_vars:term_envBindlib.mvar(** Pattern variables that appear in the RHS. The last [pr_xvars_nb]
variables do not appear in the LHS. *);pr_rhs:tbox(** Body of the RHS, should only be unboxed once. *);pr_names:(int,string)Hashtbl.t(** Gives the original name (if any) of pattern variable at given index. *);pr_arities:intarray(** Gives the arity of all the pattern variables in field [pr_vars]. *);pr_xvars_nb:int(** Number of variables that appear in the RHS but not in the LHS. *)}(** [rule_of_pre_rule r] converts a pre-rewrite rule into a rewrite rule. *)letrule_of_pre_rule:pre_ruleloc->rule=fun{elt=pr;pos=rule_pos}->let{pr_lhs;pr_vars;pr_rhs;pr_arities;pr_xvars_nb;_}=prin{lhs=pr_lhs;rhs=Bindlib.(unbox(bind_mvarpr_varspr_rhs));arity=List.lengthpr_lhs;arities=pr_arities;vars=pr_vars;xvars_nb=pr_xvars_nb;rule_pos}(** [scope_rule ur ss r] turns a parser-level rewriting rule [r], or a
unification rule if [ur] is true, into a pre-rewriting rule. *)letscope_rule:bool->sig_state->p_rule->pre_ruleloc=funurss{elt=(p_lhs,p_rhs);pos}->(* Compute the set of pattern variables on both sides. *)let(pvs_lhs,nl)=patt_varsp_lhsin(* NOTE to reject non-left-linear rules check [nl = []] here. *)let(pvs_rhs,_)=patt_varsp_rhsin(* Check that pattern variables of RHS that are in the LHS have the right
arity. *)letcheck_arity(m,i)=tryletj=List.assocmpvs_lhsinifi<>jthenfatalp_lhs.pos"Arity mismatch for %s."mwithNot_found->()inList.itercheck_aritypvs_rhs;(* Scope the LHS and get the reserved index for named pattern variables. *)let(pr_lhs,lhs_indices,lhs_arities,pr_names,lhs_size)=letmode=M_LHS{m_lhs_prv=is_private(get_rootss[]p_lhs);m_lhs_indices=Hashtbl.create7;m_lhs_arities=Hashtbl.create7;m_lhs_names=Hashtbl.create7;m_lhs_size=0;m_lhs_in_env=nl@List.mapfstpvs_rhs}inletpr_lhs=scope0modessEnv.emptyp_lhsinmatchmodewith|M_LHS{m_lhs_indices;m_lhs_names;m_lhs_size;m_lhs_arities;_}->(Bindlib.unboxpr_lhs,m_lhs_indices,m_lhs_arities,m_lhs_names,m_lhs_size)|_->assertfalsein(* Check the head symbol and build the actual LHS. *)let(pr_sym,pr_lhs)=let(h,args)=get_argspr_lhsinmatchhwith|Symb(s)->ifis_constantsthenfatalp_lhs.pos"Symbol %s has been declared constant, it cannot be used as the \
head of a rewrite rule LHS."s.sym_name;ifs.sym_expo=Protec&&ss.signature.sign_path<>s.sym_paththenfatalp_lhs.pos"Cannot define rules on foreign protected symbols.";(s,args)|_->fatalp_lhs.pos"No head symbol in LHS."in(* Create the pattern variables that can be bound in the RHS. *)letpr_vars=Array.initlhs_size(funi->new_tevar(string_of_inti))inletmode=lethtbl_vars=Hashtbl.create(Hashtbl.lengthlhs_indices)inletfnki=Hashtbl.addhtbl_varskpr_vars.(i)inHashtbl.iterfnlhs_indices;ifurthenM_URHS{m_urhs_data=htbl_vars;m_urhs_vars_nb=Array.lengthpr_vars;m_urhs_xvars=[]}elseM_RHS{m_rhs_prv=is_privatepr_sym;m_rhs_data=htbl_vars;m_rhs_new_metas=new_problem()}inletpr_rhs=scope0modessEnv.emptyp_rhsinletprerule=(* We put everything together to build the pre-rule. *)letpr_arities=letfni=tryHashtbl.findlhs_aritiesiwithNot_found->assertfalse(* Unreachable. *)inArray.initlhs_sizefninifurthen(* Unification rule. *)(* We scope the RHS and retrieve variables not occurring in the LHS. *)letxvars=matchmodewith|M_URHS{m_urhs_xvars;_}->m_urhs_xvars|_->assertfalse(* Guarded by the [if ur] *)in(* Add RHS-only variables to [pr_vars] and get index of the first
one. *)let(pr_vars,pr_xvars_nb)=(* If there is no variable introduced in RHS, do nothing (typically
while scoping regular rewriting rules.) *)ifStdlib.(xvars=[])then(pr_vars,0)elseletxvars=Array.of_list(List.mapsndxvars)in(Array.appendpr_varsxvars,Array.lengthxvars)in(* We put everything together to build the pre-rule. *){pr_sym;pr_lhs;pr_vars;pr_rhs;pr_arities;pr_names;pr_xvars_nb}else(* Rewrite rule. *){pr_sym;pr_lhs;pr_vars;pr_rhs;pr_arities;pr_names;pr_xvars_nb=0}inPos.makeposprerule(** [scope_pattern ss env t] turns a parser-level term [t] into an actual term
that will correspond to selection pattern (rewrite tactic). *)letscope_pattern:sig_state->env->p_term->term=funssenvt->Bindlib.unbox(scope0M_Pattssenvt)(** [scope_rw_patt ss env t] turns a parser-level rewrite tactic specification
[s] into an actual rewrite specification (possibly containing variables of
[env] and using [ss] for aliasing). *)letscope_rw_patt:sig_state->env->p_rw_patt->(term,tbinder)rw_patt=funssenvs->matchs.eltwith|Rw_Term(t)->Rw_Term(scope_patternssenvt)|Rw_InTerm(t)->Rw_InTerm(scope_patternssenvt)|Rw_InIdInTerm(x,t)->letv=new_tvarx.eltinlett=scope_patternss((x.elt,(v,_Kind,None))::env)tinRw_InIdInTerm(bindvlift_not_canonicalt)|Rw_IdInTerm(x,t)->letv=new_tvarx.eltinlett=scope_patternss((x.elt,(v,_Kind,None))::env)tinRw_IdInTerm(bindvlift_not_canonicalt)|Rw_TermInIdInTerm(u,(x,t))->letu=scope_patternssenvuinletv=new_tvarx.eltinlett=scope_patternss((x.elt,(v,_Kind,None))::env)tinRw_TermInIdInTerm(u,bindvlift_not_canonicalt)|Rw_TermAsIdInTerm(u,(x,t))->letu=scope_patternssenvuinletv=new_tvarx.eltinlett=scope_patternss((x.elt,(v,_Kind,None))::env)tinRw_TermAsIdInTerm(u,bindvlift_not_canonicalt)