123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515typeidentifier=AST.identifiermoduleISet=ASTUtils.ISetmoduleIMap=ASTUtils.IMapmoduleTimeFrame=structtypet=Constant|Config|Executionletequalt1t2=match(t1,t2)with|Constant,Constant|Config,Config|Execution,Execution->true|Constant,(Config|Execution)|Config,(Constant|Execution)|Execution,(Config|Constant)->falseletis_beforet1t2=match(t1,t2)with|Constant,Constant|Config,Config|Execution,Execution->true|Config,Execution|Constant,(Config|Execution)->true|Execution,Config|(Config|Execution),Constant->falseletmaxt1t2=ifis_beforet1t2thent2elset1letof_ldk=letopenASTinfunctionLDK_Constant->Constant|LDK_Let|LDK_Var->Executionletof_gdk=letopenASTinfunction|GDK_Constant->Constant|GDK_Config->Config|GDK_Let|GDK_Var->Executionendtyperead={name:identifier;time_frame:TimeFrame.t;immutable:bool}typet=|ReadsLocalofread|WritesLocalofidentifier|ReadsGlobalofread|WritesGlobalofidentifier|ThrowsExceptionofidentifier|CallsRecursiveofidentifier|PerformsAssertions|NonDeterministictypeside_effect=tletequal(t1:t)(t2:t):bool=match(t1,t2)with|ReadsLocal{name=s1},ReadsLocal{name=s2}|WritesLocals1,WritesLocals2|ReadsGlobal{name=s1},ReadsGlobal{name=s2}|WritesGlobals1,WritesGlobals2|ThrowsExceptions1,ThrowsExceptions2|CallsRecursives1,CallsRecursives2->String.equals1s2|PerformsAssertions,PerformsAssertions|NonDeterministic,NonDeterministic->true|(ReadsLocal_,(WritesLocal_|ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|(WritesLocal_,(ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|(ReadsGlobal_,(WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|(WritesGlobal_,(ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|ThrowsException_,(CallsRecursive_|PerformsAssertions|NonDeterministic)|CallsRecursive_,(PerformsAssertions|NonDeterministic)|PerformsAssertions,NonDeterministic|((WritesLocal_|ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),ReadsLocal_)|((ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),WritesLocal_)|((WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),ReadsGlobal_)|((ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),WritesGlobal_)|((CallsRecursive_|PerformsAssertions|NonDeterministic),ThrowsException_)|(PerformsAssertions|NonDeterministic),CallsRecursive_|NonDeterministic,PerformsAssertions->falseletcompare(t1:t)(t2:t):int=match(t1,t2)with|ReadsLocal{name=s1},ReadsLocal{name=s2}|WritesLocals1,WritesLocals2|ReadsGlobal{name=s1},ReadsGlobal{name=s2}|WritesGlobals1,WritesGlobals2|ThrowsExceptions1,ThrowsExceptions2|CallsRecursives1,CallsRecursives2->String.compares1s2|PerformsAssertions,PerformsAssertions|NonDeterministic,NonDeterministic->0|(ReadsLocal_,(WritesLocal_|ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|(WritesLocal_,(ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|(ReadsGlobal_,(WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|(WritesGlobal_,(ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic))|ThrowsException_,(CallsRecursive_|PerformsAssertions|NonDeterministic)|CallsRecursive_,(PerformsAssertions|NonDeterministic)|PerformsAssertions,NonDeterministic->1|((WritesLocal_|ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),ReadsLocal_)|((ReadsGlobal_|WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),WritesLocal_)|((WritesGlobal_|ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),ReadsGlobal_)|((ThrowsException_|CallsRecursive_|PerformsAssertions|NonDeterministic),WritesGlobal_)|((CallsRecursive_|PerformsAssertions|NonDeterministic),ThrowsException_)|(PerformsAssertions|NonDeterministic),CallsRecursive_|NonDeterministic,PerformsAssertions->-1letpp_printf=letopenFormatinfunction|ReadsLocal{name=s}->fprintff"ReadsLocal %S"s|WritesLocals->fprintff"WritesLocal %S"s|ReadsGlobal{name=s}->fprintff"ReadsGlobal %S"s|WritesGlobals->fprintff"WritesGlobal %S"s|ThrowsExceptions->fprintff"ThrowsException %S"s|CallsRecursives->fprintff"CallsRecursive %S"s|PerformsAssertions->fprintff"PerformsAssertions"|NonDeterministic->fprintff"NonDeterministic"lettime_frame=function|ReadsLocal{time_frame}|ReadsGlobal{time_frame}->time_frame|WritesLocal_|WritesGlobal_|NonDeterministic|CallsRecursive_|ThrowsException_->TimeFrame.Execution|PerformsAssertions->TimeFrame.Constantletis_pure=function|ReadsLocal_|ReadsGlobal_|NonDeterministic|PerformsAssertions->true|WritesLocal_|WritesGlobal_|CallsRecursive_|ThrowsException_->false(* Begin IsSymbolicallyEvaluable *)letis_symbolically_evaluable=function|ReadsLocal{immutable}|ReadsGlobal{immutable}->immutable|WritesLocal_|WritesGlobal_|NonDeterministic|CallsRecursive_|ThrowsException_|PerformsAssertions->false(* End *)(* SES = Side Effect Set *)moduleSES=struct(* This module uses an abstraction over a set of side-effects. *)typet={(* Decomposition into subsets *)local_reads:ISet.t;(* Only store reads to mutable variables *)local_writes:ISet.t;global_reads:ISet.t;(* Only store reads to mutable variables *)global_writes:ISet.t;thrown_exceptions:ISet.t;calls_recursives:ISet.t;assertions_performed:bool;non_determinism:bool;(* Invariants kept *)max_local_read_time_frame:TimeFrame.t*identifier;max_global_read_time_frame:TimeFrame.t*identifier;}letempty={local_reads=ISet.empty;local_writes=ISet.empty;global_reads=ISet.empty;global_writes=ISet.empty;thrown_exceptions=ISet.empty;calls_recursives=ISet.empty;assertions_performed=false;non_determinism=false;max_local_read_time_frame=(TimeFrame.Constant,"1");max_global_read_time_frame=(TimeFrame.Constant,"1");}letwitnessed_time_frame_max((t1,_w1)astw1)((t2,_w2)astw2)=ifTimeFrame.is_beforet1t2thentw2elsetw1letmax_time_frameses=ifISet.is_emptyses.local_writes&&ISet.is_emptyses.global_writes&&ISet.is_emptyses.thrown_exceptions&&ISet.is_emptyses.calls_recursives&¬ses.non_determinismthenTimeFrame.max(fstses.max_global_read_time_frame)(fstses.max_local_read_time_frame)elseTimeFrame.Executionletis_pureses=ISet.is_emptyses.local_writes&&ISet.is_emptyses.global_writes&&ISet.is_emptyses.thrown_exceptions&&ISet.is_emptyses.calls_recursivesletall_reads_are_immutableses=ISet.is_emptyses.local_reads&&ISet.is_emptyses.global_reads(* Begin SESIsSymbolicallyEvaluable *)letis_symbolically_evaluableses=is_pureses&&(notses.non_determinism)&&(notses.assertions_performed)&&all_reads_are_immutableses(* End *)(* Begin SESIsDeterministic *)letis_deterministicses=notses.non_determinism(* End *)letadd_local_readstime_frameimmutableses=letlocal_reads=ifimmutablethenses.local_readselseISet.addsses.local_readsandmax_local_read_time_frame=witnessed_time_frame_max(time_frame,s)ses.max_local_read_time_framein{seswithlocal_reads;max_local_read_time_frame}letadd_local_writesses={seswithlocal_writes=ISet.addsses.local_writes}letadd_global_readstime_frameimmutableses=letglobal_reads=ifimmutablethenses.global_readselseISet.addsses.global_readsandmax_global_read_time_frame=witnessed_time_frame_max(time_frame,s)ses.max_global_read_time_framein{seswithglobal_reads;max_global_read_time_frame}letadd_global_writesses={seswithglobal_writes=ISet.addsses.global_writes}letadd_thrown_exceptionsses={seswiththrown_exceptions=ISet.addsses.thrown_exceptions}letadd_calls_recursivesses={seswithcalls_recursives=ISet.addsses.calls_recursives}letadd_assertionses={seswithassertions_performed=true}letadd_non_determinismses={seswithnon_determinism=true}letadd_side_effectseses=matchsewith|ReadsLocal{name;time_frame;immutable}->add_local_readnametime_frameimmutableses|ReadsGlobal{name;time_frame;immutable}->add_global_readnametime_frameimmutableses|WritesLocals->add_local_writesses|WritesGlobals->add_global_writesses|ThrowsExceptions->add_thrown_exceptionsses|CallsRecursives->add_calls_recursivesses|PerformsAssertions->add_assertionses|NonDeterministic->add_non_determinismses(* Constructors *)letreads_localstimmutable=add_local_readstimmutableemptyletwrites_locals=add_local_writesemptyletreads_globalstimmutable=add_global_readstimmutableemptyletwrites_globals=add_global_writesemptyletthrows_exceptions=add_thrown_exceptionsemptyletcalls_recursives=add_calls_recursivesemptyletperforms_assertions=add_assertionemptyletnon_deterministic=add_non_determinismemptyletequalses1ses2=ses1==ses2||ISet.equalses1.calls_recursivesses2.calls_recursives&&ISet.equalses1.global_readsses2.global_reads&&ISet.equalses1.global_writesses2.global_writes&&ISet.equalses1.local_readsses2.local_reads&&ISet.equalses1.local_writesses2.local_writes&&ISet.equalses1.thrown_exceptionsses2.thrown_exceptions&&Bool.equalses1.non_determinismses2.non_determinism&&Bool.equalses1.assertions_performedses2.assertions_performed&&TimeFrame.equal(fstses1.max_global_read_time_frame)(fstses2.max_global_read_time_frame)&&TimeFrame.equal(fstses1.max_global_read_time_frame)(fstses2.max_global_read_time_frame)letunionses1ses2=ifses1==emptythenses2elseifses2==emptythenses1else{local_reads=ISet.unionses1.local_readsses2.local_reads;local_writes=ISet.unionses1.local_writesses2.local_writes;global_reads=ISet.unionses1.global_readsses2.global_reads;global_writes=ISet.unionses1.global_writesses2.global_writes;thrown_exceptions=ISet.unionses1.thrown_exceptionsses2.thrown_exceptions;calls_recursives=ISet.unionses1.calls_recursivesses2.calls_recursives;assertions_performed=ses1.assertions_performed||ses2.assertions_performed;non_determinism=ses1.non_determinism||ses2.non_determinism;max_local_read_time_frame=witnessed_time_frame_maxses1.max_local_read_time_frameses2.max_local_read_time_frame;max_global_read_time_frame=witnessed_time_frame_maxses1.max_global_read_time_frameses2.max_global_read_time_frame;}(* Properties *)letis_side_effect_freeses=is_pureses&¬ses.assertions_performedletis_side_effect_free_without_global_readsses=is_side_effect_freeses&&ISet.is_emptyses.global_readsletare_non_conflictingses1ses2=ifnot(ISet.is_emptyses1.calls_recursives)thenis_side_effect_free_without_global_readsses2elseifnot(ISet.is_emptyses2.calls_recursives)thenis_side_effect_free_without_global_readsses1elseifnot(ISet.is_emptyses1.thrown_exceptions)thenis_side_effect_freeses2elseifnot(ISet.is_emptyses2.thrown_exceptions)thenis_side_effect_freeses1elseISet.disjointses1.global_writesses2.global_writes&&ISet.disjointses1.global_writesses2.global_reads&&ISet.disjointses1.global_readsses2.global_writes&&ISet.disjointses1.local_writesses2.local_writes&&ISet.disjointses1.local_writesses2.local_reads&&ISet.disjointses1.local_readsses2.local_writesletchoose_side_effectses=ifnot(ISet.is_emptyses.global_writes)thenWritesGlobal(ISet.chooseses.global_writes)elseifnot(ISet.is_emptyses.local_writes)thenWritesLocal(ISet.chooseses.local_writes)elseifnot(ISet.is_emptyses.thrown_exceptions)thenThrowsException(ISet.chooseses.thrown_exceptions)elseifnot(ISet.is_emptyses.calls_recursives)thenCallsRecursive(ISet.chooseses.calls_recursives)elseifses.assertions_performedthenPerformsAssertionselseraiseNot_foundletmake_readsname={name;time_frame=TimeFrame.Execution;immutable=false}letmake_reads_localname=ReadsLocal(make_readsname)letmake_reads_globalname=ReadsGlobal(make_readsname)letchoose_side_effect_with_readsses=trychoose_side_effectseswithNot_found->ifnot(ISet.is_emptyses.global_reads)thenletname=ISet.chooseses.global_readsinmake_reads_globalnameelseifnot(ISet.is_emptyses.local_reads)thenletname=ISet.chooseses.local_readsinmake_reads_globalnameelseraiseNot_foundletremove_pureses={seswithglobal_reads=ISet.empty;local_reads=ISet.empty}letchoose_inters1s2=ISet.inters1s2|>ISet.chooseletchoose_conflicting_side_effectsses1ses2=ifnot(ISet.is_emptyses1.thrown_exceptions)then(ThrowsException(ISet.chooseses1.thrown_exceptions),choose_side_effectses2)elseifnot(ISet.is_emptyses2.thrown_exceptions)then(choose_side_effectses1,ThrowsException(ISet.chooseses2.thrown_exceptions))elseifnot(ISet.is_emptyses1.calls_recursives)then(CallsRecursive(ISet.chooseses1.calls_recursives),choose_side_effect_with_readsses2)elseifnot(ISet.is_emptyses2.calls_recursives)then(choose_side_effect_with_readsses1,CallsRecursive(ISet.chooseses2.calls_recursives))elseifnot(ISet.disjointses1.global_writesses2.global_writes)thenlets=choose_interses1.global_writesses2.global_writesin(WritesGlobals,WritesGlobals)elseifnot(ISet.disjointses1.global_writesses2.global_reads)thenletname=choose_interses1.global_writesses2.global_readsin(WritesGlobalname,make_reads_globalname)elseifnot(ISet.disjointses1.global_readsses2.global_writes)thenletname=choose_interses1.global_readsses2.global_writesin(make_reads_globalname,WritesGlobalname)elseifnot(ISet.disjointses1.local_writesses2.local_writes)thenlets=choose_interses1.local_writesses2.local_writesin(WritesLocals,WritesLocals)elseifnot(ISet.disjointses1.local_writesses2.local_reads)thenletname=choose_interses1.local_writesses2.local_readsin(WritesLocalname,make_reads_localname)elseifnot(ISet.disjointses1.local_readsses2.local_writes)thenlets=choose_interses1.local_readsses2.local_writesin(make_reads_locals,WritesLocals)else(choose_side_effectses1,choose_side_effectses2)letnon_conflicting_union~failses1ses2=ifses1==emptythenses2elseifses2==emptythenses1elseifare_non_conflictingses1ses2thenunionses1ses2elsechoose_conflicting_side_effectsses1ses2|>failletiterated_unionunionempty=(* Dichotomic implementation of iterated union. *)(* [unions2 acc [l1; l2; ...; l2n]] is the list
[[union l1 l2; union l3 l4; ... union l2n-1 l2n]]. *)letrecunions2acc=function|[]->acc|[h]->h::acc|h1::h2::t->unions2(unionh1h2::acc)tin(* [unions li] calls [unions2] on [li] until it only has one element. *)letrecunions=function|[]->empty|[h]->h|li->unions2[]li|>unionsinunionsletunions=iterated_unionunionemptyletnon_conflicting_unions~fail=iterated_union(non_conflicting_union~fail)emptyletunion3ses1ses2ses3=unionses1(unionses2ses3)letget_calls_recursivesses=ses.calls_recursivesletremove_localsses={seswithlocal_reads=ISet.empty;local_writes=ISet.empty;max_local_read_time_frame=(TimeFrame.Constant,"1");}letremove_thrown_exceptionsses={seswiththrown_exceptions=ISet.empty}letremove_calls_recursivesses={seswithcalls_recursives=ISet.empty}letremove_assertionsses={seswithassertions_performed=false}letremove_non_determinismses={seswithnon_determinism=false}letfilter_thrown_exceptionsfses={seswiththrown_exceptions=ISet.filterfses.thrown_exceptions}letfilter_calls_recursivesfses={seswithcalls_recursives=ISet.filterfses.calls_recursives}moduleSESet=Set.Make(structtypet=side_effectletcompare=compareend)letto_side_effect_listses=letset_map_to_listfs=ISet.fold(funeltaccu->felt::accu)sinletadd_ifelttestaccu=iftestthenelt::accuelseaccuinletadd_from_tff(t,w)setaccu=ifTimeFrame.equaltTimeFrame.Constant||ISet.memwsetthenaccuelsefwt::accuin[]|>add_ifPerformsAssertionsses.assertions_performed|>add_ifNonDeterministicses.non_determinism|>add_from_tf(funnametime_frame->ReadsGlobal{name;time_frame;immutable=true})ses.max_global_read_time_frameses.global_reads|>add_from_tf(funnametime_frame->ReadsLocal{name;time_frame;immutable=true})ses.max_local_read_time_frameses.local_reads|>set_map_to_list(funs->CallsRecursives)ses.calls_recursives|>set_map_to_list(funs->ThrowsExceptions)ses.thrown_exceptions|>set_map_to_list(funs->WritesGlobals)ses.global_writes|>set_map_to_listmake_reads_globalses.global_reads|>set_map_to_list(funs->WritesLocals)ses.local_writes|>set_map_to_listmake_reads_localses.local_readsletto_side_effect_setses=to_side_effect_listses|>SESet.of_listletpp_printfses=letelements=to_side_effect_listsesinletopenFormatinletpp_sepf()=fprintff",@ "infprintff"@[[%a]@]"(pp_print_list~pp_seppp_print)elementsend