123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406open!ImportopenStd_internal(* the module [T] serves to enforce the invariant that all Blang.t values are in a
normal form whereby boolean constants True and False only appear as the topmost
constructor -- in any other position they are simplified away using laws of
boolean algebra.
Note: this file deviates from the usual pattern of modules with Stable interfaces in
that the Stable sub-module is not the first thing to be defined in the module. The
reason for this deviation is so that one can convince oneself of the aforementioned
invariant after reading only this small amount of code. After defining T we then
immediately define its Stable interface.
*)moduleT:sigtype'at=private|True|False|Andof'at*'at|Orof'at*'at|Notof'at|Ifof'at*'at*'at|Baseof'a[@@derivingbin_io,compare,hash]valinvariant:'at->unitvaltrue_:'atvalfalse_:'atvalnot_:'at->'atvalandalso:'at->'at->'atvalorelse:'at->'at->'atvalif_:'at->'at->'at->'atvalbase:'a->'atend=structtype'at=|True|False|Andof'at*'at|Orof'at*'at|Notof'at|Ifof'at*'at*'at|Baseof'a[@@derivingbin_io,compare,hash]letinvariant=letsubterms=function|True|False|Base_->[]|Nott1->[t1]|And(t1,t2)|Or(t1,t2)->[t1;t2]|If(t1,t2,t3)->[t1;t2;t3]inletreccontains_no_constants=function|True|False->assertfalse|t->List.iter~f:contains_no_constants(subtermst)infunt->List.iter~f:contains_no_constants(subtermst);;lettrue_=Trueletfalse_=Falseletbasev=Basevletnot_=function|True->False|False->True|Nott->t|t->Nott;;letandalsot1t2=matcht1,t2with|_,False|False,_->False|other,True|True,other->other|_->And(t1,t2);;letorelset1t2=matcht1,t2with|_,True|True,_->True|other,False|False,other->other|_->Or(t1,t2);;letif_abc=matchawith|True->b|False->c|_->(matchb,cwith|True,_->orelseac|_,False->andalsoab|_,True->orelse(not_a)b|False,_->andalso(not_a)c|_->If(a,b,c));;endincludeTmoduleStable=structmoduleV1:sig(* THIS TYPE AND ITS SERIALIZATIONS SHOULD NEVER BE CHANGED - PLEASE SPEAK WITH
ANOTHER DEVELOPER IF YOU NEED MORE DETAIL *)type'at='aT.t=private|True|False|Andof'at*'at|Orof'at*'at|Notof'at|Ifof'at*'at*'at|Baseof'a[@@derivingbin_io,compare,hash,sexp](* the remainder of this signature consists of functions used in the definitions
of sexp conversions that are also useful more generally *)valand_:'atlist->'atvalor_:'atlist->'atvalgather_conjuncts:'at->'atlistvalgather_disjuncts:'at->'atlistend=structtype'at='aT.t=private|True|False|Andof'at*'at|Orof'at*'at|Notof'at|Ifof'at*'at*'at|Baseof'ainclude(T:sigtype'at[@@derivingbin_io,compare,hash]endwithtype'at:='at)typesexp=Sexp.t=|Atomofstring|Listofsexplist(* cheap import *)(* flatten out nested and's *)letgather_conjunctst=letrecloopacc=function|True::ts->loopaccts|And(t1,t2)::ts->loopacc(t1::t2::ts)|t::ts->loop(t::acc)ts|[]->List.revaccinloop[][t];;(* flatten out nested or's *)letgather_disjunctst=letrecloopacc=function|False::ts->loopaccts|Or(t1,t2)::ts->loopacc(t1::t2::ts)|t::ts->loop(t::acc)ts|[]->List.revaccinloop[][t];;letand_ts=letrecloopacc=function|[]->acc|False::_->false_(* short circuit evaluation *)|t::ts->loop(andalsoacct)tsinlooptrue_ts;;letor_ts=letrecloopacc=function|[]->acc|True::_->true_(* short circuit evaluation *)|t::ts->loop(orelseacct)tsinloopfalse_ts;;letunarynameargssexp=matchargswith|[x]->x|_->letn=List.lengthargsinof_sexp_error(sprintf"%s expects one argument, %d found"namen)sexp;;letternarynameargssexp=matchargswith|[x;y;z]->x,y,z|_->letn=List.lengthargsinof_sexp_error(sprintf"%s expects three arguments, %d found"namen)sexp;;letsexp_of_tsexp_of_valuet=letrecauxt=matchtwith|Basex->sexp_of_valuex|True->Atom"true"|False->Atom"false"|Nott->List[Atom"not";auxt]|If(t1,t2,t3)->List[Atom"if";auxt1;auxt2;auxt3]|And_ast->letts=gather_conjunctstinList(Atom"and"::List.map~f:auxts)|Or_ast->letts=gather_disjunctstinList(Atom"or"::List.map~f:auxts)inauxt;;lett_of_sexpbase_of_sexpsexp=letbasesexp=base(base_of_sexpsexp)inletrecauxsexp=matchsexpwith|Atomkw->(matchString.lowercasekwwith|"true"->true_|"false"->false_|_->basesexp)|List(Atomkw::args)->(matchString.lowercasekwwith|"and"->and_(List.map~f:auxargs)|"or"->or_(List.map~f:auxargs)|"not"->not_(aux(unary"not"argssexp))|"if"->letx,y,z=ternary"if"argssexpinif_(auxx)(auxy)(auxz)|_->basesexp)|_->basesexpinauxsexp;;endendinclude(Stable.V1:moduletypeofStable.V1withtype'at:='at)letconstantb=ifbthentrue_elsefalse_moduletypeConstructors=sigvalbase:'a->'atvaltrue_:_tvalfalse_:_tvalconstant:bool->_tvalnot_:'at->'atvaland_:'atlist->'atvalor_:'atlist->'atvalif_:'at->'at->'at->'atendmoduleO=structincludeTletnot=not_letand_=and_letor_=or_letconstant=constantlet(&&)=andalsolet(||)=orelselet(==>)ab=nota||bendletconstant_value=function|True->Sometrue|False->Somefalse|_->None;;(* [values t] lists the base predicates in [t] from left to right *)letvaluest=letrecloopacc=function|Basev::ts->loop(v::acc)ts|True::ts->loopaccts|False::ts->loopaccts|Nott1::ts->loopacc(t1::ts)|And(t1,t2)::ts->loopacc(t1::t2::ts)|Or(t1,t2)::ts->loopacc(t1::t2::ts)|If(t1,t2,t3)::ts->loopacc(t1::t2::t3::ts)|[]->List.revaccinloop[][t];;moduleC=Container.Make(structtype'at='aT.tletfoldt~init~f=letrecloopacctpending=matchtwith|Basea->next(facca)pending|True|False->nextaccpending|Nott->loopacctpending|And(t1,t2)|Or(t1,t2)->loopacct1(t2::pending)|If(t1,t2,t3)->loopacct1(t2::t3::pending)andnextacc=function|[]->acc|t::ts->loopaccttsinloopinitt[];;letiter=`Define_using_foldletlength=`Define_using_foldend)letcount=C.countletsum=C.sumletexists=C.existsletfind=C.findletfind_map=C.find_mapletfold=C.foldletfor_all=C.for_allletis_empty=C.is_emptyletiter=C.iterletlength=C.lengthletmem=C.memletto_array=C.to_arrayletto_list=C.to_listletmin_elt=C.min_eltletmax_elt=C.max_eltletfold_result=C.fold_resultletfold_until=C.fold_untilincludeMonad.Make(structtype'at='aT.tletreturn=baseletrecbindt~f:k=matchtwith|Basev->kv|True->true_|False->false_|Nott1->not_(bindt1~f:k)(* Unfortunately we need to duplicate some of the short-circuiting from [andalso] and
friends here. In principle we could do something involving [Lazy.t] but the
overhead probably wouldn't be worth it. *)|And(t1,t2)->(matchbindt1~f:kwith|False->false_|other->andalsoother(bindt2~f:k))|Or(t1,t2)->(matchbindt1~f:kwith|True->true_|other->orelseother(bindt2~f:k))|If(t1,t2,t3)->(matchbindt1~f:kwith|True->bindt2~f:k|False->bindt3~f:k|other->if_other(bindt2~f:k)(bindt3~f:k));;letmap=`Define_using_bindend)(* semantics *)letevaltbase_eval=letreceval=function|True->true|False->false|And(t1,t2)->evalt1&&evalt2|Or(t1,t2)->evalt1||evalt2|Nott->not(evalt)|If(t1,t2,t3)->ifevalt1thenevalt2elseevalt3|Basex->base_evalxinevalt;;letspecializetf=bindt~f:(funv->matchfvwith|`Knownc->constantc|`Unknown->basev);;leteval_set~universe:allset_of_base=letrecaux(b:_t)=matchbwith|True->forceall|False->Set.Using_comparator.empty~comparator:(Set.comparator(forceall))|And(a,b)->Set.inter(auxa)(auxb)|Or(a,b)->Set.union(auxa)(auxb)|Nota->Set.diff(forceall)(auxa)|Basea->set_of_basea|If(cond,a,b)->letcond=auxcondinSet.union(Set.intercond(auxa))(Set.inter(Set.diff(forceall)cond)(auxb))inaux;;