why3session_html.ml 10.4 KB
Newer Older
Andrei Paskevich's avatar
Andrei Paskevich committed
1 2 3
(********************************************************************)
(*                                                                  *)
(*  The Why3 Verification Platform   /   The Why3 Development Team  *)
MARCHE Claude's avatar
MARCHE Claude committed
4
(*  Copyright 2010-2017   --   INRIA - CNRS - Paris-Sud University  *)
Andrei Paskevich's avatar
Andrei Paskevich committed
5 6 7 8
(*                                                                  *)
(*  This software is distributed under the terms of the GNU Lesser  *)
(*  General Public License version 2.1, with the special exception  *)
(*  on linking described in file LICENSE.                           *)
9
(*                                                                  *)
Andrei Paskevich's avatar
Andrei Paskevich committed
10
(********************************************************************)
11

12
open Format
13
open Why3
14
open Why3session_lib
15

16
module Hprover = Whyconf.Hprover
17
module S = Session_itp
18

19
let output_dir = ref ""
20
let opt_context = ref false
21

22
type style = SimpleTree | Table
23

24 25
let opt_style = ref Table
let default_style = "table"
26 27

let set_opt_style = function
28
  | "simpletree" -> opt_style := SimpleTree
29
  | "table" -> opt_style := Table
Andrei Paskevich's avatar
Andrei Paskevich committed
30
  | _ ->
31 32 33
    eprintf "Unknown html style, ignored@."

let () = set_opt_style default_style
34

35 36 37 38 39 40 41 42 43
let opt_pp = ref []

let set_opt_pp_in,set_opt_pp_cmd,set_opt_pp_out =
  let suf = ref "" in
  let cmd = ref "" in
  (fun s -> suf := s),
  (fun s -> cmd := s),
  (fun s -> opt_pp := (!suf,(!cmd,s))::!opt_pp)

44
let spec =
45 46
  ("-o",
   Arg.Set_string output_dir,
MARCHE Claude's avatar
MARCHE Claude committed
47
   "<path> output directory ('-' for stdout)") ::
48
  ("--context", Arg.Set opt_context,
49
   " add context around the generated HTML code") ::
50
  ("--style", Arg.Symbol (["simpletree";"table"], set_opt_style),
MARCHE Claude's avatar
MARCHE Claude committed
51
   " style to use, defaults to '" ^ default_style ^ "'."
52
) ::
53
  ("--add_pp", Arg.Tuple
54 55 56
    [Arg.String set_opt_pp_in;
     Arg.String set_opt_pp_cmd;
     Arg.String set_opt_pp_out],
57
  "<suffix> <cmd> <out_suffix> declare a pretty-printer for edited proofs") ::
58 59
  ("--coqdoc",
   Arg.Unit (fun ()->
60
    opt_pp := (".v",("coqdoc --no-index --html -o %o %i",".html"))::!opt_pp),
MARCHE Claude's avatar
MARCHE Claude committed
61
  " use coqdoc to print Coq proofs") ::
62
  common_options
63

64
open Session_itp
65

66
type context =
67
    (string ->
MARCHE Claude's avatar
MARCHE Claude committed
68
     (formatter -> session -> unit) -> session
69 70
     -> unit, formatter, unit) format

71
let run_file (context : context) print_session fname =
MARCHE Claude's avatar
MARCHE Claude committed
72 73
  let ses,_ = read_session fname in
  let project_dir = get_dir ses in
74 75 76 77 78 79
  let output_dir =
    if !output_dir = "" then project_dir else !output_dir
  in
  let basename = Filename.basename project_dir in
  let cout =
    if output_dir = "-" then stdout else
80
      open_out (Filename.concat output_dir ("why3session.html"))
81
  in
82 83
  let fmt = formatter_of_out_channel cout in
  if !opt_context
MARCHE Claude's avatar
MARCHE Claude committed
84 85
  then fprintf fmt context basename (print_session basename) ses
  else print_session basename fmt ses;
86 87 88 89
  pp_print_flush fmt ();
  if output_dir <> "-" then close_out cout


90 91 92
module Table =
struct

MARCHE Claude's avatar
MARCHE Claude committed
93 94 95
  let provers_stats s provers theory =
    theory_iter_proof_attempt s (fun a ->
      Hprover.replace provers a.prover a.prover) theory
96 97 98 99

  let print_prover = Whyconf.print_prover


Andrei Paskevich's avatar
Andrei Paskevich committed
100 101 102
  let color_of_status ?(dark=false) fmt b =
    fprintf fmt "%s" (if b then
        if dark then "008000" else "C0FFC0"
103 104
      else "FF0000")

