123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215openFlecheletmessage~io=letlvl=Io.Level.InfoinFormat.kasprintf(funmessage->Io.Report.msg~io~lvl"[baseline] %s"message)(* Log with newline *)letlog~io:_=Stdlib.Format.eprintf"[baseline] ";Stdlib.Format.(kfprintf(funfmt->pp_print_newlinefmt();pp_print_flushfmt())err_formatter)(* Log without newline *)letlog_line~io:_=(* XXX Improve, before it was *)(* let reset = Spectrum.prepare_ppf Stdlib.Format.err_formatter in *)letreset_()=()inStdlib.Format.eprintf"\r ";Stdlib.Format.eprintf"\r[baseline] ";Stdlib.Format.(kfprintf(funfmt->pp_print_flushfmt();resetfmt())err_formatter)letget_goals~token~st=letpr=Info.Goals.to_ppinmatchInfo.Goals.goals~token~compact:true~st~prwith|{Coq.Protect.E.r=Interrupted;_}|{r=Completed(Error_);_}|{r=Completed(OkNone);_}->[]|{r=Completed(Ok(Somegoals));_}->goals.goalsletget_goals_thm~token{Common.ThmDecl.names=_;node}=letst=node.stateinget_goals~token~stmoduleTacResult=structtypet={names:stringlist;goals:Pp.tCoq.Goals.Reified_goal.tlist;feedback:Loc.tCoq.Message.tlist}(* let pp fmt { names; goals; feedback } = () *)endletrun_tac_silent=trueletredirect_writefdescf=(* Should call fflush on fdesc, where is the ocaml api? *)letbak=Unix.dupfdescinletnew_=Unix.openfile"/dev/null"[Unix.O_WRONLY]0o644inUnix.dup2new_fdesc;Unix.closenew_;letfinally()=Unix.dup2bakfdesc;Unix.closebakinFun.protect~finallyf(* We capture stderr/stdin as to have better output for hammer *)letrun_tac~token~st~timeouttac=ifrun_tac_silentthenredirect_writeUnix.stdout(fun()->redirect_writeUnix.stderr(fun()->Common.run_tac~token~st~timeouttac))elseCommon.run_tac~token~st~timeouttac(* Dont' forget the dot at the end of [tac] *)letapply_tac~token~tac{Common.ThmDecl.names;node}=letderror=Lang.Diagnostic.Severity.errorinletst=node.statein(* Timeout from env or default 5.0 *)lettimeout=matchSys.getenv_opt"BASE_TIMEOUT"with|Somet->float_of_stringt|None->5.0inletst,feedback=matchrun_tac~token~st~timeouttacwith|Coq.Protect.E.{r=Interrupted;feedback}->(* This can happen in timeouts, etc... *)letmsg=Pp.(str"Coq was interrupted while executing the tactic")inletmsg={Coq.Message.Payload.range=None;msg;quickFix=None}in(st,(derror,msg)::feedback)|Coq.Protect.E.{r=Completed(Error(User{range;msg;_}));feedback}|Coq.Protect.E.{r=Completed(Error(Anomaly{range;msg;_}));feedback}->letmsg={Coq.Message.Payload.range;msg;quickFix=None}in(st,(derror,msg)::feedback)|Coq.Protect.E.{r=Completed(OkNone);feedback}->letmsg=Pp.(str"EOF when parsing tactic")inletmsg={Coq.Message.Payload.range=None;msg;quickFix=None}in(st,(derror,msg)::feedback)|Coq.Protect.E.{r=Completed(Ok(Somest));feedback}->(st,feedback)inletgoals=get_goals~token~stin{TacResult.names;goals;feedback}letcheck_provedgoals=List.filter_map(fun{TacResult.names;goals;feedback=_}->ifCList.is_emptygoalsthenSomenameselseNone)goalsletpp_namesfmtnames=Format.fprintffmt"{%s}"(String.concat" "names)lettraced~io~doc_name~tac~totalfidxx=let({TacResult.names;goals;_}asres)=fxinlog_line~io"%s | [%s] (%d/%d) %a open_goals :%d"doc_nametacidxtotalpp_namesnames(List.lengthgoals);res(* Display list of proven theorems *)letdisplay_theorems=falseletcheck_tac~io~token~thms~doc_name~tac=letpp_sep=Format.pp_print_spaceinlettotal=List.lengththmsinletgoals_after=List.mapi(traced~io~doc_name~tac~total(apply_tac~token~tac))thmsinletproved_thms=check_provedgoals_afterinletproved_thms_to_show=ifdisplay_theoremsthenproved_thmselse[]inlog_line~io"%s | [%s] theorems proved (%d/%d):@\n @[<hov>%a@]"doc_nametac(List.lengthproved_thms)totalFormat.(pp_print_list~pp_seppp_names)proved_thms_to_show;proved_thmsmoduleBaselineResult=structtypet={tactic:string;proved:stringlist}[@@derivingyojson]endletdo_baseline~io~token~doc=letthms=Common.get_theorems~docinletgoals_original=List.map(get_goals_thm~token)thmsinletdoc_name=Stdlib.Filename.basename(Lang.LUri.File.to_string_filedoc.uri)inletcheck=check_tac~io~token~thms~doc_namein(* EJGA: Note OCaml will start evaluating this by the last element, so I've
reversed them. *)letproved_baselines=[("tactician-base",check~tac:"by synth.");("hammer",check~tac:"by hammer.");("sauto",check~tac:"by sauto.");("auto",check~tac:"by auto.")]inmessage~io"number of theorems %d"(List.lengththms);message~io"number of goals %d"List.(length(concatgoals_original));message~io"baseline report end -------------------------";(* If timeout is given add it to the name *)lettimeout=matchSys.getenv_opt"BASE_TIMEOUT"with|Somet->"_"^t|None->""inletfn=Lang.LUri.File.to_string_filedoc.uri^timeout^".baseline.json"inletsummary=List.map(fun(tactic,proved)->BaselineResult.{tactic;proved=List.flattenproved})proved_baselinesinletoc=open_outfninoutput_stringoc@@(`List(List.mapBaselineResult.to_yojsonsummary)|>Yojson.Safe.to_string)^"\n";close_outoc;()letdo_require_tauto~io:_=letfrom,library=(Some"Hammer","Tactics")inlettactics=Coq.Workspace.Require.{library;from;flags=Some(Import,None)}in(* From Hammer Require Import Hammer *)letfrom,library=(Some"Hammer","Hammer")inlethammer=Coq.Workspace.Require.{library;from;flags=Some(Import,None)}inletfrom,library=(Some"Tactician","Ltac1")inlettactician=Coq.Workspace.Require.{library;from;flags=Some(Import,None)}inignore[tactics;hammer;tactician];[]letdo_baseline~io~token~(doc:Fleche.Doc.t)=matchCommon.completed_without_error~docwith|None->do_baseline~io~token~doc|Somediags->letfile=Lang.LUri.File.to_string_filedoc.uriinlog~io"@[Document creation for file %s did fail!!@\nDiags:@\n @[%a@]"fileCommon.pp_diagsdiagslet()=Theory.Register.InjectRequire.adddo_require_tauto;Theory.Register.Completed.adddo_baseline