1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243(* This file is free software, part of Logtk. See file "license" for more details. *)(** {1 Inner Terms} *)moduleI=Int32letzero=I.zerolet(<<<)=I.shift_leftlet(>>>)=I.shift_right_logicallet(&&&)=I.logandlet(|||)=I.logorlet(~~~)=I.lognot(* flags for propetries
flag is set if for any subterm the corresponding property holds *)letf_has_freevars=I.oneletf_is_beta_reducible=f_has_freevars<<<1(* If DB has more than 16 bits (very unlikely),
then we set a bit that forces to recompute the property *)letf_db_overflowed=f_is_beta_reducible<<<1letf_has_lams=f_db_overflowed<<<1letf_has_quant=f_has_lams<<<1(* From 16th bit onwards, we will keep the maximum
De Bruijn variable seen so far. *)letf_db_mask=(~~~zero)<<<16letmax_db=I.to_int(f_db_mask>>>16)letset_propertypropsprop_flag=props|||prop_flagletunset_propertypropsprop_flag=props&&&(~~~prop_flag)letget_propertypropsprop_flag=not@@I.equalzero(props&&&prop_flag)letdec_max_dbprops=letmax_db_val=I.to_int((props&&&f_db_mask)>>>16)inletcleared=props&&&(~~~f_db_mask)inletmax_db_val=(I.of_int@@max(max_db_val-1)0)<<<16incleared|||max_db_valletupdate_max_dbpropsnew_db=ifnew_db>max_dbthen(set_propertypropsf_db_overflowed)else(letmax_db_val=max(I.to_int((props&&&f_db_mask)>>>16))new_dbin(props&&&(~~~f_db_mask))|||((I.of_intmax_db_val)<<<16))letget_max_dbprops=I.to_int((props&&&f_db_mask)>>>16)(* Properties that should be set if they are set for ANY of the subterms *)letany_props=f_is_beta_reducible|||f_has_freevars|||f_has_lams|||f_has_quant(* Properties that should be set if they are set for ALL of the subterms *)letall_props=zero(* currently no props like that -- is_closed computed
by looking at the value of max_db *)letdebug_propsoutprops=CCFormat.fprintfout"db:%d"(get_max_dbprops);CCFormat.fprintfout" h_fv:%b"(get_propertypropsf_has_freevars);CCFormat.fprintfout" h_l:%b"(get_propertypropsf_has_lams);CCFormat.fprintfout" h_q:%b"(get_propertypropsf_has_quant);CCFormat.fprintfout" beta_r:%b@."(get_propertypropsf_is_beta_reducible);typet={term:view;ty:type_result;mutableid:int;mutablepayload:exn;props:I.t;ho_weight:intlazy_t;}(* head form *)andview=|VaroftHVar.t(** Free or bound variable *)|DBofint|BindofBinder.t*t*t(** Type, sub-term *)|ConstofID.t(** Constant *)|Appoft*tlist(** Uncurried application *)|AppBuiltinofBuiltin.t*tlist(** For representing special constructors *)andtype_result=|NoType|HasTypeofttypeterm=tletany_props_for_ts=List.fold_left(funacct->letnew_props=(any_props&&&t.props)|||accinupdate_max_dbnew_props(get_max_dbt.props))zeroletadd_ty_varspropsty_props=ifget_propertyty_propsf_has_freevarsthen(set_propertypropsf_has_freevars)elsepropsletadd_ty_varspropsty_props=ifget_propertyty_propsf_has_freevarsthen(set_propertypropsf_has_freevars)elsepropslet[@inline]viewt=t.termlet[@inline]tyt=t.tylet[@inline]ty_exnt=matcht.tywith|NoType->invalid_arg"InnerTerm.ty_exn"|HasTypety->tylet[@inline]hasht=Hash.intt.idlet[@inline]equal:t->t->bool=funt1t2->t1==t2let[@inline]comparet1t2=Pervasives.comparet1.idt2.idletrecsame_l_recl1l2=matchl1,l2with|[],[]->true|[],_|_,[]->assertfalse|x1::tail1,x2::tail2->equalx1x2&&same_l_rectail1tail2letsame_ll1l2=matchl1,l2with|[],[]->true|[t1],[t2]->equalt1t2|[t1;u1],[t2;u2]->equalt1t2&&equalu1u2|_->same_l_recl1l2let[@inline]ty_is_funty=matchviewtywith|AppBuiltin(Builtin.Arrow,_ret::args)->List.lengthargs!=0|_->falseletsame_l_genl1l2=List.lengthl1==List.lengthl2&&same_ll1l2let_hash_tyt=matcht.tywith|NoType->1|HasTypety->Hash.combine22ty.idlet_hash_norect=matchviewtwith|Varv->Hash.combine21(HVar.hashv)|DBv->Hash.combine22(Hash.intv)|Bind(b,varty,t')->Hash.combine43(Binder.hashb)(hashvarty)(hasht')|Consts->Hash.combine24(ID.hashs)|App(f,l)->Hash.combine310(hashf)(Hash.listhashl)|AppBuiltin(b,l)->Hash.combine320(Builtin.hashb)(Hash.listhashl)lethash_mod_alphat:int=letrecaux(d:int)t=leth_t=ifd=0then10(* fuel is exhausted *)elsematcht.termwith|Var_->1(* ignore variable's name *)|DBv->Hash.combine22(Hash.intv)|Bind(b,varty,t')->Hash.combine43(Binder.hashb)(aux(d-1)varty)(aux(d-1)t')|Consts->Hash.combine24(ID.hashs)|App(f,l)->Hash.combine310(aux(d-1)f)(Hash.list(aux(d-1))l)|AppBuiltin(b,l)->Hash.combine320(Builtin.hashb)(Hash.list(aux(d-1))l)andh_ty=matcht.tywith|NoType->0|HasTypety->auxdtyinHash.combine342h_th_tyinaux2tlet_eq_tyt1t2=matcht1.ty,t2.tywith|NoType,NoType->true|HasTypety1,HasTypety2->equalty1ty2|_->falseletrec_eq_norec_listl1l2=matchl1,l2with|[],[]->true|[],_|_,[]->false|t1::l1',t2::l2'->equalt1t2&&_eq_norec_listl1'l2'letrec_eq_record_listl1l2=matchl1,l2with|[],[]->true|[],_|_,[]->false|(n1,t1)::l1',(n2,t2)::l2'->n1=n2&&equalt1t2&&_eq_record_listl1'l2'let_eq_norect1t2=_eq_tyt1t2&&matcht1.term,t2.termwith|Vari,Varj->HVar.equalequalij|DBi,DBj->i=j|Consts1,Consts2->ID.equals1s2|Bind(b1,varty1,t1'),Bind(b2,varty2,t2')->Binder.equalb1b2&&equalvarty1varty2&&equalt1't2'|App(f1,l1),App(f2,l2)->equalf1f2&&_eq_norec_listl1l2|AppBuiltin(b1,l1),AppBuiltin(b2,l2)->Builtin.equalb1b2&&_eq_norec_listl1l2|_->false(** {3 Constructors} *)(* XXX: use cppo?
module H = Hashcons.MakeNonWeak(struct
*)moduleH=Hashcons.Make(structtypet=termletequal=_eq_noreclethash=_hash_noreclet[@inline]tagit=assert(t.id=~-1);t.id<-iend)lethashcons_stats()=H.stats()exceptionNo_payloadexceptionIllFormedTermofstringtypenat=intletrecopen_bindbt=matchviewtwith|Bind(b',ty,t')whenb=b'->letargs,ret=open_bindbt'inty::args,ret|_->[],tlet[@inline]is_vart=matchviewtwith|Var_->true|_->falselet[@inline]is_lamt=matchviewtwith|Bind(Binder.Lambda,_,_)->true|_->falseletopen_funty=matchviewtywith|AppBuiltin(Builtin.Arrow,ret::args)->args,ret|_->[],tyletho_weight_tt_ty=letrecauxtt_ty=letinit_ws_ty=matchs_tywith|NoType->0|HasTypety->beginmatchviewtywith|AppBuiltin(Builtin.Arrow,l)->List.lengthl-1|_->0endinbeginmatchtwith|Var_|DB_|Const_->init_wt_ty+1|Bind(Binder.Lambda,_,t')->let_,t'=open_bindBinder.Lambdat'ininit_w(tyt')+aux(viewt')(tyt')|Bind(_,_,t')->aux(viewt')(tyt')|App(f,l)->ifis_varfthen1elseinit_wt_ty+aux_l(aux(viewf)(tyf))l|AppBuiltin(_,l)->aux_l(init_wt_ty+1)lendandaux_lacc=function|[]->acc|x::xs->aux_l(acc+aux(viewx)(tyx))xsinauxtt_tylet[@inline]ho_weightt=Lazy.forcet.ho_weightletmake_~props~tyterm={term;ty;id=~-1;payload=No_payload;props;ho_weight=lazy(ho_weight_termty)}letconst~tys=letmy_t=make_~props:(add_ty_varszeroty.props)~ty:(HasTypety)(Consts)inH.hashconsmy_tletbuiltin~tyb=letmy_t=make_~props:(add_ty_varszeroty.props)~ty:(HasTypety)(AppBuiltin(b,[]))inH.hashconsmy_tlettType=letmy_t=make_~props:zero~ty:NoType(AppBuiltin(Builtin.TType,[]))inH.hashconsmy_tletopen_funty=matchviewtywith|AppBuiltin(Builtin.Arrow,ret::args)->args,ret|_->[],tylet[@inline]is_a_typet=matchtytwith|HasTypety->equaltytType|NoType->assertfalseletexpected_argst=matchviewtwith|AppBuiltin(Builtin.Arrow,l)->CCList.lengthl-1|_->0letrecdebugfoutt=matchviewtwith|AppBuiltin(b,[])->Builtin.ppoutb|AppBuiltin(b,l)->Format.fprintfout"(@[<1>%a@ %a@])"Builtin.ppb(Util.pp_listdebugf)l|Vari->HVar.ppouti|DBi->Format.fprintfout"Y%d"i|Consts->ID.ppouts|App(_,[])->assertfalse|App(s,l)->Format.fprintfout"(@[<1>%a@ %a@])"debugfs(Util.pp_listdebugf)l|Bind(b,varty,t')->Format.fprintfout"(@[<1>%a@ %a@ %a@])"Binder.ppbdebugfvartydebugft'letflatten_and_orbl=letrecauxacc=function|[]->List.revacc|x::xs->matchviewxwith|AppBuiltin(b',ys)whenBuiltin.equalbb'->auxacc(ys@xs)|_->aux(x::acc)xsinifBuiltin.is_flattened_logicalbthenaux[]lelselletrecapp_builtin~tybl=letprop=builtin~ty:tTypeBuiltin.propinletl=flatten_and_orblinmatchb,lwith|Builtin.Arrow,[]->assertfalse|Builtin.Arrow,[ret]->ret|Builtin.Arrow,({term=AppBuiltin(Builtin.Arrow,ret::l1);_}::l2)->(* flatten *)app_builtin~tyBuiltin.Arrow(ret::l2@l1)|Builtin.Not,[]->letty=app_builtin~ty:tTypeBuiltin.arrow[prop;prop]inletmy_t=make_~props:zero~ty:(HasTypety)(AppBuiltin(b,[]))inH.hashconsmy_t|(Builtin.And|Builtin.Or),lwhenCCList.lengthl<2&&expected_argsty<2->letargs=(ifCCList.is_emptylthen[prop]else[])@[prop;prop]inletty=app_builtin~ty:tTypeBuiltin.arrowargsinletprops=add_ty_vars(any_props_for_tsl)ty.propsinletmy_t=make_~props~ty:(HasTypety)(AppBuiltin(b,l))inH.hashconsmy_t|_->assert(not(List.membBuiltin.[Eq;Neq;ForallConst;ExistsConst])||List.lengthl>=1&&is_a_type(List.hdl));letty=ifBuiltin.is_quantifierb&&List.lengthl=2then((* reassing the type if other parts of the code assigned it wrong *)prop)elsetyinletprops=add_ty_vars(any_props_for_tsl)ty.propsinletprops=ifBuiltin.is_quantifierb&&List.lengthl=2then(set_propertypropsf_has_quant)elsepropsinletmy_t=make_~props~ty:(HasTypety)(AppBuiltin(b,l))inH.hashconsmy_tletarrowlr=app_builtin~ty:tTypeBuiltin.arrow(r::l)letapp~tyfl=matchf.term,lwith|_,[]->f|App(f1,l1),_::_->(* flatten *)letflattened=l1@linletprops=add_ty_vars(any_props_for_ts(f1::flattened))ty.propsinletprops=ifis_lamf1thenset_propertypropsf_is_beta_reducibleelsepropsinletmy_t=make_~props~ty:(HasTypety)(App(f1,flattened))inH.hashconsmy_t|AppBuiltin(f1,l1),_->lett_args=flatten_and_orf1l1@linletty=ifBuiltin.is_logical_opf1&¬(Builtin.is_quantifierf1)then(letprop=builtin~ty:tTypeBuiltin.Propinletargs,_=open_funtyinifList.lengthargs>0then(ty)elseifBuiltin.is_logical_binopf1then(ifList.lengtht_args>=2thenpropelse(ifList.lengtht_args=1thenarrow[prop]propelsearrow[prop;prop]prop))else(ifList.lengtht_args=1thenpropelsearrow[prop]prop))elsetyinletprops=add_ty_vars(any_props_for_tst_args)ty.propsinletprops=ifBuiltin.is_quantifierf1&&List.lengtht_args=2then(set_propertypropsf_has_quant)elsepropsinletmy_t=make_~props~ty:(HasTypety)(AppBuiltin(f1,t_args))inH.hashconsmy_t|_->letprops=add_ty_vars(any_props_for_ts(f::l))ty.propsinletprops=ifis_lamfthenset_propertypropsf_is_beta_reducibleelsepropsinletmy_t=make_~props~ty:(HasTypety)(App(f,l))inH.hashconsmy_tletvarv=letprops=set_propertyzerof_has_freevarsinH.hashcons(make_~props~ty:(HasType(HVar.tyv))(Varv))letbvar~tyi=ifi<0thenraise(IllFormedTerm"bvar");letmax_db=i+1inletprops=add_ty_vars(update_max_dbzeromax_db)ty.propsinH.hashcons(make_~props~ty:(HasTypety)(DBi))letbind~ty~vartyst'=letprops=add_ty_vars(add_ty_varst'.propsty.props)varty.propsinletprops=ifBinder.equalBinder.Lambdas||Binder.equalBinder.ForallTysthendec_max_dbpropselsepropsinletprops=ifBinder.equalBinder.Lambdasthenset_propertypropsf_has_lamselsepropsinH.hashcons(make_~props~ty:(HasTypety)(Bind(s,varty,t')))letcast~tyold=matchold.termwith|Varv->var(HVar.castv~ty)|DBi->bvar~tyi|Consts->const~tys|Bind(s,varty,t')->bind~tys~vartyt'|App(f,l)->app~tyfl|AppBuiltin(s,l)->app_builtin~tysllet[@inline]is_bvart=matchviewtwith|DB_->true|_->falselet[@inline]is_constt=matchviewtwith|Const_->true|_->falselet[@inline]is_bindt=matchviewtwith|Bind_->true|_->falselet[@inline]is_appt=matchviewtwith|App_->true|_->falselet[@inline]is_tTypet=matchviewtwithAppBuiltin(Builtin.TType,_)->true|_->falselet[@inline]is_lambdat=matchviewtwithBind(Binder.Lambda,_,_)->true|_->false(** {3 Payload} *)letpayloadt=t.payloadletset_payload_erasete=t.payload<-eletset_payloadte=matcht.payloadwith|No_payload->t.payload<-e|_->invalid_arg"Term.set_payload: collision"(** {3 Containers} *)moduleAsKey=structtypet=termletequal=equallethash=hashletcompare=compareendmoduleSet=CCSet.Make(AsKey)moduleMap=CCMap.Make(AsKey)moduleTbl=CCHashtbl.Make(AsKey)moduleHVarKey=structtypet=termHVar.tletcompare=HVar.comparecompareletequal=HVar.equalequallethash=HVar.hashendmoduleVarMap=CCMap.Make(HVarKey)moduleVarSet=CCSet.Make(HVarKey)moduleVarTbl=CCHashtbl.Make(HVarKey)(** {3 Basic Printer} *)let[@inline]has_lambdat=get_propertyt.propsf_has_lamslet[@inline]is_eta_reduciblet=(* if it has a quantifier -- we have to expand *)get_propertyt.propsf_has_quant||get_propertyt.propsf_has_lamslet[@inline]is_beta_reduciblet=letres=get_propertyt.propsf_is_beta_reducibleinassert(notres||has_lambdat);res(** {3 De Bruijn} *)moduleDB=structtypeenv=tDBEnv.t(* sequence2 of [De Bruijn, depth] pairs *)letrec_to_iter~depthtk=beginmatcht.tywith|NoType->()|HasTypety->_to_iter~depthtykend;matchviewtwith|DBv->k(v,depth)|Var_|Const_->()|Bind(_,varty,t')->_to_iter~depthvartyk;_to_iter~depth:(depth+1)t'k|AppBuiltin(_,l)->List.iter(funt->_to_iter~depthtk)l|App(f,l)->_to_iter~depthfk;List.iter(funt->_to_iter~depthtk)llet[@inline]_idx=xletclosedt=letdb_calct=_to_iter~depth:0t|>Iter.map(fun(bvar,depth)->bvar<depth)|>Iter.for_all_idinifget_propertyt.propsf_db_overflowedthen(db_calct)else(letres=(get_max_dbt.props)=0in(* if(res != db_calc t) then (
CCFormat.printf "t:@[%a@];max_db:%d@." debugf t (get_max_db t.props);
assert(false);
); *)res)(* check whether t contains the De Bruijn symbol n *)letcontainstn=_to_iter~depth:0t|>Iter.map(fun(bvar,depth)->bvar=n+depth)|>Iter.exists_idletunboundt=_to_iter~depth:0t|>Iter.filter_map(fun(bvar,depth)->ifbvar>=depththenSome(bvar-depth)elseNone)|>Iter.to_rev_list(* maps the term to another term, calling [on_binder acc t]
when it meets a binder, and [on_bvar acc t] when it meets a
bound variable. *)let_fold_map?(depth=0)acc~on_bvar~on_bindert=letrecrecurse~depthacct=matcht.tywith|NoType->assert(t==tType);t|HasTypety->letty=recurse~depthacctyinmatchviewtwith|Varv->var(HVar.cast~tyv)|DBi->bvar~ty(on_bvar~depthacci)|Consts->const~tys|Bind(s,varty,t')->letacc'=on_binder~ty~depthaccsvartyinletvarty'=recurse~depthaccvartyinlett'=recurse~depth:(depth+1)acc't'inbind~ty~varty:varty'st'|App(f,l)->app~ty(recurse~depthaccf)(List.map(recurse~depthacc)l)|AppBuiltin(s,l)->app_builtin~tys(List.map(recurse~depthacc)l)inrecurse~depthacct(* shift the non-captured De Bruijn indexes in the term by n *)letshift_real?depthnt=assert(n>=0);_fold_map?depth()~on_bvar:(fun~depth()i->ifi>=depththeni+n(* shift *)elsei)~on_binder:(fun~ty:_~depth:_()__->())tletshift?(depth=0)nt=ifdepth=0&&n=0thentelseshift_real~depthntletunshift_real?depthnt=_fold_map?depth()~on_bvar:(fun~depth()i->ifi>=depth+nthen(i-n(* unshift *))elsei)~on_binder:(fun~ty:_~depth:_()__->())tletunshift?(depth=0)nt=assert(n>=0);ifdepth=0&&n=0thentelseunshift_real~depthnt(* recurse and replace elements of l. *)letrec_replacedepth~to_replacet=matcht.tywith|NoType->assert(t==tType);t|HasTypety->letty=_replacedepthty~to_replaceinmatchviewtwith|_whenCCList.exists(equalt)to_replace->beginmatchCCList.find_idx(equalt)to_replacewith|None->assertfalse|Some(i,t')->assert(equaltt');bvar~ty(depth+List.lengthto_replace-i-1)(* replace *)end|Varv->var(HVar.cast~tyv)|DBi->ifi<depththenbvar~tyielsebvar~ty(i+List.lengthto_replace)(* shift *)|Consts->const~tys|Bind(s,varty,t')->letvarty'=_replacedepth~to_replacevartyinlett'=_replace(depth+1)t'~to_replaceinbind~ty~varty:varty'st'|App(f,l)->app~ty(_replacedepth~to_replacef)(List.map(_replacedepth~to_replace)l)|AppBuiltin(s,l)->app_builtin~tys(List.map(_replacedepth~to_replace)l)letreplace_lt~l=_replace0t~to_replace:lletreplacet~sub=_replace0t~to_replace:[sub]letfrom_vart~var=assert(is_varvar);replacet~sub:varlet_evalenv0t=letrec_evalenvt=matcht.tywith|NoType->assert(t==tType);t|HasTypety->letty=_evalenvtyinmatchviewtwith|Varv->var(HVar.cast~tyv)|DBi->beginmatchDBEnv.findenviwith|None->ifi>=DBEnv.sizeenvthenbvar~ty(i-DBEnv.sizeenv0)(* unshift *)elsebvar~tyi|Somet'->(* type might not be exactly equal, e.g. might be equal
up to unifier *)(*assert (equal (ty_exn t') ty);*)(* [t'] is defined in scope 0, but there are [i-1] binders
between the scope where its open variables live, and
the current scope.
Therefore we must lift by [i-1].
The depth is the number of binders between the original [env0]
and current [env]. *)shift(DBEnv.sizeenv-DBEnv.sizeenv0)t'end|Consts->const~tys|Bind(s,varty,t')->letvarty'=_evalenvvartyinlett'=_eval(DBEnv.push_noneenv)t'inbind~ty~varty:varty'st'|App(f,l)->app~ty(_evalenvf)(List.map(_evalenv)l)|AppBuiltin(s,l)->app_builtin~tys(List.map(_evalenv)l)in_evalenv0tletevalenvt=ifDBEnv.is_emptyenvthentelse_evalenvtletapply_substsubstt=letrecauxdeptht=matcht.tywith|NoType->assert(t==tType);t|HasTypety->letty=auxdepthtyinaux'depthtytandaux'depthtyt=matchviewtwith|Varv->begintryshiftdepth(VarMap.findvsubst)withNot_found->var(HVar.cast~tyv)end|DBi->bvar~tyi|Consts->const~tys|Bind(s,varty,t')->letvarty'=auxdepthvartyinlett'=aux(depth+1)t'inbind~ty~varty:varty'st'|App(f,l)->app~ty(auxdepthf)(List.map(auxdepth)l)|AppBuiltin(s,l)->app_builtin~tys(List.map(auxdepth)l)inaux0tendletbind_vars~tybvarst=(* subst: bind vars_i to a De Bruijn (reverse list so that last element is 0) *)letsubst=CCList.foldi(funsiv->VarMap.addv(bvar~ty:(HVar.tyv)i)s)VarMap.empty(List.revvars)inList.fold_right(funvt->letvarty=HVar.tyv|>DB.apply_substsubstinbind~ty~vartybt)vars(DB.apply_substsubstt)(** {3 Iterators} *)moduleSeq=structletvarstk=letrecvarst=matchviewtwith|Varv->kv|DB_|Const_->()|App(head,l)->varshead;List.itervarsl|AppBuiltin(_,l)->List.itervarsl|Bind(_,varty,t')->varsvarty;varst'invarstletsubtermstk=letrecsubtermst=kt;matchviewtwith|Var_|DB_|Const_->()|Bind(_,varty,t')->subtermsvarty;subtermst'|AppBuiltin(_,l)->List.itersubtermsl|App(f,l)->subtermsf;List.itersubtermslinsubtermstletsubterms_depthtk=letrecrecursedeptht=k(t,depth);matchviewtwith|App(_,l)->letdepth'=depth+1inList.iter(funt'->recursedepth't')l|AppBuiltin(_,l)->List.iter(recurse(depth+1))l|Bind(_,varty,t')->recursedepthvarty;recurse(depth+1)t'|Const_|DB_|Var_->()inrecurse0tletsymbolstk=letrecsymbolst=matchviewtwith|DB_|Var_->()|Consts->ks|App(head,l)->symbolshead;List.itersymbolsl|AppBuiltin(_,l)->List.itersymbolsl|Bind(_,varty,t')->symbolsvarty;symbolst'insymbolstlettypestk=letrectypest=beginmatcht.tywith|NoType->()|HasTypety->ktyend;matchviewtwith|Var_|DB_|Const_->()|App(head,l)->typeshead;List.itertypesl|AppBuiltin(_,l)->List.itertypesl|Bind(_,_,t')->typest'intypestletmax_varseq=letr=ref0inseq(funi->r:=max(HVar.idi)!r);!rletmin_varseq=letr=refmax_intinseq(funi->r:=min(HVar.idi)!r);!rletadd_set=Iter.fold(funsett->Set.addtset)letadd_tbltbl=Iter.iter(funt->Tbl.replacetblt())end(** {3 Positions} *)modulePos=structmoduleP=Positionletfail_tpos=Util.errorf~where:"Term.Pos""@[<2>invalid position `@[%a@]`@ in term `@[%a@]`@]"P.ppposdebugftletrecattpos=matchviewt,poswith|_,P.Typepos'->beginmatcht.tywith|NoType->fail_tpos|HasTypety->attypos'end|_,P.Stop->t|Var_,_->fail_tpos|Bind(_,_,t'),P.Bodysubpos->att'subpos|App(t,_),P.Headsubpos->attsubpos|App(_,l),P.Arg(n,subpos)whenn<List.lengthl->at(List.nthl(List.lengthl-1-n))subpos|AppBuiltin(_,l),P.Arg(n,subpos)whenn<List.lengthl->at(List.nthl(List.lengthl-1-n))subpos|_->fail_tposletrecreplacetpos~by=matcht.ty,viewt,poswith|_,_,P.Stop->by|NoType,_,P.Type_->fail_tpos|HasTypety,_,P.Typepos'->letty=replacetypos'~byincast~tyt|_,Var_,_->fail_tpos|HasTypety,Bind(s,varty,t'),P.Bodysubpos->bind~ty~vartys(replacet'subpos~by)|HasTypety,App(f,l),P.Headsubpos->app~ty(replacefsubpos~by)l|HasTypety,App(f,l),P.Arg(n,subpos)whenn<List.lengthl->letn'=List.lengthl-1-ninlett'=replace(List.nthln')subpos~byinletl'=CCList.set_at_idxn't'linapp~tyfl'|HasTypety,AppBuiltin(s,l),P.Arg(n,subpos)whenn<List.lengthl->letn'=List.lengthl-1-ninlett'=replace(List.nthln')subpos~byinletl'=CCList.set_at_idxn't'linapp_builtin~tysl'|_->fail_tposendletreplace_mtm=letrecauxdeptht=matchMap.get(DB.shiftdeptht)mwith|Someu->assert(ty_exnu==ty_exnt);DB.shiftdepthu|None->beginmatcht.ty,viewtwith|HasTypety,Bind(s,varty,t')->letty=auxdepthtyinbind~ty~vartys(aux(depth+1)t')|HasTypety,App(f,l)->letty=auxdepthtyinletf'=auxdepthfinletl'=List.map(auxdepth)linapp~tyf'l'|HasTypety,AppBuiltin(s,l)->letty=auxdepthtyinletl'=List.map(auxdepth)linapp_builtin~tysl'|NoType,_->t|_,(Var_|DB_|Const_)->tendinaux0t(* [replace t ~old ~by] syntactically replaces all occurrences of [old]
in [t] by the term [by]. *)letreplacet~old~by=letm=Map.singletonoldbyinreplace_mtm(** {3 Variables} *)(* TODO: sort variables, so that type variables come first *)letclose_vars~tyst=letvars=Seq.varst|>VarSet.of_iter|>VarSet.elementsinbind_vars~tysvarst(* make the function closing over all the arguments *)letmk_fun~ty_l(t:t):t=ifty_l=[]thentelse((* close over environment *)List.fold_right(funvartybody->letty=arrow[varty](ty_exnbody)inbind~ty~vartyBinder.Lambdabody)ty_lt)letfun_(ty_arg:t)body=letty=arrow[ty_arg](ty_exnbody)inbind~ty~varty:ty_argBinder.Lambdabodyletfun_lty_argsbody=List.fold_rightfun_ty_argsbodyletfun_of_fvarsvarsbody=ifvars=[]thenbodyelse(letbody=DB.replace_lbody~l:(List.mapvarvars)inList.fold_right(funvbody->fun_(HVar.tyv)body)varsbody)letopen_bind_freshbt=letrecauxenvvarst=matchviewtwith|Bind(b',ty_var,body)whenb=b'->letv=HVar.fresh~ty:ty_var()inletenv=DBEnv.pushenv(varv)inauxenv(v::vars)body|_->lett'=DB.evalenvtinList.revvars,t'inauxDBEnv.empty[]tletopen_bind_fresh2?(eq_ty=equal)bt1t2=letrecauxenvvarst1t2=matchviewt1,viewt2with|Bind(b1,ty_var1,body1),Bind(b2,ty_var2,body2)whenb1=b&&b2=b&&eq_tyty_var1ty_var2->letv=HVar.fresh~ty:ty_var1()inletenv=DBEnv.pushenv(varv)inauxenv(v::vars)body1body2|_->lett1=DB.evalenvt1inlett2=DB.evalenvt2inList.revvars,t1,t2inauxDBEnv.empty[]t1t2letrecopen_poly_funty=matchviewtywith|Bind(Binder.ForallTy,_,ty')->leti,args,ret=open_poly_funty'ini+1,args,ret|_->letargs,ret=open_funtyin0,args,retletrecreturnsty=matchviewtywith|Bind(Binder.ForallTy,_,ty')->returnsty'|AppBuiltin(Builtin.Arrow,ret::_)->ret|_->tyletrecexpected_ty_varsty=matchviewtywith|Bind(Binder.ForallTy,_,ty')->1+expected_ty_varsty'|_->0letis_groundt=not@@get_propertyt.propsf_has_freevars(** {3 Misc} *)letrecsizet=matchviewtwith|Const_|Var_|DB_->1|Bind(_,_,t')->1+sizet'|AppBuiltin(_,l)->List.fold_left(funst->s+sizet)1l|App(head,l)->_size_list(1+sizehead)land_size_listaccl=matchlwith|[]->acc|t::l'->_size_list(acc+sizet)l'letdeptht=Seq.subterms_deptht|>Iter.mapsnd|>Iter.foldmax0letrecheadt=matchviewtwith|Consts->Somes|DB_|Var_|Bind(_,_,_)|AppBuiltin(_,_)->None|App(h,_)->headhlettype_is_unifiable(ty:t):bool=matchviewtywith|AppBuiltin((Builtin.TyInt|Builtin.TyRat),_)|Bind(Binder.ForallTy,_,_)->false|_->truelettype_non_unifiable_tags(ty:t):_list=matchviewtywith|AppBuiltin(Builtin.TyInt,_)->[Builtin.Tag.T_lia;Builtin.Tag.T_cannot_orphan]|AppBuiltin(Builtin.TyRat,_)->[Builtin.Tag.T_lra;Builtin.Tag.T_cannot_orphan]|Bind(Binder.ForallTy,_,_)->[Builtin.Tag.T_ho]|_->[]lettype_is_propt=matchviewtwithAppBuiltin(Builtin.Prop,_)->true|_->falselet[@inline]get_typet=matchtytwith|HasTypety->ty|NoType->invalid_arg"must have type!"let[@inline]as_appt=matchviewtwith|App(f,l)->beginmatchviewfwith|AppBuiltin(b,l')->app_builtinb~ty:(ty_exnt)(l'@l),[]|_->f,lend|AppBuiltin(b,l)when(not(Builtin.is_quantifierb))->letty_args,args=CCList.partitionis_a_typelinletty=arrow(List.mapty_exnargs)(ty_exnt)inapp_builtin~tybty_args,args|_->t,[]let[@inline]as_vart=matchviewtwithVarv->Somev|_->Nonelet[@inline]as_var_exnt=matchviewtwithVarv->v|_->invalid_arg"as_var_exn"letas_constt=matchviewtwithConstv->Somev|_->Noneletas_const_exnt=matchviewtwithConstv->v|_->invalid_arg"as_const_exn"let[@inline]as_bvar_exnt=matchviewtwithDBi->i|_->invalid_arg"as_bvar_exn"let[@inline]is_bvar_iit=matchviewtwithDBj->i=j|_->false(** {3 IO} *)letprint_hashconsing_ids=reffalseletprint_all_types=reffalsetypeprint_hook=int->(CCFormat.t->t->unit)->CCFormat.t->t->boollet_hooks=ref[]letadd_default_hookh=_hooks:=h::!_hooksletdefault_hooks()=!_hooksletneeds_args(t:t):bool=matchviewtwith|AppBuiltin(Builtin.Arrow,_)->true|Bind(Binder.ForallTy,_,_)->true|_->falseletshow_type_arguments=reffalseletrecopen_bind2bt1t2=matchviewt1,viewt2with|Bind(b1',ty1,t1'),Bind(b2',ty2,t2')whenb=b1'&&b=b2'->letargs1,ret1,args2,ret2=open_bind2bt1't2'inty1::args1,ret1,ty2::args2,ret2|_->[],t1,[],t2letrecpp_depth?(hooks=[])depthoutt=letrec_ppdepthoutt=ifList.exists(funh->hdepth(_ppdepth)outt)hooksthen()(* hook took control *)else(_pp_rootdepthoutt;if!print_hashconsing_idsthen(Format.fprintfout"/%d"t.id);)and_pp_rootdepthoutt=matchviewtwith|Varv->pp_varoutv;if!print_all_typesthen(Format.fprintfout":%a"(_pp_surroundeddepth)(ty_exnt));|DBi->Format.fprintfout"Y%d"(depth-i-1);if!print_all_typesthen(Format.fprintfout":%a"(_pp_surroundeddepth)(ty_exnt));|Consts->beginmatchID.as_prefixswith|Somes->CCFormat.stringouts|None->ID.ppoutsend;|Bind(b,_,_)->(* unfold *)letvarty_l,t'=open_bindbtinletpp_tyvarout(i,varty)=Format.fprintfout"(@[Y%d:@[%a@])@]"(depth+i)(_ppdepth)vartyinFormat.fprintfout"@[<1>%a@ @[%a@].@ %a@]"Binder.ppb(Util.pp_iter~sep:" "pp_tyvar)(Iter.of_array_i(Array.of_listvarty_l))(_pp_surrounded(depth+List.lengthvarty_l))t'|AppBuiltin(Builtin.Arrow,([]|[_]))->assertfalse|AppBuiltin(Builtin.Arrow,ret::args)->Format.fprintfout"@[%a@ → %a@]"(Util.pp_list~sep:" → "(_pp_surroundeddepth))args(_pp_surroundeddepth)ret|AppBuiltin((Builtin.ExistsConst|Builtin.ForallConst)asb,[x;body])->Format.fprintfout"%a %a. %a"Builtin.ppb(_ppdepth)x(_ppdepth)body;|AppBuiltin((Builtin.Eq|Builtin.Neq)asb,x::rest)->letsep,l=ifis_a_typexthen(CCFormat.sprintf"(%a::%a) "Builtin.ppb(_ppdepth)x,rest)else(CCFormat.sprintf"%a "Builtin.ppb,x::rest)inifCCList.lengthl=1thenFormat.fprintfout"(%a @[%a@])"Builtin.ppb(_ppdepth)(List.hdl)elseFormat.fprintfout" @[%a@]"(Util.pp_list~sep(_ppdepth))l|AppBuiltin(b,([_;a]|[a]))whenBuiltin.is_prefixb->Format.fprintfout"@[<1>%a %a@]"Builtin.ppb(_ppdepth)a|AppBuiltin(b,[t1;t2])whenBuiltin.is_infixb->Format.fprintfout"(@[%a %s@ %a@])"(_ppdepth)t1(Builtin.to_stringb)(_ppdepth)t2|AppBuiltin(b,[_ty;t1;t2])whenBuiltin.is_infixb&&is_tType(ty_exn_ty)->(* always drop the type argument, it's always inferrable for builtins *)Format.fprintfout"(@[%a %s@ %a@])"(_ppdepth)t1(Builtin.to_stringb)(_ppdepth)t2|AppBuiltin(b,l)whenBuiltin.is_infixb&&List.lengthl>=2->letsep=CCFormat.sprintf" %s "(Builtin.to_stringb)inFormat.fprintfout"(@[%a@])"(Util.pp_list~sep(_ppdepth))l|AppBuiltin(b,[])->Builtin.ppoutb|AppBuiltin(b,l)->letl=ifBuiltin.is_combinatorb&¬!show_type_argumentsthenList.filter(funt->not(is_tType@@ty_exnt))lelselinifCCList.is_emptylthenFormat.fprintfout"@[%a@]"Builtin.ppbelseFormat.fprintfout"@[%a(%a)@]"Builtin.ppb(Util.pp_list(_ppdepth))l|App(f,l)->(* remove type arguments unless required,
or unless we are already printing a type *)letl=if!show_type_arguments||is_tType(ty_exnt)thenlelseList.filter(funt->not(is_tType@@ty_exnt))linletas_infix=matchviewfwithConstid->ID.as_infixid|_->Noneinletas_prefix=matchviewfwithConstid->ID.as_prefixid|_->Noneinbeginmatchas_infix,as_prefix,lwith|_,_,[]->_ppdepthoutf|Somes,_,[a;b]->Format.fprintfout"@[<1>%a@ %s@ %a@]"(_pp_surroundeddepth)as(_pp_surroundeddepth)b|_,Somes,[a]->Format.fprintfout"@[<1>%s@ %a@]"s(_pp_surroundeddepth)a|_->Format.fprintfout"@[<1>%a@ %a@]"(_pp_surroundeddepth)f(Util.pp_list~sep:" "(_pp_surroundeddepth))lendand_pp_surroundeddepthoutt=matchviewtwith|App(_,l)whennot!show_type_arguments&¬(is_tType(ty_exnt))&&List.for_all(funt->is_tType(ty_exnt))l->_ppdepthoutt|Bind_|AppBuiltin(_,_::_)|App(_,_::_)->Format.fprintfout"(@[%a@])"(_ppdepth)t|_->_ppdepthouttin_ppdepthouttandpp_varoutv=letty=HVar.tyvinbeginmatchviewtywith|AppBuiltin(Builtin.TType,[])->Format.fprintfout"A%d"(HVar.idv)|AppBuiltin(Builtin.TyInt,[])->Format.fprintfout"I%d"(HVar.idv)|AppBuiltin(Builtin.TyRat,[])->Format.fprintfout"Q%d"(HVar.idv)|AppBuiltin(Builtin.Prop,[])->Format.fprintfout"P%d"(HVar.idv)|_whenneeds_argsty->Format.fprintfout"F%d"(HVar.idv)|_->HVar.ppoutvendletppoutt=pp_depth~hooks:!_hooks0outtletto_stringt=CCFormat.to_stringpptletrecpp_zfoutt=letrecpp_depthoutt=matchviewtwith|Varv->pp_var_zfoutv|DBi->Format.fprintfout"Y%d"(depth-i-1)|Consts->ID.pp_zfouts|Bind(b,_,_)->(* unfold *)letvarty_l,t'=open_bindbtinletpp_tyvarout(i,varty)=Format.fprintfout"(@[Y%d:@[%a@])@]"(depth+i)(pp_depth)vartyinFormat.fprintfout"@[<1>%a@ @[%a@].@ %a@]"Binder.ZF.ppb(Util.pp_iter~sep:" "pp_tyvar)(Iter.of_array_i(Array.of_listvarty_l))(_pp_surrounded(depth+List.lengthvarty_l))t'|AppBuiltin(Builtin.Arrow,([]|[_]))->assertfalse|AppBuiltin(Builtin.Arrow,ret::args)->Format.fprintfout"@[%a@ -> %a@]"(Util.pp_list~sep:" -> "(_pp_surroundeddepth))args(_pp_surroundeddepth)ret|AppBuiltin(b,[x;body])whenBuiltin.equalbBuiltin.ExistsConst||Builtin.equalbBuiltin.ForallConst->Format.printf"%a %a. %a"Builtin.ppbpp_zfxpp_zfbody;|AppBuiltin(b,([_;a]|[a]))whenBuiltin.is_prefixb->Format.fprintfout"@[<1>%a %a@]"Builtin.ZF.ppb(pp_depth)a|AppBuiltin(b,[t1;t2])whenBuiltin.is_infixb->Format.fprintfout"(@[%a %a@ %a@])"(pp_depth)t1Builtin.ZF.ppb(pp_depth)t2|AppBuiltin(b,[_ty;t1;t2])whenBuiltin.is_infixb&&is_tType(ty_exn_ty)->(* always drop the type argument, it's always inferrable for builtins *)Format.fprintfout"(@[%a %a@ %a@])"(pp_depth)t1Builtin.ZF.ppb(pp_depth)t2|AppBuiltin(b,l)whenList.lengthl>=2&&Builtin.is_infixb->letsep=CCFormat.sprintf" %s "(Builtin.to_stringb)inFormat.fprintfout"(@[%a@])"(Util.pp_list~seppp_zf)l|AppBuiltin(b,[])->Builtin.ZF.ppoutb|AppBuiltin(b,l)->Format.fprintfout"@[%a(%a)@]"Builtin.ZF.ppb(Util.pp_list(pp_depth))l|App(f,l)->beginmatchlwith|[]->pp_depthoutf|_::_->Format.fprintfout"@[<1>%a@ %a@]"(_pp_surroundeddepth)f(Util.pp_list~sep:" "(_pp_surroundeddepth))lendand_pp_surroundeddepthoutt=matchviewtwith|Bind_|AppBuiltin(_,_::_)|App(_,_::_)->Format.fprintfout"(@[%a@])"(pp_depth)t|_->pp_depthouttinpp_0outtandpp_var_zfoutv=letty=HVar.tyvinbeginmatchviewtywith|AppBuiltin(Builtin.TType,[])->Format.fprintfout"A%d"(HVar.idv)|AppBuiltin(Builtin.TyInt,[])->Format.fprintfout"I%d"(HVar.idv)|AppBuiltin(Builtin.TyRat,[])->Format.fprintfout"Q%d"(HVar.idv)|AppBuiltin(Builtin.Prop,[])->Format.fprintfout"P%d"(HVar.idv)|_whenneeds_argsty->Format.fprintfout"F%d"(HVar.idv)|_->HVar.ppoutvendletpp_in=function|Output_format.O_zf->pp_zf|Output_format.O_tptp->assertfalse|Output_format.O_normal->pp|Output_format.O_none->CCFormat.silent