MARCHE Claude's avatar
MARCHE Claude committed
105
let print_results fmt s provers proofs =
106 107 108 109
  List.iter (fun p ->
    fprintf fmt "<td bgcolor=\"#";
    begin
      try
MARCHE Claude's avatar
MARCHE Claude committed
110 111
        let pr = get_proof_attempt_node s (Hprover.find proofs p) in
        let s = pr.proof_state in
112 113
        begin
          match s with
MARCHE Claude's avatar
MARCHE Claude committed
114
	  | Some res ->
115 116 117 118 119 120 121
	    begin
	      match res.Call_provers.pr_answer with
		| Call_provers.Valid ->
                  fprintf fmt "C0FFC0\">%.2f" res.Call_provers.pr_time
		| Call_provers.Invalid ->
                  fprintf fmt "FF0000\">Invalid"
		| Call_provers.Timeout ->
MARCHE Claude's avatar
MARCHE Claude committed
122
                  fprintf fmt "FF8000\">Timeout (%ds)"
MARCHE Claude's avatar
MARCHE Claude committed
123
                    pr.limit.Call_provers.limit_time
124
		| Call_provers.OutOfMemory ->
MARCHE Claude's avatar
MARCHE Claude committed
125
                  fprintf fmt "FF8000\">Out Of Memory (%dM)"
MARCHE Claude's avatar
MARCHE Claude committed
126
                    pr.limit.Call_provers.limit_mem
127 128
		| Call_provers.StepLimitExceeded ->
                  fprintf fmt "FF8000\">Step limit exceeded"
129
		| Call_provers.Unknown _ ->
MARCHE Claude's avatar
MARCHE Claude committed
130
                  fprintf fmt "FF8000\">%.2f" res.Call_provers.pr_time
131
		| Call_provers.Failure _ ->
Andrei Paskevich's avatar
Andrei Paskevich committed
132 133 134
                  fprintf fmt "FF8000\">Failure"
		| Call_provers.HighFailure ->
                  fprintf fmt "FF8000\">High Failure"
135
	    end
MARCHE Claude's avatar
MARCHE Claude committed
136
	  | None -> fprintf fmt "E0E0E0\">result missing"
137
        end;
138
        if pr.S.proof_obsolete then fprintf fmt " (obsolete)"
MARCHE Claude's avatar
MARCHE Claude committed
139
      with Not_found -> fprintf fmt "E0E0E0\">---"
140 141 142
    end;
    fprintf fmt "</td>") provers

MARCHE Claude's avatar
MARCHE Claude committed
143
let rec num_lines s acc tr =
MARCHE Claude's avatar
MARCHE Claude committed
144
  List.fold_left
Andrei Paskevich's avatar
Andrei Paskevich committed
145
    (fun acc g -> 1 +
MARCHE Claude's avatar
MARCHE Claude committed
146 147 148
      List.fold_left (fun acc tr -> 1 + num_lines s acc tr)
      acc (get_transformations s g))
    acc (get_sub_tasks s tr)
MARCHE Claude's avatar
MARCHE Claude committed
149

MARCHE Claude's avatar
MARCHE Claude committed
150
  let rec print_transf fmt s depth max_depth provers tr =
151
    fprintf fmt "<tr>";
152
    for _i=1 to 0 (* depth-1 *) do fprintf fmt "<td></td>" done;
Andrei Paskevich's avatar
Andrei Paskevich committed
153
    fprintf fmt "<td bgcolor=\"#%a\" colspan=\"%d\">"
MARCHE Claude's avatar
MARCHE Claude committed
154
      (color_of_status ~dark:false) (tn_proved s tr)
MARCHE Claude's avatar
MARCHE Claude committed
155 156
      (max_depth - depth + 1);
    (* for i=1 to depth-1 do fprintf fmt "&nbsp;&nbsp;&nbsp;&nbsp;" done; *)
MARCHE Claude's avatar
MARCHE Claude committed
157 158 159
    let name = (get_transf_name s tr) ^
                 (String.concat "" (get_transf_args s tr)) in
    fprintf fmt "%s</td>" name ;
160
    for _i=1 (* depth *) to (*max_depth - 1 + *) List.length provers do
161 162 163
      fprintf fmt "<td bgcolor=\"#E0E0E0\"></td>"
    done;
    fprintf fmt "</tr>@\n";
MARCHE Claude's avatar
MARCHE Claude committed
164
    fprintf fmt "<td rowspan=\"%d\">&nbsp;&nbsp;</td>" (num_lines s 0 tr);
