123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604openFmttypelocation={start:Lexing.position;stop:Lexing.position}typeterm_kind=Check|Pre|Post|XPosttypeerror=|Violated_axiom|Axiom_failureof{exn:exn}|Violated_invariantof{term:string;position:term_kind}|Violated_conditionof{term:string;term_kind:term_kind}|Specification_failureof{term:string;term_kind:term_kind;exn:exn}|Unexpected_exceptionof{allowed_exn:stringlist;exn:exn}|Uncaught_checksof{term:string}|Unexpected_checksof{terms:stringlist}letstyled_listlpp=List.fold_left(funaccx->styledxacc)pplletquotedppppf=pfppf"`%a'"ppletpp_term_kind=using(function|Check->"`checks' pre-condition"|Pre->"pre-condition"|Post->"post-condition"|XPost->"exceptional post-condition")(styled`Yellowstring)letpp_position=using(function|Pre|Check->"the pre-state"|Post->"the post-state"|XPost->"an exceptional post-state")(styled`Yellowstring)letpp_term=quoted(styled`Boldstring)letpp_terms=list~sep:(any"@\n")pp_termletpp_loc=letunstyledppfloc=pfppf"File \"%s\", line %d, characters %d-%d:"loc.start.pos_fnameloc.start.pos_lnum(loc.start.pos_cnum-loc.start.pos_bol)(loc.stop.pos_cnum-loc.start.pos_bol)instyled_list[`Underline;`Bold]unstyledletpp_fun_name=quoted(styled`Bluestring)letpp_quoted_exn=quoted(styled`Boldstring)letpp_exn=usingPrintexc.to_stringpp_quoted_exnletpp_allowed_exn=list~sep:commapp_quoted_exnletpp_errorppf=function|Violated_axiom->pfppf"the axiom was %a."(styled`Redstring)"violated"|Axiom_failure{exn}->pfppf"the evaluation of the axiom %a:@\n @[%a@]"(styled`Redstring)"raised an exception"pp_exnexn|Violated_invariant{term;position}->pfppf"the %a@\n @[%a@]@\nwas %a in %a."(styled`Yellowstring)"invariant"pp_termterm(styled`Redstring)"violated"pp_positionposition|Violated_condition{term;term_kind}->pfppf"the %a@\n @[%a@]@\nwas %a."pp_term_kindterm_kindpp_termterm(styled`Redstring)"violated"|Specification_failure{term;term_kind;exn}->pfppf"the evaluation of the %a@\n @[%a@]@\n%a:@\n @[%a@]"pp_term_kindterm_kindpp_termterm(styled`Redstring)"raised an exception"pp_exnexn|Unexpected_exception{allowed_exn;exn}->pfppf"it raised an %a:@\n\
\ @[%a@]@\n\
only the following exceptions were declared:@\n\
\ @[%a@]"(styled`Redstring)"unexpected exception"pp_exnexnpp_allowed_exnallowed_exn|Uncaught_checks{term}->pfppf"a %a in@\n\
\ @[%a@]@\n\
was not detected.@\n\
Function should have raised %a."(styled`Redstring)"`checks' precondition violation"pp_termtermpp_quoted_exn"Invalid_argument"|Unexpected_checks{terms}->pfppf"it %a@\n\
\ @[%a@]\n\
but none of the declared `checks' preconditions@\n\
\ @[%a@]\n\
were violated."(styled`Redstring)"raised exception"pp_quoted_exn"Invalid_argument"pp_termstermstypeerror_report={loc:location;fun_name:string;mutableerrors:errorlist;}letpp_error_reportppf{loc;fun_name;errors}=letpp_bulletppppf=pfppf"- @[%a@]"ppinpfppf"%a@\n%a in function %a@\n @[%a@]"pp_locloc(styled_list[`Bold;`Red]string)"Runtime error"pp_fun_namefun_name(list~sep:(any"@\n")(pp_bulletpp_error))errorsexceptionErroroferror_reportmoduleErrors=structtypet=error_reportletcreatelocfun_name={loc;fun_name;errors=[]}letregisterte=t.errors<-e::t.errorsletreportt=matcht.errorswith|[]->()|_->pfstderr"%a@."pp_error_reportt;raise(Errort)endexceptionPartial_functionofexn*locationlet_=Printexc.register_printer(function(* When the exception arises in [next_state] called from [postcond], say, it
will be wrapped twice *)|Partial_function(Partial_function(e,l),_)|Partial_function(e,l)->Some(Printf.sprintf"Partial function in specification\n\
%s\n\
A partial function used in the specification was called out of \
its definition\n\
domain, raising the following exception:\n\
%s"(str"%a"pp_locl)(Printexc.to_stringe))|_->None)typeinteger=Z.tletstring_of_integer=Z.to_stringmoduleAux=structlettakenxs=letrecauxnaccxs=match(n,xs)with|_,[]|0,_->Stdlib.List.revacc|_,x::xs->aux(n-1)(x::acc)xsinifn<0theninvalid_arg"take"elseauxn[]xslettakenxs=take(Z.to_intn)xsletrecdropn=function|[]->[]|xswhenn<=0->xs|_::xs->drop(n-1)xsletdropnxs=drop(Z.to_intn)xsendletcopyx=letopenMarshalinfrom_string(to_stringx[])0moduleGospelstdlib=struct(** Implementation of the Gospel Stdlib
Note: [bag] and [set] are implemented as decreasing sorted lists where
each element appears at most once, using the polymorphic comparison.
For [bag]s, the list contains pairs, where [snd x] is the number of
occurrences of [fst x], with [snd x > 0].
Rationale: obviously, the time complexity of these implementations is not
ideal, but:
- it is a purely functional implementation (so it can be used with
QCheck-STM),
- it is compatible with the polymorphic equality: Ortac uses OCaml's [(=)]
to implement Gospel's [(=)], this ensures that [set]s and [bag]s can be
tested for equality in the generated code,
- they are sorted in decreasing order so that the resulting order
(according to the polymorphic comparison) on sets and bags is more
natural. *)type'asequence='alisttype'abag=('a*Z.t)listtype'aset='alistletsucc=Z.succletpred=Z.predlet(~-)=Z.(~-)let(+)=Z.(+)let(-)=Z.(-)let(*)=Z.(*)let(/)=Z.(/)let(mod)=Z.(mod)letpowxn=tryZ.powx(Z.to_intn)withZ.Overflow->invalid_arg"Exponent too big"letabs=Z.absletmin=Z.minletmax=Z.maxlet(>)=Z.gtlet(>=)=Z.geqlet(<)=Z.ltlet(<=)=Z.leqletlogand=Z.logandletlogor=Z.logorletlogxor=Z.logxorletlognot=Z.lognotletshift_leftvs=Z.shift_leftv(Z.to_ints)letshift_rightvs=Z.shift_rightv(Z.to_ints)letshift_right_truncvs=Z.shift_right_truncv(Z.to_ints)letinteger_of_int=Z.of_intletint_of_integer=Z.to_intletmax_int=Z.of_intmax_intletmin_int=Z.of_intmin_intletfst=fstletsnd=sndlet(~!)=(!)moduleList=structtype'at='alistletlengthl=List.lengthl|>Z.of_intlethd=List.hdlettl=List.tlletnthli=List.nthl(Z.to_inti)letnth_optli=trySome(nthli)with_->Noneletrev=List.revletinitif=leti=Z.to_intiinletfi=f(Z.of_inti)inList.initifletmap=List.mapletmapif=letfi=f(Z.of_inti)inList.mapifletfold_left=List.fold_leftletfold_right=List.fold_rightletmap2=List.map2letfor_all=List.for_alllet_exists=List.existsletfor_all2=List.for_all2let_exists2=List.exists2letmem=List.memletto_seq=Fun.idletof_seq=Fun.idendmoduleSequence=structtype'at='asequenceletlength=List.lengthletempty=[]letsingletonx=[x]letinit=List.initletconsxxs=x::xsletsnocxsx=xs@[x]lethd=List.hdlettl=List.tlletappend=Stdlib.List.appendletmemsx=List.memxs(* is that flip intentional? *)letmap=List.mapletfilter=Stdlib.List.filterletfilter_map=Stdlib.List.filter_mapletget=List.nthletsetxsnx=leterr()=failwith"index out of bounds"inletn=Z.to_intninletopenStdlibin(* to get standard (-) and (<) back *)letrecaux=function|[],0->[x]|_::xs,0->x::xs|[],_->err()|x::xs,n->x::aux(xs,n-1)inifn<0thenerr()elseaux(xs,n)letrev=List.revletfold_left=List.fold_leftletfold_right=List.fold_rightendlet(++)=Sequence.appendlet__mix_Bub=(* [_] *)Sequence.getlet__mix_Buddbxsb=(* [_..] *)Aux.dropbxslet__mix_Bddubxse=(* [.._] *)Aux.take(succe)xslet__mix_Buddubxsbe=(* [_.._] *)ife<bthen[]elseAux.take(succ(e-b))(Aux.dropbxs)moduleBagSet=structmoduletypeBagSetType=sigtype'aelem(** type of the list items in a ['a bag] or ['a set] *)valproj:'aelem->'a(** [proj x] is the projection of a list item into the actual value *)valplusone:'a->'aelemoption->'aelem(** [plusone x y]
Precondition: [y] is either [Some z] with [proj z = x] or [None] *)valminusone:'aelem->'aelemoptionvalof_list:'alist->'aelemlist(** ['a elem list] is really ['a set] or ['a bag] *)endmoduleMake(T:BagSetType)=structopenStdlib(* To recover standard operators, rather than Z ones *)(* [focus] and [unfocus] factor out much of the code of all the functions
doing a search for an element, following the standard principle of
zippers *)letfocusxxs=letrecauxl=function|[]->(l,None,[])|y::rasr'->leto=compare(T.projy)xinifo>0thenaux(y::l)relseifo=0then(l,Somey,r)else(* o < 0 *)(l,None,r')inaux[]xsletunfocus(l,m,r)=List.rev_appendl(matchmwithNone->r|Somex->x::r)letempty=[]letis_empty=function[]->true|_->falseletmemxb=matchfocusxbwith_,None,_->false|_,Some_,_->trueletaddxb=letl,y,r=focusxbinunfocus(l,Some(T.plusonexy),r)letsingletonx=[T.plusonexNone]letremovexb=matchfocusxbwith|l,Somey,r->unfocus(l,T.minusoney,r)|_,None,_->btypeside=Left|Righttype'aoneortwo=Oneof'a*side|Twoof'a*'aletcombinefxsys=letcsoptq=matchoptwithSomev->v::q|None->qinletrecauxxsys=match(xs,ys)with|[],_->List.filter_map(funy->f(One(y,Right)))ys|_,[]->List.filter_map(funx->f(One(x,Left)))xs|x::xs',y::ys'->leto=compare(T.projx)(T.projy)inifo>0(* x > y *)thencs(f(One(x,Left)))(auxxs'ys)elseifo=0(* x = y *)thencs(f(Two(x,y)))(auxxs'ys')else(* x < y *)cs(f(One(y,Right)))(auxxsys')inauxxsysletdisjointxsys=letjoin=functionTwo_->raiseExit|One_->Noneintryignore(combinejoinxsys);truewithExit->falseletchoose=function[]->invalid_arg"choose"|x::_->T.projxletchoose_opt=function[]->None|x::_->Some(T.projx)letof_list=T.of_listletto_listxs=List.mapT.projxsletto_seq=to_listletof_seq=of_listletmapfxs=of_list(List.map(funx->f(T.projx))xs)letfoldfbv=List.fold_left(funvx->f(T.projx)v)vbletfor_allpb=List.for_all(funx->p(T.projx))blet_existspb=List.exists(funx->p(T.projx))bletfilterpb=List.filter(funx->p(T.projx))bletfilter_mapfb=of_list(List.filter_map(funx->f(T.projx))b)letpartitionfb=List.partition(funx->f(T.projx))bletcomparexy=Z.of_int(comparexy)endendmoduleBag=structtype'at='abagmoduleBagType=structtype'aelem='a*Z.tletproj=fstletplusonex=function|None->(x,Z.one)|Some(y,o)->(y,Z.succo)letminusone=function|_,owhenZ.equaloZ.one->None|x,o->Some(x,Z.predo)letof_listxs=letrecrev_groupaccxo=function|[]->(x,o)::acc|y::ys->ifx=ythenrev_groupaccx(Z.succo)yselserev_group((x,o)::acc)yZ.oneysinmatchStdlib.List.fast_sortcomparexswith|[]->[]|x::xs->rev_group[]xZ.onexsendincludeBagSet.Make(BagType)letoccurrencesxb=matchfocusxbwith_,None,_->Z.zero|_,Some(_,o),_->oletunionb1b2=letjoin=function|One(x,_)->Somex|Two((x,ox),(_,oy))->Some(x,Z.maxoxoy)incombinejoinb1b2letsumb1b2=letjoin=function|One(x,_)->Somex|Two((x,ox),(_,oy))->Some(x,Z.addoxoy)incombinejoinb1b2letinterb1b2=letjoin=function|One(x,_)->Somex|Two((x,ox),(_,oy))->Some(x,Z.minoxoy)incombinejoinb1b2letdiffb1b2=letjoin=function|One(x,Left)->Somex|One(_,Right)->None|Two((x,xo),(_,yo))->ifZ.gtxoyothenSome(x,Z.subxoyo)elseNoneincombinejoinb1b2letsubsetb1b2=letjoin=function|One(_,Left)->raiseExit|Two((_,xo),(_,yo))->ifZ.gtxoyothenraiseExitelseNone|_->Noneintryignore(combinejoinb1b2);truewithExit->falseletcardinalb=List.fold_left(func(_,o)->Z.addco)Z.zerobendlet__mix_Cc=[]moduleSet=structtype'at='asetmoduleSetType=structtype'aelem='aletproj=Fun.idletplusonex=functionNone->x|Somey->y(* We should have x = y here, but we'd rather keep the value
already in the set *)letminusone_=Noneletof_listxs=letrev_comparexy=compareyxinStdlib.List.sort_uniqrev_comparexsendincludeBagSet.Make(SetType)letunions1s2=letjoin=functionOne(x,_)|Two(x,_)->Somexincombinejoins1s2letinters1s2=letjoin=functionOne_->None|Two(x,_)->Somexincombinejoins1s2letdiffs1s2=letjoin=functionOne(x,Left)->Somex|_->Noneincombinejoins1s2letsubsets1s2=letjoin=functionOne(_,Left)->raiseExit|_->Noneintryignore(combinejoins1s2);truewithExit->falseletcardinal=List.lengthendmoduleArray=structtype'at='aarrayletlengtharr=Array.lengtharr|>Z.of_intletgetarrz=ifZ.(z<zero||z>=of_int(Array.lengtharr))thenraise(Invalid_argument"Out of array bounds")elseArray.unsafe_getarr(Z.to_intz)letmakez=ifZ.(z>of_intSys.max_array_length)thenraise(Invalid_argument"Array length too big")elseArray.make(Z.to_intz)letinitnf=Array.init(Z.to_intn)(funi->f(Z.of_inti))letappend=Array.appendletconcat=Array.concatletsubxsij=Array.subxs(Z.to_inti)(Z.to_intj)letmap=Array.mapletmapifxs=Array.mapi(funix->f(Z.of_inti)x)xsletfold_left=Array.fold_leftletfold_right=Array.fold_rightletmap2=Array.map2letfor_all=Array.for_alllet_exists=Array.existsletfor_all2=Array.for_all2let_exists2=Array.exists2letmem=Array.memletto_list=Array.to_listletof_list=Array.of_listletto_seq=Array.to_listletof_seq=Array.of_listletto_baga=Bag.of_list(to_lista)letpermuta1a2=to_baga1=to_baga2letpermut_suba1a2lohi=letopenStdlibinletl=Array.lengtha1andlo=Z.to_intloandhi=Z.to_inthiinifl<>Array.lengtha2||lo<0||hi>l||hi<lotheninvalid_arg"permut_sub";tryfori=0tolo-1doifa1.(i)<>a2.(i)thenraiseExitdone;fori=hitol-1doifa1.(i)<>a2.(i)thenraiseExitdone;permut(Array.suba1lo(hi-lo+1))(Array.suba2lo(hi-lo+1))withExit->falseendlet__mix_Bmgbmxvy=ify=xthenvelsemymoduleMap=structendmoduleOrder=structletis_pre_order_=failwith"is_pre_order cannot be implemented as a test!"endmoduleSys=structletbig_endian=Sys.big_endianletint_size=Sys.int_sizeletmax_array_length=Sys.max_array_lengthletmax_string_length=Sys.max_string_lengthletword_size=Sys.word_sizeendendmoduleZ=structopenZletrecforallstartstopp=start>stop||(pstart&&forall(succstart)stopp)letrecexistsstartstopp=start<=stop&&(pstart||exists(succstart)stopp)end