From 8506a4d60417ce498ce4525de044a6a590a5e922 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Wed, 29 Jul 2015 18:38:27 +0200 Subject: Rewrite the main loop of coq-tex. Before this commit, coq-tex was reading the .v file and was guessing how many lines from the coqtop output it should display. Now, it reads the coqtop output and it guesses how many lines from the .v file it should display. That way, coq-tex no longer needs to embed a parser; it relies on coqtop for parsing. This is much more robust and makes it possible to properly handle script such as the following one: Goal { True } + { False }. { left. exact I. } As before, if there is a way for a script to produce something that looks like a prompt (that is, a line that starts with "foo < "), coq-tex will be badly confused. --- tools/coq_tex.ml | 160 ++++++++++++++++++++++++++----------------------------- 1 file changed, 76 insertions(+), 84 deletions(-) (limited to 'tools') diff --git a/tools/coq_tex.ml b/tools/coq_tex.ml index fc652f584c..9a5ff86ef3 100644 --- a/tools/coq_tex.ml +++ b/tools/coq_tex.ml @@ -24,10 +24,7 @@ let hrule = ref false let small = ref false let boot = ref false -let coq_prompt = Str.regexp "Coq < " -let any_prompt = Str.regexp "^[A-Z0-9a-z_\\$']* < " - -let remove_prompt s = Str.replace_first any_prompt "" s +let any_prompt = Str.regexp "[A-Z0-9a-z_\\$']* < " (* First pass: extract the Coq phrases to evaluate from [texfile] * and put them into the file [inputv] *) @@ -66,9 +63,6 @@ let extract texfile inputv = let begin_coq_example = Str.regexp "\\\\begin{coq_\\(example\\|example\\*\\|example\\#\\)}[ \t]*$" let begin_coq_eval = Str.regexp "\\\\begin{coq_eval}[ \t]*$" -let end_coq_example = Str.regexp "\\\\end{coq_\\(example\\|example\\*\\|example\\#\\)}[ \t]*$" -let end_coq_eval = Str.regexp "\\\\end{coq_eval}[ \t]*$" -let dot_end_line = Str.regexp "\\(\\.\\|}\\)[ \t]*\\((\\*.*\\*)\\)?[ \t]*$" let has_match r s = try let _ = Str.search_forward r s 0 in true with Not_found -> false @@ -111,99 +105,97 @@ let insert texfile coq_output result = let c_tex = open_in texfile in let c_coq = open_in coq_output in let c_out = open_out result in - (* next_block k : this function reads the next block of Coq output - * removing the k leading prompts. - * it returns the block as a list of string) *) - let last_read = ref "" in - let next_block k = - if !last_read = "" then last_read := input_line c_coq; - (* skip k prompts *) - for _i = 1 to k do - last_read := remove_prompt !last_read; - done; + (* read lines until a prompt is found (starting from the second line), + purge prompts on the first line and return their number *) + let last_read = ref (input_line c_coq) in + let read_output () = + let first = !last_read in + let nb = ref 0 in + (* remove the leading prompts *) + let rec skip_prompts pos = + if Str.string_match any_prompt first pos then + let () = incr nb in + skip_prompts (Str.match_end ()) + else pos in + let first = + let start = skip_prompts 0 in + String.sub first start (String.length first - start) in (* read and return the following lines until a prompt is found *) let rec read_lines () = let s = input_line c_coq in if Str.string_match any_prompt s 0 then begin last_read := s; [] end else - s :: (read_lines ()) - in - let first = !last_read in first :: (read_lines ()) - in - (* we are just after \end{coq_...} block *) - let rec just_after () = + s :: read_lines () in + (first :: read_lines (), !nb) in + let unhandled_output = ref None in + (* we are inside a \begin{coq_...} ... \end{coq_...} block + * show_... tell what kind of block it is *) + let rec inside show_answers show_questions not_first = let s = input_line c_tex in - if Str.string_match begin_coq_example s 0 then begin - inside (Str.matched_group 1 s <> "example*") - (Str.matched_group 1 s <> "example#") 0 false - end - else begin - if !hrule then output_string c_out "\\hrulefill\\\\\n"; - output_string c_out "\\end{flushleft}\n"; - if !small then output_string c_out "\\end{small}\n"; - if Str.string_match begin_coq_eval s 0 then - eval 0 + if not (Str.string_match end_coq s 0) then begin + let (bl,n) = + match !unhandled_output with + | Some some -> unhandled_output := None; some + | None -> read_output () in + assert (n > 0); + if not_first then output_string c_out "\\medskip\n"; + if !verbose then Printf.printf "Coq < %s\n" s; + if show_questions then encapsule false c_out ("Coq < " ^ s); + let rec read_lines k = + if k = 0 then [] + else + let s = input_line c_tex in + if Str.string_match end_coq s 0 then [] + else s :: read_lines (k - 1) in + let al = read_lines (n - 1) in + if !verbose then List.iter (Printf.printf " %s\n") al; + if show_questions then + List.iter (fun s -> encapsule false c_out (" " ^ s)) al; + let la = n - 1 - List.length al in + if la <> 0 then + (* this happens when the block ends with a comment; the output + is for the command at the beginning of the next block *) + unhandled_output := Some (bl, la) else begin - output_string c_out (s ^ "\n"); - outside () + if !verbose then List.iter print_endline bl; + if show_answers then print_block c_out bl; + inside show_answers show_questions (show_answers || show_questions) end - end + end in (* we are outside of a \begin{coq_...} ... \end{coq_...} block *) - and outside () = - let s = input_line c_tex in - if Str.string_match begin_coq_example s 0 then begin + let rec outside just_after = + let start_block () = if !small then output_string c_out "\\begin{small}\n"; output_string c_out "\\begin{flushleft}\n"; + if !hrule then output_string c_out "\\hrulefill\\\\\n" in + let end_block () = if !hrule then output_string c_out "\\hrulefill\\\\\n"; - inside (Str.matched_group 1 s <> "example*") - (Str.matched_group 1 s <> "example#") 0 true - end else if Str.string_match begin_coq_eval s 0 then - eval 0 - else begin - output_string c_out (s ^ "\n"); - outside () - end - (* we are inside a \begin{coq_example?} ... \end{coq_example?} block - * show_answers tells what kind of block it is - * k is the number of lines read until now *) - and inside show_answers show_questions k first_block = + output_string c_out "\\end{flushleft}\n"; + if !small then output_string c_out "\\end{small}\n" in let s = input_line c_tex in - if Str.string_match end_coq_example s 0 then begin - just_after () + if Str.string_match begin_coq s 0 then begin + let kind = Str.matched_group 1 s in + if kind = "eval" then begin + if just_after then end_block (); + inside false false false; + outside false + end else begin + let show_answers = kind <> "example*" in + let show_questions = kind <> "example#" in + if not just_after then start_block (); + inside show_answers show_questions just_after; + outside true + end end else begin - let prompt = if k = 0 then "Coq < " else " " in - if !verbose then Printf.printf "%s%s\n" prompt s; - if (not first_block) && k=0 then output_string c_out "\\medskip\n"; - if show_questions then encapsule false c_out (prompt ^ s); - if has_match dot_end_line s then begin - let bl = next_block (succ k) in - if !verbose then List.iter print_endline bl; - if show_answers then print_block c_out bl; - inside show_answers show_questions 0 false - end else - inside show_answers show_questions (succ k) first_block - end - (* we are inside a \begin{coq_eval} ... \end{coq_eval} block - * k is the number of lines read until now *) - and eval k = - let s = input_line c_tex in - if Str.string_match end_coq_eval s 0 then - outside () - else begin - if !verbose then Printf.printf "Coq < %s\n" s; - if has_match dot_end_line s then - let bl = next_block (succ k) in - if !verbose then List.iter print_endline bl; - eval 0 - else - eval (succ k) - end - in + if just_after then end_block (); + output_string c_out (s ^ "\n"); + outside false + end in try - let _ = next_block 0 in (* to skip the Coq banner *) - let _ = next_block 0 in (* to skip the Coq answer to Set Printing Width *) - outside () + let _ = read_output () in (* to skip the Coq banner *) + let _ = read_output () in (* to skip the Coq answer to Set Printing Width *) + outside false with End_of_file -> begin close_in c_tex; close_in c_coq; -- cgit v1.2.3 From ffb2788b92323901c1024d1eae221e4beb4b6670 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Wed, 29 Jul 2015 19:07:54 +0200 Subject: Remove empty commands from the output of coq-tex. --- tools/coq_tex.ml | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/coq_tex.ml b/tools/coq_tex.ml index 9a5ff86ef3..9c91889a03 100644 --- a/tools/coq_tex.ml +++ b/tools/coq_tex.ml @@ -129,16 +129,20 @@ let insert texfile coq_output result = s :: read_lines () in (first :: read_lines (), !nb) in let unhandled_output = ref None in + let read_output () = + match !unhandled_output with + | Some some -> unhandled_output := None; some + | None -> read_output () in (* we are inside a \begin{coq_...} ... \end{coq_...} block * show_... tell what kind of block it is *) - let rec inside show_answers show_questions not_first = + let rec inside show_answers show_questions not_first discarded = let s = input_line c_tex in - if not (Str.string_match end_coq s 0) then begin - let (bl,n) = - match !unhandled_output with - | Some some -> unhandled_output := None; some - | None -> read_output () in - assert (n > 0); + if s = "" then + inside show_answers show_questions not_first (discarded + 1) + else if not (Str.string_match end_coq s 0) then begin + let (bl,n) = read_output () in + assert (n > discarded); + let n = n - discarded in if not_first then output_string c_out "\\medskip\n"; if !verbose then Printf.printf "Coq < %s\n" s; if show_questions then encapsule false c_out ("Coq < " ^ s); @@ -160,8 +164,13 @@ let insert texfile coq_output result = else begin if !verbose then List.iter print_endline bl; if show_answers then print_block c_out bl; - inside show_answers show_questions (show_answers || show_questions) + inside show_answers show_questions (show_answers || show_questions) 0 end + end else if discarded > 0 then begin + (* this happens when the block ends with an empty line *) + let (bl,n) = read_output () in + assert (n > discarded); + unhandled_output := Some (bl, n - discarded) end in (* we are outside of a \begin{coq_...} ... \end{coq_...} block *) let rec outside just_after = @@ -178,13 +187,13 @@ let insert texfile coq_output result = let kind = Str.matched_group 1 s in if kind = "eval" then begin if just_after then end_block (); - inside false false false; + inside false false false 0; outside false end else begin let show_answers = kind <> "example*" in let show_questions = kind <> "example#" in if not just_after then start_block (); - inside show_answers show_questions just_after; + inside show_answers show_questions just_after 0; outside true end end else begin -- cgit v1.2.3 From 9a5fb78ef3c7c5d4f568a4d04e169475e9105def Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Wed, 29 Jul 2015 19:58:39 +0200 Subject: Make coq-tex more robust with respect to the (non-)command on the last line. --- tools/coq_tex.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/coq_tex.ml b/tools/coq_tex.ml index 9c91889a03..f65708698c 100644 --- a/tools/coq_tex.ml +++ b/tools/coq_tex.ml @@ -55,7 +55,10 @@ let extract texfile inputv = ("Set Printing Width " ^ (string_of_int !linelen) ^".\n"); outside () with End_of_file -> - begin close_in chan_in; close_out chan_out end + (* a dummy command, just in case the last line was a comment *) + output_string chan_out "Set Printing Width 78.\n"; + close_in chan_in; + close_out chan_out (* Second pass: insert the answers of Coq from [coq_output] into the * TeX file [texfile]. The result goes in file [result]. *) -- cgit v1.2.3 From 5383cdc276d9ba7f1bb05bfe5aeae0a25edbd4a4 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Thu, 30 Jul 2015 07:56:49 +0200 Subject: Remove usage of Printexc.catch in the tools, as it is deprecated since 2001. "This function is deprecated: the runtime system is now able to print uncaught exceptions as precisely as Printexc.catch does. Moreover, calling Printexc.catch makes it harder to track the location of the exception using the debugger or the stack backtrace facility. So, do not use Printexc.catch in new code." --- tools/coq_makefile.ml | 4 +--- tools/coq_tex.ml | 4 +--- tools/coqdep_boot.ml | 4 +--- tools/coqdoc/main.ml | 4 +--- tools/coqwc.mll | 4 +--- tools/gallina.ml | 5 +---- 6 files changed, 6 insertions(+), 19 deletions(-) (limited to 'tools') diff --git a/tools/coq_makefile.ml b/tools/coq_makefile.ml index 8f4772e286..71134c2d97 100644 --- a/tools/coq_makefile.ml +++ b/tools/coq_makefile.ml @@ -842,11 +842,9 @@ let do_makefile args = if not (makefile = None) then close_out !output_channel; exit 0 -let main () = +let _ = let args = if Array.length Sys.argv = 1 then usage (); List.tl (Array.to_list Sys.argv) in do_makefile args - -let _ = Printexc.catch main () diff --git a/tools/coq_tex.ml b/tools/coq_tex.ml index f65708698c..53444cee78 100644 --- a/tools/coq_tex.ml +++ b/tools/coq_tex.ml @@ -285,7 +285,7 @@ let find_coqtop () = "coqtop" end -let main () = +let _ = parse_cl (); if !image = "" then image := Filename.quote (find_coqtop ()); if !boot then image := !image ^ " -boot"; @@ -298,5 +298,3 @@ let main () = flush stdout end; List.iter one_file (List.rev !files) - -let _ = Printexc.catch main () diff --git a/tools/coqdep_boot.ml b/tools/coqdep_boot.ml index 2d5fd36a63..64ce66d2d1 100644 --- a/tools/coqdep_boot.ml +++ b/tools/coqdep_boot.ml @@ -30,7 +30,7 @@ let rec parse = function | f :: ll -> treat_file None f; parse ll | [] -> () -let coqdep_boot () = +let _ = let () = option_boot := true in if Array.length Sys.argv < 2 then exit 1; parse (List.tl (Array.to_list Sys.argv)); @@ -47,5 +47,3 @@ let coqdep_boot () = end; if !option_c then mL_dependencies (); coq_dependencies () - -let _ = Printexc.catch coqdep_boot () diff --git a/tools/coqdoc/main.ml b/tools/coqdoc/main.ml index 9531cd2b07..2554ed495b 100644 --- a/tools/coqdoc/main.ml +++ b/tools/coqdoc/main.ml @@ -557,10 +557,8 @@ let produce_output fl = (*s \textbf{Main program.} Print the banner, parse the command line, read the files and then call [produce_document] from module [Web]. *) -let main () = +let _ = let files = parse () in Index.init_coqlib_library (); if not !quiet then banner (); if files <> [] then produce_output files - -let _ = Printexc.catch main () diff --git a/tools/coqwc.mll b/tools/coqwc.mll index 417ec5355c..9a42553da2 100644 --- a/tools/coqwc.mll +++ b/tools/coqwc.mll @@ -276,7 +276,7 @@ let rec parse = function (*s Main program. *) -let main () = +let _ = let files = parse (List.tl (Array.to_list Sys.argv)) in if not (!spec_only || !proof_only) then printf " spec proof comments\n"; @@ -285,8 +285,6 @@ let main () = | [f] -> process_file f | _ -> List.iter process_file files; print_totals () -let _ = Printexc.catch main () - (*i*)}(*i*) diff --git a/tools/gallina.ml b/tools/gallina.ml index 279919c582..5ce19e7f88 100644 --- a/tools/gallina.ml +++ b/tools/gallina.ml @@ -39,7 +39,7 @@ let traite_stdin () = with Sys_error _ -> () -let gallina () = +let _ = let lg_command = Array.length Sys.argv in if lg_command < 2 then begin output_string stderr "Usage: gallina [-] [-stdout] file1 file2 ...\n"; @@ -59,6 +59,3 @@ let gallina () = traite_stdin () else List.iter traite_fichier !vfiles - -let _ = Printexc.catch gallina () - -- cgit v1.2.3 From 52940b19a7f47fa5022d75c5679785ac90aaa0dc Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Thu, 30 Jul 2015 08:10:05 +0200 Subject: Remove unused variables. --- tools/coq_tex.ml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'tools') diff --git a/tools/coq_tex.ml b/tools/coq_tex.ml index 53444cee78..26a9715ef7 100644 --- a/tools/coq_tex.ml +++ b/tools/coq_tex.ml @@ -63,17 +63,6 @@ let extract texfile inputv = (* Second pass: insert the answers of Coq from [coq_output] into the * TeX file [texfile]. The result goes in file [result]. *) -let begin_coq_example = - Str.regexp "\\\\begin{coq_\\(example\\|example\\*\\|example\\#\\)}[ \t]*$" -let begin_coq_eval = Str.regexp "\\\\begin{coq_eval}[ \t]*$" - -let has_match r s = - try let _ = Str.search_forward r s 0 in true with Not_found -> false - -let percent = Str.regexp "%" -let bang = Str.regexp "!" -let expos = Str.regexp "^" - let tex_escaped s = let dollar = "\\$" and backslash = "\\\\" and expon = "\\^" in let delims = Str.regexp ("[_{}&%#" ^ dollar ^ backslash ^ expon ^"~ <>'`]") in @@ -216,7 +205,7 @@ let insert texfile coq_output result = (* Process of one TeX file *) -let rm f = try Sys.remove f with any -> () +let rm f = try Sys.remove f with _ -> () let one_file texfile = let inputv = Filename.temp_file "coq_tex" ".v" in -- cgit v1.2.3 From 070139d3a82ea23e4d050dd5ccebe3f17047cc62 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Thu, 30 Jul 2015 08:19:10 +0200 Subject: Fix broken regexp. Characters do not need to be escaped in character ranges. It just had the effect of matching backslashes four times. --- tools/coq_tex.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/coq_tex.ml b/tools/coq_tex.ml index 26a9715ef7..8218f84f1f 100644 --- a/tools/coq_tex.ml +++ b/tools/coq_tex.ml @@ -64,8 +64,7 @@ let extract texfile inputv = * TeX file [texfile]. The result goes in file [result]. *) let tex_escaped s = - let dollar = "\\$" and backslash = "\\\\" and expon = "\\^" in - let delims = Str.regexp ("[_{}&%#" ^ dollar ^ backslash ^ expon ^"~ <>'`]") in + let delims = Str.regexp "[_{}&%#$\\^~ <>'`]" in let adapt_delim = function | "_" | "{" | "}" | "&" | "%" | "#" | "$" as c -> "\\"^c | "\\" -> "{\\char'134}" -- cgit v1.2.3 From a9f3607ae72517156301570a4ffa05908609b7e0 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Thu, 30 Jul 2015 08:30:00 +0200 Subject: Fix width of underscore in coq_tex output. --- tools/coq_tex.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/coq_tex.ml b/tools/coq_tex.ml index 8218f84f1f..dbdc2e9db1 100644 --- a/tools/coq_tex.ml +++ b/tools/coq_tex.ml @@ -66,7 +66,8 @@ let extract texfile inputv = let tex_escaped s = let delims = Str.regexp "[_{}&%#$\\^~ <>'`]" in let adapt_delim = function - | "_" | "{" | "}" | "&" | "%" | "#" | "$" as c -> "\\"^c + | "{" | "}" | "&" | "%" | "#" | "$" as c -> "\\"^c + | "_" -> "{\\char`\\_}" | "\\" -> "{\\char'134}" | "^" -> "{\\char'136}" | "~" -> "{\\char'176}" -- cgit v1.2.3 From 505eb0f0dae9b8a6ac810070d60916b67942b305 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Fri, 31 Jul 2015 09:34:48 +0200 Subject: Remove some outdated files and fix permissions. --- tools/README.coq-tex | 13 ------------- tools/README.emacs | 0 tools/coq-sl.sty | 0 3 files changed, 13 deletions(-) delete mode 100755 tools/README.coq-tex mode change 100755 => 100644 tools/README.emacs mode change 100755 => 100644 tools/coq-sl.sty (limited to 'tools') diff --git a/tools/README.coq-tex b/tools/README.coq-tex deleted file mode 100755 index 5c7606a968..0000000000 --- a/tools/README.coq-tex +++ /dev/null @@ -1,13 +0,0 @@ -DESCRIPTION. - -The coq-tex filter extracts Coq phrases embedded in LaTeX files, -evaluates them, and insert the outcome of the evaluation after each -phrase. - -The filter is written in Perl, so you'll need Perl version 4 installed -on your machine. - -USAGE. See the manual page (coq-tex.1). - -AUTHOR. Jean-Christophe Filliatre (jcfillia@lip.ens-lyon.fr) - from caml-tex of Xavier Leroy. diff --git a/tools/README.emacs b/tools/README.emacs old mode 100755 new mode 100644 diff --git a/tools/coq-sl.sty b/tools/coq-sl.sty old mode 100755 new mode 100644 -- cgit v1.2.3