MARCHE Claude's avatar
MARCHE Claude committed
165 166
    let (_:bool) = List.fold_left
      (fun is_first g ->
MARCHE Claude's avatar
MARCHE Claude committed
167
        print_goal fmt s is_first (depth+1) max_depth provers g;
MARCHE Claude's avatar
MARCHE Claude committed
168
        false)
MARCHE Claude's avatar
MARCHE Claude committed
169
      true (get_sub_tasks s tr)
MARCHE Claude's avatar
MARCHE Claude committed
170 171
    in ()

MARCHE Claude's avatar
MARCHE Claude committed
172
  and print_goal fmt s is_first depth max_depth provers g =
MARCHE Claude's avatar
MARCHE Claude committed
173 174
    if not is_first then fprintf fmt "<tr>";
    (* for i=1 to 0 (\* depth-1 *\) do fprintf fmt "<td></td>" done; *)
Andrei Paskevich's avatar
Andrei Paskevich committed
175
    fprintf fmt "<td bgcolor=\"#%a\" colspan=\"%d\">"
MARCHE Claude's avatar
MARCHE Claude committed
176
      (color_of_status ~dark:false) (pn_proved s g)
177
      (max_depth - depth + 1);
MARCHE Claude's avatar
MARCHE Claude committed
178
    (* for i=1 to depth-1 do fprintf fmt "&nbsp;&nbsp;&nbsp;&nbsp;" done; *)
MARCHE Claude's avatar
MARCHE Claude committed
179
    fprintf fmt "%s</td>" (get_proof_name s g).Ident.id_string;
180
(*    for i=depth to max_depth-1 do fprintf fmt "<td></td>" done; *)
MARCHE Claude's avatar
MARCHE Claude committed
181
    print_results fmt s provers (get_proof_attempt_ids s g);
182
    fprintf fmt "</tr>@\n";
MARCHE Claude's avatar
MARCHE Claude committed
183 184 185
    List.iter
      (print_transf fmt s depth max_depth provers)
      (get_transformations s g)
186

MARCHE Claude's avatar
MARCHE Claude committed
187 188
  let print_theory s fn fmt th =
    let depth = theory_depth s th in
189
    if depth > 0 then
MARCHE Claude's avatar
MARCHE Claude committed
190
    let provers = get_used_provers_theory s th in
191
    let provers =
MARCHE Claude's avatar
MARCHE Claude committed
192
      Whyconf.Sprover.fold (fun pr acc -> pr :: acc) provers []
193 194
    in
    let provers = List.sort Whyconf.Prover.compare provers in
195 196
    let name =
      try
MARCHE Claude's avatar
MARCHE Claude committed
197
        let (l,t,_) = Theory.restore_path (theory_name th) in
198
        String.concat "." ([fn]@l@[t])
MARCHE Claude's avatar
MARCHE Claude committed
199
      with Not_found -> fn ^ "." ^ (theory_name th).Ident.id_string
200 201
    in
    fprintf fmt "<h2><font color=\"#%a\">Theory \"%s\": "
MARCHE Claude's avatar
MARCHE Claude committed
202
      (color_of_status ~dark:true) (th_proved s th)
203
      name;
MARCHE Claude's avatar
MARCHE Claude committed
204 205 206
    if th_proved s th then
      fprintf fmt "fully verified in %%.02f s"
    else fprintf fmt "not fully verified";
207
    fprintf fmt "</font></h2>@\n";
MARCHE Claude's avatar
MARCHE Claude committed
208

209
    fprintf fmt "<table border=\"1\"><tr><td colspan=\"%d\">Obligations</td>" depth;
MARCHE Claude's avatar
MARCHE Claude committed
210
    (* fprintf fmt "<table border=\"1\"><tr><td>Obligations</td>"; *)
211 212 213 214
    List.iter
      (fun pr -> fprintf fmt "<td text-rotation=\"90\">%a</td>" print_prover pr)
      provers;
    fprintf fmt "</td></tr>@\n";
MARCHE Claude's avatar
MARCHE Claude committed
215
    List.iter (print_goal fmt s true 1 depth provers) (theory_goals th);
216 217
    fprintf fmt "</table>@\n"

MARCHE Claude's avatar
MARCHE Claude committed
218
  let print_file s fmt f =
219
    (* fprintf fmt "<h1>File %s</h1>@\n" f.file_name; *)
MARCHE Claude's avatar
MARCHE Claude committed
220
    let fn = Filename.basename (file_name f) in
221
    let fn = Filename.chop_extension fn in
222
    fprintf fmt "%a"
