123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776(* elpi: embedded lambda prolog interpreter *)(* license: GNU Lesser General Public License Version 2.1 or later *)(* ------------------------------------------------------------------------- *)moduletypeShow=sigtypetvalpp:Format.formatter->t->unitvalshow:t->stringendmoduletypeShowKey=sigtypekeyvalpp_key:Format.formatter->key->unitvalshow_key:key->stringendmoduletypeShow1=sigtype'atvalpp:(Format.formatter->'a->unit)->Format.formatter->'at->unitvalshow:(Format.formatter->'a->unit)->'at->stringendmoduletypeShow2=sigtype('a,'b)tvalpp:(Format.formatter->'a->unit)->(Format.formatter->'b->unit)->Format.formatter->('a,'b)t->unitvalshow:(Format.formatter->'a->unit)->(Format.formatter->'b->unit)->('a,'b)t->stringendmoduleMap=structmoduletypeS=sigincludeMap.SincludeShow1withtype'at:='atincludeShowKeywithtypekey:=keyendmoduletypeOrderedType=sigincludeMap.OrderedTypeincludeShowwithtypet:=tendmoduleMake(Ord:OrderedType)=structincludeMap.Make(Ord)letppffmtm=Format.fprintffmt"{{ @[<hov 2>";iter(funkv->Format.fprintffmt"%a ->@ %a;@ "Ord.ppkfv)m;Format.fprintffmt"@] }}"letshowfm=letb=Buffer.create20inletfmt=Format.formatter_of_bufferbinppffmtm;Format.fprintffmt"@?";Buffer.contentsbletpp_key=Ord.ppletshow_key=Ord.showendendmoduleSet=structmoduletypeS=sigincludeSet.SincludeShowwithtypet:=tendmoduletypeOrderedType=sigincludeSet.OrderedTypeincludeShowwithtypet:=tendmoduleMake(Ord:OrderedType)=structincludeSet.Make(Ord)letppfmtm=Format.fprintffmt"{{ @[<hov 2>";iter(funx->Format.fprintffmt"%a;@ "Ord.ppx)m;Format.fprintffmt"@] }}"letshowm=letb=Buffer.create20inletfmt=Format.formatter_of_bufferbinppfmtm;Format.fprintffmt"@?";Buffer.contentsbendendmoduleInt=structtypet=intletppfmtx=Format.pp_print_intfmtxletshowx=Format.asprintf"@[%a@]"ppxletcomparexy=x-yendmoduleBool=structtypet=boolletppfmtx=Format.pp_print_boolfmtxletshowx=Format.asprintf"@[%a@]"ppxletcompare=Bool.compareendmoduleString=structincludeStringletppfmts=Format.fprintffmt"%s"sletshowx=xendmoduleIntMap=Map.Make(Int)moduleStrMap=Map.Make(String)moduleIntSet=Set.Make(Int)moduleStrSet=Set.Make(String)moduleFmt=FormatmoduleDigest=structincludeDigestletshow=Digest.to_hexletppfmtd=Fmt.fprintffmt"%s"(showd)endmoduleHashtbl=structincludeHashtblletpppapbfmth=Format.fprintffmt"{{ @[<hov 2>";Hashtbl.iter(funkv->Format.fprintffmt"%a -> %a;@ "pakpbv)h;Format.fprintffmt"@] }}"letshowpapbh=letb=Buffer.create20inletfmt=Format.formatter_of_bufferbinpppapbfmth;Format.fprintffmt"@?";Buffer.contentsbendmoduleLoc=structtypet={client_payload:Obj.toption;source_name:string;source_start:int;source_stop:int;line:int;line_starts_at:int;}letto_string{source_name;source_start;source_stop;line;line_starts_at;}=letsource=ifsource_name=""then""else"File \""^source_name^"\", "inletchars=Printf.sprintf"characters %d-%d"source_startsource_stopinletpos=ifline=-1thencharselsePrintf.sprintf"line %d, column %d, %s"line(source_start-line_starts_at)charsinRe.(Str.global_replace(Str.regexp_string"\\")"/"source)^pos^":"letppfmtl=Fmt.fprintffmt"@[%s@]"(to_stringl)letshowl=to_stringl(* WARNING: loc comparison must be correct, otherwise two occurrences of
the samy symbol may be compiled to different constants (e.g. if the payload
is different) *)letcomparel1l2=letx=Stdlib.comparel1.source_startl2.source_startinifx=0thenStdlib.compare{l1withclient_payload=None}{l2withclient_payload=None}elsexletequall1l2={l1withclient_payload=None}={l2withclient_payload=None}letinitial?client_payloadsource_name={client_payload;source_name;source_start=0;source_stop=0;line=1;line_starts_at=0;}letis_initial{source_start;source_stop;line;line_starts_at}=source_start=0&&source_stop=0&&line=1&&line_starts_at=0letoption_appendo1o2=matcho1with|None->o2|Some_->o1letmerge?(merge_payload=option_append)lr={client_payload=merge_payloadl.client_payloadr.client_payload;source_name=l.source_name;source_start=l.source_start;source_stop=r.source_stop;line=r.line;line_starts_at=r.line_starts_at;}letmerge?merge_payloadlr=ifis_initiallthenrelseifis_initialrthenlelsemerge?merge_payloadlrletextendnl={lwithsource_start=l.source_start-n;source_stop=l.source_stop+n}endletpplist?(max=max_int)?(boxed=false)ppelem?(pplastelem=ppelem)sepfl=ifl<>[]thenbeginifboxedthenFmt.fprintff"@[<hov>";letargs,last=matchList.revlwith[]->assertfalse;|head::tail->List.revtail,headinList.iteri(funix->ifi=max+1thenFmt.fprintff"..."elseifi>maxthen()elseFmt.fprintff"%a%s@,"ppelemxsep)args;Fmt.fprintff"%a"pplastelemlast;ifboxedthenFmt.fprintff"@]"end;;letrecsmart_mapf=function[]->[]|(hd::tl)asl->lethd'=fhdinlettl'=smart_mapftlinifhd==hd'&&tl==tl'thenlelsehd'::tl';;letrecsmart_map2fx=function[]->[]|(hd::tl)asl->lethd'=fxhdinlettl'=smart_map2fxtlinifhd==hd'&&tl==tl'thenlelsehd'::tl';;letrecsmart_map3fxy=function[]->[]|(hd::tl)asl->lethd'=fxyhdinlettl'=smart_map3fxytlinifhd==hd'&&tl==tl'thenlelsehd'::tl';;letrecuniqq=function[]->[]|x::xswhenList.memqxxs->uniqqxs|x::xs->x::uniqqxs;;letrecfor_all3bpl1l2blb=match(l1,l2,bl)with|([],[],_)->true|([a1],[a2],[])->pa1a2b|([a1],[a2],b3::_)->pa1a2b3|(a1::l1,a2::l2,[])->pa1a2b&&for_all3bpl1l2blb|(a1::l1,a2::l2,b3::bl)->pa1a2b3&&for_all3bpl1l2blb|(_,_,_)->false;;moduletypeMode=sigtypet=Input|Output[@@derivingshow,ord]typeho=Fooft|Hooft*holistandhos=holist[@@derivingshow,ord]valget_head:ho->tvalto_ho:t->hovalshow_pretty:t->stringvalpretty:Fmt.formatter->t->unitendmoduleMode:Mode=structtypet=Input|Output[@@derivingshow,ord]typeho=|Fooft|Hooft*hosandhos=holist[@@derivingshow,ord]letget_head=functionFoa->a|Ho(a,_)->aletto_hox=Foxletshow_pretty=functionInput->"i"|Output->"o"letprettyfmtm=Format.fprintffmt"%s"(show_prettym)endletrecfor_all3b3~argsdepth(p:argsdepth:int->matching:bool->'a)x1x2x3l1l2blb=match(l1,l2,bl)with|([],[],_)->true|([a1],[a2],[])->p~argsdepthx1x2x3a1a2~matching:b|([a1],[a2],b3::_)->p~argsdepthx1x2x3a1a2~matching:(Mode.get_headb3==Input)|(a1::l1,a2::l2,[])->p~argsdepthx1x2x3a1a2~matching:b&&for_all3b3~argsdepthpx1x2x3l1l2blb|(a1::l1,a2::l2,b3::bl)->p~argsdepthx1x2x3a1a2~matching:(Mode.get_headb3==Input)&&for_all3b3~argsdepthpx1x2x3l1l2blb|(_,_,_)->false;;letrecfor_all2pl1l2=match(l1,l2)with|([],[])->true|([a1],[a2])->pa1a2|(a1::l1,a2::l2)->pa1a2&&for_all2pl1l2|(_,_)->false;;letrecfor_all23~argsdepth(p:argsdepth:int->matching:bool->'a)x1x2x3l1l2=match(l1,l2)with|([],[])->true|([a1],[a2])->p~argsdepthx1x2x3a1a2~matching:false|(a1::l1,a2::l2)->p~argsdepthx1x2x3a1a2~matching:false&&for_all23~argsdepthpx1x2x3l1l2|(_,_)->false;;letpp_loc_opt=function|None->""|Someloc->Loc.showloctypewarning_id=LinearVariable|UndeclaredGlobal|FlexClause|ImplicationPrecedenceletdefault_warn?loc~id:_s=Format.eprintf"@[<hv>Warning: %s@,%s@]\n%!"(pp_loc_optloc)sletdefault_error?locs=Format.eprintf"@[<hv>Fatal error: %s@,%s@]\n%!"(pp_loc_optloc)s;exit1letdefault_anomaly?locs=lettrace=matchPrintexc.(get_callstackmax_int|>backtrace_slots)with|None->""|Someslots->letlines=Array.mapiPrintexc.Slot.formatslotsinlet_,lines_repetitions=List.fold_left(fun(pos,acc)l->matchlwith|None->pos+1,acc|Some_whenpos=0->pos+1,acc|Somel->matchaccwith|(l1,q)::accwhenl=l1->pos+1,(l1,q+1)::acc|_->pos+1,(l,1)::acc)(0,[])(Array.to_listlines)inletlines=lines_repetitions|>List.map(function|(l,1)->l|(l,n)->l^Printf.sprintf" [%d times]"n)inString.concat"\n"linesinPrintf.eprintf"%s\nAnomaly: %s %s\n%!"trace(pp_loc_optloc)s;exit2letdefault_type_error?locs=default_error?locsletwarn_f=ref(Obj.reprdefault_warn)leterror_f=ref(Obj.reprdefault_error)letanomaly_f=ref(Obj.reprdefault_anomaly)lettype_error_f=ref(Obj.reprdefault_type_error)letstd_fmt=refFormat.std_formatterleterr_fmt=refFormat.err_formatterletset_formatters_maxcolsi=Format.pp_set_margin!std_fmti;Format.pp_set_margin!err_fmtiletset_formatters_maxboxi=Format.pp_set_max_boxes!std_fmti;Format.pp_set_max_boxes!err_fmtiletset_warnf=warn_f:=(Obj.reprf)letset_errorf=error_f:=(Obj.reprf)letset_anomalyf=anomaly_f:=(Obj.reprf)letset_type_errorf=type_error_f:=(Obj.reprf)letset_std_formatterf=std_fmt:=fletset_err_formatterf=err_fmt:=fletwarn?loc~ids:unit=Obj.obj!warn_f?loc~idsleterror?locs=Obj.obj!error_f?locsletanomaly?locs=Obj.obj!anomaly_f?locslettype_error?locs=Obj.obj!type_error_f?locsletprintfx=Format.fprintf!std_fmtxleteprintfx=Format.fprintf!err_fmtxletoption_get?err=function|Somex->x|None->matcherrwith|None->assertfalse|Somemsg->anomalymsgletoption_mapf=function|Somex->Some(fx)|None->Noneletoption_smart_mapf=function|Somexasorig->letx'=fxinifx'==xthenorigelseSomex'|None->Noneletoption_mapaccfacc=function|Somex->letacc,y=faccxinacc,Somey|None->acc,Noneletoption_iterf=functionNone->()|Somex->fxletoption_defaultd=functionNone->d|Somex->xmodulePair=structletpppoly_apoly_bfmtx=let(x0,x1)=xinFormat.pp_open_boxfmt1;Format.pp_print_stringfmt"(";Format.pp_open_boxfmt0;poly_afmtx0;Format.pp_close_boxfmt();Format.pp_print_stringfmt",";Format.pp_print_spacefmt();Format.pp_open_boxfmt0;poly_bfmtx1;Format.pp_close_boxfmt();Format.pp_print_stringfmt")";Format.pp_close_boxfmt()letshowpoly_apoly_bx=Format.asprintf"@[%a@]"(pppoly_apoly_b)xendletpp_optionffmt=functionNone->()|Somex->ffmtxletpp_int=Int.ppletpp_string=String.ppletpp_pair=Pair.ppletshow_pair=Pair.showletremove_from_listx=letrecauxacc=function[]->anomaly"Element to be removed not in the list"|y::tlwhenx==y->List.revacc@tl|y::tl->aux(y::acc)tlinaux[]letrecmap_existsf=function[]->None|hd::tl->matchfhdwithNone->map_existsftl|res->resletrecmap_filterf=function[]->[]|hd::tl->matchfhdwithNone->map_filterftl|Someres->res::map_filterftlletmap_accfaccl=leta,l=List.fold_left(fun(a,xs)x->leta,x=faxina,x::xs)(acc,[])lina,List.revlletmap_acc2faccl1l2=leta,l=List.fold_left2(fun(a,xs)xy->leta,x=faxyina,x::xs)(acc,[])l1l2ina,List.revlletmap_acc3faccl1l2l3=letrecauxall1l2l3=matchl1,l2,l3with|[],[],[]->a,List.revl|x::xs,y::ys,z::zs->leta,v=faxyzinauxa(v::l)xsyszs|_->invalid_arg"map_acc3"inauxacc[]l1l2l3letpartition_ifl=letrecauxna1a2=function|[]->List.reva1,List.reva2|x::xs->if(fnx)thenaux(n+1)(x::a1)a2xselseaux(n+1)a1(x::a2)xsinaux0[][]l;;letfold_left2ifaccl1l2=letrecauxnaccl1l2=matchl1,l2with|[],[]->acc|x::xs,y::ys->aux(n+1)(fnaccxy)xsys|_->anomaly"fold_left2i"inaux0accl1l2letrecuniq=function|[]->[]|[_]asx->x|x::(y::_astl)->ifx=ythenuniqtlelsex::uniqtlmoduleGlobal:sigtypebackup(* Takes the initial value *)valnew_local:'a->'arefvalbackup:unit->backupvalrestore:backup->unit(* Like doing a backup just after having created all globals *)valinitial_backup:unit->backup(* Hack, in case the initial value cannot be provided when the
* global is created *)valset_value:'aref->'a->backup->backupvalget_value:'aref->backup->'aend=structtypebackup=(Obj.tref*Obj.t)listletall_globals:backupref=ref[]letnew_local(t:'a):'aref=letres=reftinall_globals:=Obj.magic(res,t)::!all_globals;resletset_value(g:'aref)(v:'a)(l:(Obj.tref*Obj.t)list)=letv=Obj.reprvinletg:Obj.tref=Obj.magicginList.map(fun(g',_asorig)->ifg==g'then(g,v)elseorig)lletget_value(p:'aref)(l:(Obj.tref*Obj.t)list):'a=Obj.magic(List.assq(Obj.magicp)l)letbackup():(Obj.tref*Obj.t)list=List.map(fun(o,_)->o,!o)!all_globalsletrestorel=List.iter(fun(r,v)->r:=v)lletinitial_backup()=!all_globalsendmoduleFork=structtype'alocal_ref='areftypeprocess={exec:'a'b.('a->'b)->'a->'b;get:'a.'alocal_ref->'a;set:'a.'alocal_ref->'a->unit}letnew_local=Global.new_localletfork()=letsaved_globals=Global.backup()inletmy_globals=ref(Global.initial_backup())inletensure_runtimefx=(* [%spy "exec-begin" (fun _ _ -> ()) ()]; *)Global.restore!my_globals;tryletrc=fxinmy_globals:=Global.backup();Global.restoresaved_globals;(* [%spy "exec-end" (fun _ _ -> ()) ()]; *)rcwithe->my_globals:=Global.backup();Global.restoresaved_globals;(* [%spy "exec-end" (fun _ _ -> ()) ()]; *)raiseein{exec=ensure_runtime;get=(funp->Global.get_valuep!my_globals);set=(funpv->my_globals:=Global.set_valuepv!my_globals)}endmoduleUUID=structmoduleSelf=structtypet=intletppfmtx=Format.pp_print_intfmtxletshowx=Format.asprintf"@[%a@]"ppxlet_=show[@@@end]letcomparexy=x-yletequalxy=x==ylethashx=xendletcounter=ref2letmake()=incrcounter;!countermoduleHtbl=Hashtbl.Make(Self)includeSelfendtype'aspaghetti_printer=(Format.formatter->'a->unit)refletmk_spaghetti_printer()=ref(funfmt_->Fmt.fprintffmt"please extend this printer")letset_spaghetti_printerrf=r:=fletpp_spaghettirfmtx=!rfmtxletshow_spaghettirx=letb=Buffer.create20inletfmt=Format.formatter_of_bufferbinFormat.fprintffmt"%a%!"!rx;Buffer.contentsbletpp_spaghetti_anyr~idfmtx=!rfmt(id,Obj.reprx)moduleCData=structtypet={t:Obj.t;ty:int;}typett=ttype'adata_declaration={data_name:string;data_pp:Format.formatter->'a->unit;data_compare:'a->'a->int;data_hash:'a->int;data_hconsed:bool;}type'acdata={cin:'a->t;isc:t->bool;cout:t->'a;name:string}typecdata_declaration={cdata_name:string;cdata_pp:Format.formatter->t->unit;cdata_compare:t->t->int;cdata_hash:t->int;cdata_canon:t->t;}letm:cdata_declarationIntMap.tref=refIntMap.emptyletcgetx=Obj.objx.tletppfx=(IntMap.findx.ty!m).cdata_ppfxletequalxy=x.ty=y.ty&&(IntMap.findx.ty!m).cdata_comparexy==0letcomparexy=ifx.ty=y.tythen(IntMap.findx.ty!m).cdata_comparexyelsetype_error"cdata of different type compared"lethashx=(IntMap.findx.ty!m).cdata_hashxletnamex=(IntMap.findx.ty!m).cdata_namelethconsx=(IntMap.findx.ty!m).cdata_canonxletty2{isc;_}({ty=t1;_}asx){ty=t2;_}=iscx&&t1=t2letshowx=letb=Buffer.create22inFormat.fprintf(Format.formatter_of_bufferb)"@[%a@]"ppx;Buffer.contentsbletfresh_tid=lettid=ref0infun()->incrtid;!tidletdeclare{data_compare;data_pp;data_hash;data_name;data_hconsed}=lettid=fresh_tid()inletcdata_comparexy=data_compare(cgetx)(cgety)inletcdata_hashx=data_hash(cgetx)inletcdata_canon=ifdata_hconsedthenletmoduleCD:Hashtbl.HashedTypewithtypet=tt=structtypet=ttlethash=cdata_hashletequalxy=cdata_comparexy==0endinletmoduleHS:Weak.Swithtypedata=tt=Weak.Make(CD)inleth=HS.create17in(funx->tryHS.findhxwithNot_found->HS.addhx;x)else(funx->x)inletcdata_compare_hconsed=ifdata_hconsedthen(funxy->ifx==ythen0elsecdata_comparexy)elsecdata_compareinm:=IntMap.addtid{cdata_name=data_name;cdata_pp=(funfx->data_ppf(cgetx));cdata_compare=cdata_compare_hconsed;cdata_hash;cdata_canon;}!m;{cin=(funv->cdata_canon{t=Obj.reprv;ty=tid});isc=(func->c.ty=tid);cout=(func->assert(c.ty=tid);cgetc);name=data_name;}letmorph1{cin;cout;_}fx=cin(f(coutx))letmorph2{cin;cout;_}fxy=cin(f(coutx)(couty))letmap{cout;_}{cin;_}fx=cin(f(coutx))endletmake_absolutecwdfilename=ifnot(Filename.is_relativefilename)thenfilenameelseFilename.concatcwdfilenameletrecreadsymlinksf=tryletlink=Unix.readlinkfinifnot(Filename.is_relativelink)thenreadsymlinkslinkelsereadsymlinksFilename.(concat(dirnamef)link)withUnix.Unix_error_|Failure_->fexceptionFile_not_foundofstringletstd_resolver?(cwd=Sys.getcwd())~paths()=letdirs=List.map(funf->make_absolutecwd(readsymlinksf))pathsinfun?(cwd=Sys.getcwd())~unit:(origfilenameasfilename)()->letreciter_tjpathdirnames=letfilename,dirnames,relative=ifnot(Filename.is_relativefilename)thenfilename,[],falseelsematchdirnameswith[]->raise(File_not_foundfilename)|dirname::dirnames->Filename.concatdirnamefilename,dirnames,trueinletprefixname=Filename.remove_extensionfilenameinletchange_suffixfilename=ifFilename.check_suffixfilename".elpi"then(* Backward compatibility with Teyjus *)prefixname^".mod"elseifFilename.check_suffixfilename".mod"then(* Forward compatibility with Teyjus *)prefixname^".elpi"elsefilenameinifSys.file_existsfilenamethenfilenameelseletchanged_filename=change_suffixfilenameinifSys.file_existschanged_filenamethenchanged_filenameelseifrelativetheniter_tjpathdirnameselseraise(File_not_foundorigfilename)intryiter_tjpath(cwd::dirs)withFile_not_foundf->raise(Failure("File "^f^" not found in: "^String.concat", "dirs))(* Used by pretty printers, to be later instantiated in module Constants *)letpp_const=mk_spaghetti_printer()typeconstant=int(* De Bruijn levels *)[@@derivingord]letpp_constant=pp_spaghettipp_constletshow_constant=show_spaghettipp_constmoduleConstants:sigtypet=constantmoduleMap:Map.Swithtypekey=constantmoduleSet:Set.Swithtypeelt=constantvalpp:Format.formatter->t->unitvalshow:t->stringvalcompare:t->t->intend=structmoduleSelf=structtypet=constantletcomparexy=x-yletpp=pp_constantletshow=show_constantendmoduleMap=Map.Make(Self)moduleSet=Set.Make(Self)includeSelfendletversion_parser~whatv=tryletis_numberx=trylet_=int_of_stringxintruewith_->falseinletv'=Re.Str.(replace_first(regexp"^v")""v)in(* v1.20... -> 1.20... *)letv'=Re.Str.(replace_first(regexp"\\(-\\|\\+\\).*$")""v')in(* ...-10-fjdnfs -> ... *)letl=String.split_on_char'.'v'inmatchlwith|[ma;mi;p]whenList.for_allis_numberl->int_of_stringma,int_of_stringmi,int_of_stringp|[ma;mi]whenList.for_allis_numberl->int_of_stringma,int_of_stringmi,0|[v]whenRe.Str.(string_match(regexp"^%%.*%%$")v0)->99,99,99|[v]whenRe.Str.(string_match(regexp"^[0-9a-f]+$")v0)->99,99,99|_->raise(Failure"invalid format")withFailuremsg->warn~id:"version-parser"("cannot parse version of "^what^" '"^v^"': "^msg);0,0,0