123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* Parsing of vernacular. *)openPpopenCErrorsopenUtilopenVernacexpropenVernacprop(* The functions in this module may raise (unexplainable!) exceptions.
Use the module Coqtoplevel, which catches these exceptions
(the exceptions are explained only at the toplevel). *)letchecknav{CAst.loc;v={expr}}=ifis_navigation_vernacexpr&¬(is_resetexpr)thenCErrors.user_err?loc(str"Navigation commands forbidden in files.")(* Echo from a buffer based on position.
XXX: Should move to utility file. *)letvernac_echo?locin_chan=letopenLocinOption.iter(funloc->letlen=loc.ep-loc.bpinseek_inin_chanloc.bp;Feedback.msg_notice@@str@@really_input_stringin_chanlen)loc(* Re-enable when we get back to feedback printing *)(* let is_end_of_input any = match any with *)(* Stm.End_of_input -> true *)(* | _ -> false *)moduleState=structtypet={doc:Stm.doc;sid:Stateid.t;proof:Proof.toption;time:bool;}endletinterp_vernac~check~interactive~state({CAst.loc;_}ascom)=letopenStateintry(* The -time option is only supported from console-based clients
due to the way it prints. *)letcom=ifstate.timethenbeginCAst.map(funcmd->{cmdwithcontrol=ControlTimestate.time::cmd.control})comendelsecominletdoc,nsid,ntip=Stm.add~doc:state.doc~ontop:state.sid(not!Flags.quiet)comin(* Main STM interaction *)ifntip<>Stm.NewAddTipthenanomaly(str"vernac.ml: We got an unfocus operation on the toplevel!");(* Force the command *)letndoc=ifcheckthenStm.observe~docnsidelsedocinletnew_proof=Vernacstate.Declare.give_me_the_proof_opt()[@ocaml.warning"-3"]in{statewithdoc=ndoc;sid=nsid;proof=new_proof;}withreraise->let(reraise,info)=Exninfo.capturereraisein(* XXX: In non-interactive mode edit_at seems to do very weird
things, so we better avoid it while we investigate *)letreraise=ifinteractivethenbegin(* Exceptions don't carry enough state to print themselves (typically missing the nametab)
so we need to print before resetting to an older state. See eg #16745 *)letreraise=UserError(CErrors.printreraise)inignore(Stm.edit_at~doc:state.docstate.sid);reraiseendelsereraiseinletinfo=beginmatchLoc.get_locinfowith|None->Option.cata(Loc.add_locinfo)infoloc|Some_->infoendinExninfo.iraise(reraise,info)(* Load a vernac file. CErrors are annotated with file and location *)letload_vernac_core~echo~check~interactive~state?ldirfile=(* Keep in sync *)letin_chan=open_utf8_file_infileinletin_echo=ifechothenSome(open_utf8_file_infile)elseNoneinletinput_cleanup()=close_inin_chan;Option.iterclose_inin_echoinletdirpath=Option.cata(funldir->SomeNames.DirPath.(to_stringldir))Noneldirinletin_pa=Pcoq.Parsable.make~loc:Loc.(initial(InFile{dirpath;file}))(Gramlib.Stream.of_channelin_chan)inletopenStatein(* ids = For beautify, list of parsed sids *)letrecloopstateids=matchStm.parse_sentence~doc:state.doc~entry:Pvernac.main_entrystate.sidin_pawith|None->input_cleanup();state,ids,Pcoq.Parsable.commentsin_pa|Someast->(* Printing of AST for -compile-verbose *)Option.iter(vernac_echo?loc:ast.CAst.loc)in_echo;checknavast;letstate=Flags.silently(interp_vernac~check~interactive~state)astin(loop[@ocaml.tailcall])state(state.sid::ids)intryloopstate[]withany->(* whatever the exception *)let(e,info)=Exninfo.captureanyininput_cleanup();Exninfo.iraise(e,info)letprocess_expr~stateloc_ast=interp_vernac~interactive:true~check:true~stateloc_ast(******************************************************************************)(* Beautify-specific code *)(******************************************************************************)(* vernac parses the given stream, executes interpfun on the syntax tree it
* parses, and is verbose on "primitives" commands if verbosely is true *)letbeautify_suffix=".beautified"letset_formatter_translatorch=letoutsbe=output_substringchsbeinletft=Format.make_formatterout(fun()->flushch)inFormat.pp_set_max_boxesftmax_int;ftletpr_new_syntax?locft_beautifyocom=letloc=Option.cataLoc.unloc(0,0)locinletbefore=comment(Pputils.extract_comments(fstloc))inletcom=Option.cataPpvernac.pr_vernac(mt())ocominletafter=comment(Pputils.extract_comments(sndloc))inif!Flags.beautify_filethen(Pp.pp_withft_beautify(hov0(before++com++after));Format.pp_print_flushft_beautify())elseFeedback.msg_info(hov4(str"New Syntax:"++fnl()++(hov0com)))(* load_vernac with beautify *)letbeautify_pass~doc~comments~ids~filename=letft_beautify,close_beautify=if!Flags.beautify_filethenletchan_beautify=open_out(filename^beautify_suffix)inset_formatter_translatorchan_beautify,fun()->close_outchan_beautify;else!Topfmt.std_ft,fun()->()in(* The interface to the comment printer is imperative, so we first
set the comments, then we call print. This has to be done for
each file. *)Pputils.beautify_comments:=comments;List.iter(funid->pr_new_syntaxft_beautify(Stm.get_ast~docid))ids;(* Is this called so comments at EOF are printed? *)pr_new_syntax~loc:(Loc.make_loc(max_int,max_int))ft_beautifyNone;close_beautify()(* Main driver for file loading. For now, we only do one beautify
pass. *)letload_vernac~echo~check~interactive~state?ldirfilename=letostate,ids,comments=load_vernac_core~echo~check~interactive~state?ldirfilenamein(* Pass for beautify *)if!Flags.beautifythenbeautify_pass~doc:ostate.State.doc~comments~ids:(List.revids)~filename;(* End pass *)ostate