(************************************************************************) (* * The Coq Proof Assistant / The Coq Development Team *) (* v * Copyright INRIA, CNRS and contributors *) (* let len = loc.ep - loc.bp in seek_in in_chan loc.bp; Feedback.msg_notice @@ str @@ really_input_string in_chan len ) 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 *) module State = struct type t = { doc : Stm.doc; sid : Stateid.t; proof : Proof.t option; time : bool; } end let interp_vernac ~check ~interactive ~state ({CAst.loc;_} as com) = let open State in try (* The -time option is only supported from console-based clients due to the way it prints. *) let com = if state.time then begin CAst.map (fun cmd -> { cmd with control = ControlTime state.time :: cmd.control }) com end else com in let doc, nsid, ntip = Stm.add ~doc:state.doc ~ontop:state.sid (not !Flags.quiet) com in (* Main STM interaction *) if ntip <> `NewTip then anomaly (str "vernac.ml: We got an unfocus operation on the toplevel!"); (* Force the command *) let ndoc = if check then Stm.observe ~doc nsid else doc in let new_proof = Vernacstate.Declare.give_me_the_proof_opt () [@ocaml.warning "-3"] in { state with doc = ndoc; sid = nsid; proof = new_proof; } with reraise -> let (reraise, info) = Exninfo.capture reraise in (* XXX: In non-interactive mode edit_at seems to do very weird things, so we better avoid it while we investigate *) if interactive then ignore(Stm.edit_at ~doc:state.doc state.sid); let info = begin match Loc.get_loc info with | None -> Option.cata (Loc.add_loc info) info loc | Some _ -> info end in Exninfo.iraise (reraise, info) (* Load a vernac file. CErrors are annotated with file and location *) let load_vernac_core ~echo ~check ~interactive ~state file = (* Keep in sync *) let in_chan = open_utf8_file_in file in let in_echo = if echo then Some (open_utf8_file_in file) else None in let input_cleanup () = close_in in_chan; Option.iter close_in in_echo in let in_pa = Pcoq.Parsable.make ~source:(Loc.InFile file) (Stream.of_channel in_chan) in let open State in (* ids = For beautify, list of parsed sids *) let rec loop state ids = match Stm.parse_sentence ~doc:state.doc ~entry:Pvernac.main_entry state.sid in_pa with | None -> input_cleanup (); state, ids, Pcoq.Parsable.comments in_pa | Some ast -> (* Printing of AST for -compile-verbose *) Option.iter (vernac_echo ?loc:ast.CAst.loc) in_echo; checknav ast; let state = Flags.silently (interp_vernac ~check ~interactive ~state) ast in (loop [@ocaml.tailcall]) state (state.sid :: ids) in try loop state [] with any -> (* whatever the exception *) let (e, info) = Exninfo.capture any in input_cleanup (); Exninfo.iraise (e, info) let process_expr ~state loc_ast = interp_vernac ~interactive:true ~check:true ~state loc_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 *) let beautify_suffix = ".beautified" let set_formatter_translator ch = let out s b e = output_substring ch s b e in let ft = Format.make_formatter out (fun () -> flush ch) in Format.pp_set_max_boxes ft max_int; ft let pr_new_syntax ?loc ft_beautify ocom = let loc = Option.cata Loc.unloc (0,0) loc in let before = comment (Pputils.extract_comments (fst loc)) in let com = Option.cata Ppvernac.pr_vernac (mt ()) ocom in let after = comment (Pputils.extract_comments (snd loc)) in if !Flags.beautify_file then (Pp.pp_with ft_beautify (hov 0 (before ++ com ++ after)); Format.pp_print_flush ft_beautify ()) else Feedback.msg_info (hov 4 (str"New Syntax:" ++ fnl() ++ (hov 0 com))) (* load_vernac with beautify *) let beautify_pass ~doc ~comments ~ids ~filename = let ft_beautify, close_beautify = if !Flags.beautify_file then let chan_beautify = open_out (filename^beautify_suffix) in set_formatter_translator chan_beautify, fun () -> close_out chan_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 (fun id -> pr_new_syntax ft_beautify (Stm.get_ast ~doc id)) ids; (* Is this called so comments at EOF are printed? *) pr_new_syntax ~loc:(Loc.make_loc (max_int,max_int)) ft_beautify None; close_beautify () (* Main driver for file loading. For now, we only do one beautify pass. *) let load_vernac ~echo ~check ~interactive ~state filename = let ostate, ids, comments = load_vernac_core ~echo ~check ~interactive ~state filename in (* Pass for beautify *) if !Flags.beautify then beautify_pass ~doc:ostate.State.doc ~comments ~ids:(List.rev ids) ~filename; (* End pass *) ostate