MARCHE Claude's avatar
MARCHE Claude committed
223
      (Pp.print_list Pp.newline (print_theory s fn)) (file_theories f)
224 225 226 227

  let print_session name fmt s =
    fprintf fmt "<h1>Why3 Proof Results for Project \"%s\"</h1>@\n" name;
    fprintf fmt "%a"
MARCHE Claude's avatar
MARCHE Claude committed
228 229
      (Pp.print_iter2 Stdlib.Hstr.iter Pp.newline Pp.nothing Pp.nothing
         (print_file s)) (get_files s)
230 231


232 233 234 235 236 237 238 239 240 241 242
  let context : context = "<!DOCTYPE html\
PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\
<html xmlns=\"http://www.w3.org/1999/xhtml\">\
<head>\
<title>Why3 session of %s</title>\
</head>\
<body>\
%a\
</body>\
</html>\
243 244 245 246 247 248 249 250
"

  let run_one = run_file context print_session

end



251 252 253
module Simple =
struct

254
  let print_prover = Whyconf.print_prover
255 256

  let print_proof_status fmt = function
MARCHE Claude's avatar
MARCHE Claude committed
257 258 259 260 261
    | None -> fprintf fmt "No result"
    | Some res -> fprintf fmt "Done: %a" Call_provers.print_prover_result res

  let print_proof_attempt s fmt pa =
    let pa = get_proof_attempt_node s pa in
262
    fprintf fmt "<li>%a : %a</li>"
MARCHE Claude's avatar
MARCHE Claude committed
263
      print_prover pa.prover
264 265
      print_proof_status pa.proof_state

MARCHE Claude's avatar
MARCHE Claude committed
266 267 268
  let rec print_transf s fmt tr =
    let name = (get_transf_name s tr) ^
                 (String.concat "" (get_transf_args s tr)) in
269
    fprintf fmt "<li>%s : <ul>%a</ul></li>"
MARCHE Claude's avatar
MARCHE Claude committed
270 271
      name
      (Pp.print_list Pp.newline (print_goal s)) (get_sub_tasks s tr)
272

MARCHE Claude's avatar
MARCHE Claude committed
273
  and print_goal s fmt g =
274
    fprintf fmt "<li>%s : <ul>%a%a</ul></li>"
MARCHE Claude's avatar
MARCHE Claude committed
275 276 277 278 279 280 281 282
      (get_proof_name s g).Ident.id_string
      (Pp.print_iter2 Hprover.iter Pp.newline Pp.nothing
         Pp.nothing (print_proof_attempt s))
      (get_proof_attempt_ids s g)
      (Pp.print_iter1 List.iter Pp.newline (print_transf s))
      (get_transformations s g)

  let print_theory s fmt th =
283
    fprintf fmt "<li>%s : <ul>%a</ul></li>"
MARCHE Claude's avatar
MARCHE Claude committed
284 285
      (theory_name th).Ident.id_string
      (Pp.print_list Pp.newline (print_goal s)) (theory_goals th)
286

MARCHE Claude's avatar
MARCHE Claude committed
287
  let print_file s fmt f =
288
    fprintf fmt "<li>%s : <ul>%a</ul></li>"
MARCHE Claude's avatar
MARCHE Claude committed
289 290
      (file_name f)
      (Pp.print_list Pp.newline (print_theory s)) (file_theories f)
291 292 293

  let print_session _name fmt s =
    fprintf fmt "<ul>%a</ul>"
MARCHE Claude's avatar
MARCHE Claude committed
294 295
      (Pp.print_iter2 Stdlib.Hstr.iter Pp.newline Pp.nothing Pp.nothing
         (print_file s)) (get_files s)
296 297


298 299 300 301 302 303 304 305 306 307 308
  let context : context = "<!DOCTYPE html\
PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\
<html xmlns=\"http://www.w3.org/1999/xhtml\">\
<head>\
<title>Why3 session of %s</title>\
</head>\
<body>\
%a\
</body>\
</html>\
309
"
310

311
  let run_one = run_file context print_session
312

313
end
314

315

316
let run () =
317
  let _,_,should_exit1 = read_env_spec () in
318
  if should_exit1 then exit 1;
319 320 321
  match !opt_style with
    | Table -> iter_files Table.run_one
    | SimpleTree -> iter_files Simple.run_one
322 323 324

let cmd =
  { cmd_spec = spec;
325
    cmd_desc = "output session in HTML format";
326 327 328
    cmd_name = "html";
    cmd_run  = run;
  }
329 330 331 332 333 334 335


(*
Local Variables:
compile-command: "unset LANG; make -C ../.. bin/why3session.byte"
End:
*)