1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
open Pp
open CErrors
open Util
open Vernacexpr
open Vernacprop
let checknav { CAst.loc; v = { expr } } =
if is_navigation_vernac expr && not (is_reset expr) then
CErrors.user_err ?loc (str "Navigation commands forbidden in files.")
let vernac_beautify fmt ast =
try
Pputils.beautify_comments := comments;
let loc = Option.cata Loc.unloc (0,0) ast.CAst.loc in
let before = Pputils.extract_comments (fst loc) in
let before = if CList.is_empty before then mt() else comment before ++ fnl() in
let com = Ppvernac.pr_vernac ast ++ fnl() in
let after = comment (Pputils.extract_comments (snd loc)) in
Pp.pp_with fmt (hov 0 (before ++ com ++ after))
with e ->
let e, info = Exninfo.capture e in
let info = match ast.loc with None -> info | Some loc -> Loc.add_loc info loc in
Exninfo.iraise (e,info)
type time_output =
| ToFeedback
| ToChannel of Format.formatter
let make_time_output = function
| Coqargs.ToFeedback -> ToFeedback
| ToFile f ->
let ch = open_out f in
let fch = Format.formatter_of_out_channel ch in
let close () =
Format.pp_print_flush fch ();
close_out ch
in
at_exit close;
ToChannel fch
module State = struct
type t = {
doc : Stm.doc;
sid : Stateid.t;
proof : Proof.t option;
time : time_output option;
}
end
let emit_time state com tstart tend =
match state.State.time with
| None -> ()
| Some time ->
let pp = Topfmt.pr_cmd_header com ++ System.fmt_time_difference tstart tend in
match time with
| ToFeedback -> Feedback.msg_notice pp
| ToChannel ch -> Pp.pp_with ch (pp ++ fnl())
let interp_vernac ~check ~state ({CAst.loc;_} as com) =
let open State in
try
let doc, nsid, ntip = Stm.add ~doc:state.doc ~ontop:state.sid (not !Flags.quiet) com in
if ntip <> Stm.NewAddTip then
anomaly (str "vernac.ml: We got an unfocus operation on the toplevel!");
let () = if check then Stm.observe ~doc nsid in
let new_proof = Vernacstate.Declare.give_me_the_proof_opt () [@ocaml.warning "-3"] in
{ state with doc; sid = nsid; proof = new_proof; }
with reraise ->
let (reraise, info) = Exninfo.capture reraise in
let info =
match Loc.get_loc info, loc with
| None, Some loc -> Loc.add_loc info loc
| Some _, _ | _, None -> info
in
Exninfo.iraise (reraise, info)
let load_vernac_core ~beautify ~check ~state ?source file =
let in_chan = open_utf8_file_in file in
let input_cleanup () = close_in in_chan in
let source = Option.default (Loc.InFile {dirpath=None; file}) source in
let in_pa = Procq.Parsable.make ~loc:Loc.(initial source)
(Gramlib.Stream.of_channel in_chan) in
let open State in
let rec loop state =
let tstart = System.get_time () in
match
NewProfile.profile "parse_command" (fun () ->
Stm.parse_sentence
~doc:state.doc ~entry:Pvernac.main_entry state.sid in_pa)
()
with
| None ->
let () = beautify |> Option.iter @@ fun beautify ->
Pp.pp_with beautify (comment (List.map snd @@ Procq.Parsable.comments in_pa))
in
input_cleanup ();
state
| Some ast ->
let () = beautify |> Option.iter @@ fun beautify ->
vernac_beautify beautify ast (Procq.Parsable.comments in_pa);
Procq.Parsable.drop_comments in_pa
in
checknav ast;
let state =
try_finally
(fun () ->
NewProfile.profile "command"
~args:(fun () ->
let lnum = match ast.loc with
| None -> "unknown"
| Some loc -> string_of_int loc.line_nb
in
[("cmd", `String (Pp.string_of_ppcmds (Topfmt.pr_cmd_header ast)));
("line", `String lnum)])
(fun () ->
Flags.silently (interp_vernac ~check ~state) ast) ())
()
(fun () ->
let tend = System.get_time () in
emit_time state ast tstart tend)
()
in
(loop [@ocaml.tailcall]) state
in
try loop state
with any ->
let (e, info) = Exninfo.capture any in
input_cleanup ();
Exninfo.iraise (e, info)
let process_expr ~state loc_ast =
try interp_vernac ~check:true ~state loc_ast
with reraise ->
let reraise, info = Exninfo.capture reraise in
let reraise = UserError (CErrors.iprint (reraise, info)) in
let info = Option.cata (Loc.add_loc Exninfo.null) Exninfo.null (Loc.get_loc info) in
ignore(Stm.edit_at ~doc:state.doc state.sid);
Exninfo.iraise (reraise, info)
let process_expr ~state loc_ast =
let tstart = System.get_time () in
try_finally (fun () -> process_expr ~state loc_ast)
()
(fun () ->
let tend = System.get_time () in
emit_time state loc_ast tstart tend)
()
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 open_beautify filename =
let chan_beautify = open_out (filename^beautify_suffix) in
let fmt = set_formatter_translator chan_beautify in
fmt, fun () -> Format.pp_print_flush fmt(); close_out chan_beautify
let load_vernac ?(beautify=false) ~check ~state ?source filename =
let beautify, close_beautify = if not beautify then None, Fun.id
else let fmt, close = open_beautify filename in Some fmt, close
in
let ostate =
Util.try_finally (fun () ->
load_vernac_core ~beautify ~check ~state ?source filename)
()
close_beautify
()
in
ostate