File: pprinter.ml

package info (click to toggle)
why 2.13-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 12,608 kB
  • ctags: 16,817
  • sloc: ml: 102,672; java: 7,173; ansic: 4,439; makefile: 1,409; sh: 585
file content (404 lines) | stat: -rwxr-xr-x 13,095 bytes parent folder | download
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
(**************************************************************************)
(*                                                                        *)
(*  The Why platform for program certification                            *)
(*  Copyright (C) 2002-2008                                               *)
(*    Romain BARDOU                                                       *)
(*    Jean-Franois COUCHOT                                               *)
(*    Mehdi DOGGUY                                                        *)
(*    Jean-Christophe FILLITRE                                           *)
(*    Thierry HUBERT                                                      *)
(*    Claude MARCH                                                       *)
(*    Yannick MOY                                                         *)
(*    Christine PAULIN                                                    *)
(*    Yann RGIS-GIANAS                                                   *)
(*    Nicolas ROUSSET                                                     *)
(*    Xavier URBAIN                                                       *)
(*                                                                        *)
(*  This software is free software; you can redistribute it and/or        *)
(*  modify it under the terms of the GNU General Public                   *)
(*  License version 2, as published by the Free Software Foundation.      *)
(*                                                                        *)
(*  This software is distributed in the hope that it will be useful,      *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                  *)
(*                                                                        *)
(*  See the GNU General Public License version 2 for more details         *)
(*  (enclosed in the file GPL).                                           *)
(*                                                                        *)
(**************************************************************************)

open Options
open Misc
open Vcg
open Logic
open Cc
open Format
open Colors
open Tagsplit
open Tags

let obligs = Hashtbl.create 5501
let pprinter = Hashtbl.create 5501
let files = Hashtbl.create 10
let last_fct = ref ""
let last_line = ref 0
let last_file = ref ""
let pwd = Sys.getcwd ()
let source = ref ""
let tv_source = ref (GText.view ())

let active = ref true
let desactivate () = active := false
let activate () = active := true
let swap_active () = active := not !active
let is_active () = !active

let set_tvsource tvs = tv_source := tvs

let reset_last_file () = 
  last_file := ""

let print_loc = function 
  | None -> "\"nowhere\""
  | Some {file=f; line=l; sp=s; ep=e} ->
      let ff = if Filename.is_relative f then Filename.concat pwd f else f in
      ("file \""^ff^"\", line "^l^", characters "^s^" - "^e)

let is_cfile f = 
  Filename.check_suffix f ".c" or Filename.check_suffix f ".h"
  (* otherwise it's .why *)

let read_file = function 
  | None -> ()
  | Some {file=f} ->
      try
	let in_channel = open_in f in
	begin 
	  try
            let lexbuf = Lexing.from_channel in_channel 
	    and hilight = 
	      if is_cfile f then Hilight.token else Whyhilight.scan 
	    in
            while true do hilight !tv_source#buffer lexbuf done
	  with Hilight.Eof | Whyhilight.Eof -> ()
	end;
      with Sys_error s -> 
	begin
	  print_endline ("     [...] Sys_error : "^s); flush stdout;
	  !tv_source#buffer#set_text "" 
	end

let hypo = (* Model : HW_11 *)
  let r_hyp = Str.regexp "\\HW_\\([0-9]+\\)" in
  fun s ->
    if Str.string_match r_hyp s 0 then
      (Str.matched_group 1 s)
    else
      s

let hypothesis s = 
  "H"^(hypo s)

let grab_infos = 
  let r_loc = Str.regexp "File \"\\(.+\\)\", line \\([0-9]+\\), characters \\([0-9]+\\)-\\([0-9]+\\)" in
  fun s -> 
    if Str.string_match r_loc s 0 then 
      let source = Filename.concat pwd (Str.matched_group 1 s) in
      Some({file=source;
            line=(Str.matched_group 2 s);
            sp=(Str.matched_group 3 s);
            ep=(Str.matched_group 4 s)})
    else None
      
let is_localised = function 
  | None -> false
  | Some _ -> true

let move_to_line line = 
  if line <= !tv_source#buffer#line_count && line <> 0 then begin
    let it = !tv_source#buffer#get_iter (`LINE line) in 
    let mark = `MARK (!tv_source#buffer#create_mark it) 
    (* and y = if !tv_source#buffer#line_count < 20 then 0.23 else 0.1  *)
    in
    !tv_source#scroll_to_mark ~use_align:true ~yalign:0.5 mark;
    if debug then
      begin 
	print_endline ("     [...] Moving to line n "^(string_of_int line)); 
	flush stdout 
      end
  end

let color_tag_table = Hashtbl.create 17

let color_loc file (tv:GText.view) l b e =
  let buf = tv#buffer in
  let orange_bg = 
    try
      Hashtbl.find color_tag_table file
    with Not_found ->
      let t = buf#create_tag ~name:"orange_bg" [`BACKGROUND "orange"] in
      Hashtbl.add color_tag_table file t;
      t
  in
  buf#remove_tag orange_bg ~start:buf#start_iter ~stop:buf#end_iter;
  let top = buf#start_iter in
  let start = top#forward_lines (l-1) in
  let start = start#forward_chars b in
  let stop = start#forward_chars (e-b) in
  buf#apply_tag ~start ~stop orange_bg
  

let banner () =
"

Welcome to GWhy (the Graphical VC viewer for the Why platform)
This is Why version " ^ Version.version ^ 
", compiled on " ^ Version.date ^ "
Copyright (c) 2002-2007 ProVal team, INRIA
This is free software with ABSOLUTELY NO WARRANTY (use option -warranty)"

let move_to_source = function
  | None -> 
      last_file := "";
      begin
	try
	  !tv_source#set_buffer (Hashtbl.find files "")
	with Not_found ->
	  !tv_source#set_buffer (GText.buffer ());
	  let b = !tv_source#buffer in
	  b#set_text (banner());
	  begin
	    try
	      let why_logo_image = Options.lib_file "why-logo-1.png" in
	      let why_logo = GdkPixbuf.from_file why_logo_image in
	      b#insert_pixbuf ~iter:b#start_iter ~pixbuf:why_logo 
	    with _ -> 
	      b#insert ~iter:b#start_iter "(Why logo: image not found)"	      
	  end;
	  b#insert ~iter:b#start_iter "\n\t";
	  Hashtbl.add files "" b
      end
  | Some loc ->
      let line = int_of_string loc.line
      and file = loc.file in
      last_line := line;
      if !last_file = file then 
	move_to_line line
      else begin 
	last_file := file;
	if (Hashtbl.mem files file) && (not (Colors.has_changed ())) then 
	  !tv_source#set_buffer (Hashtbl.find files file)
	else begin
	  !tv_source#set_buffer (GText.buffer ());
	  read_file (Some loc);
	  Hashtbl.add files file !tv_source#buffer;
	  Hashtbl.remove color_tag_table file;
	end;
	move_to_line line
      end

 
let move_to_loc loc =
  move_to_source (Some loc);
  color_loc loc.file !tv_source (int_of_string loc.line) 
    (int_of_string loc.sp) (int_of_string loc.ep)

let rec intros ctx = function 
  | Forall (true, id, n, t, _, p) ->
      let id' = Ident.next_away id (predicate_vars p) in
      let p' = subst_in_predicate (subst_onev n id') p in
      let ctx', concl' = intros (Svar (id', t) :: ctx) p' in
      ctx', concl'
  | Pimplies (true, a, b) -> 
      let h = fresh_hyp () in 
      let ctx', concl' = intros (Spred (h, a) :: ctx) b in
      ctx', concl'
  (* TODO: Pnamed ? *)
  | c -> 
      ctx, c

let create_tag (tbuf:GText.buffer) t loc = 
  if not (Hashtbl.mem gtktags t) then begin
    let (fc, bc) = get_color "lpredicate" in
    let new_tag = tbuf#create_tag [`BACKGROUND bc; `FOREGROUND fc] in
    ignore(
      new_tag#connect#event ~callback:
	(fun ~origin ev it -> 
	   if GdkEvent.get_type ev = `BUTTON_PRESS then 
	     move_to_source (Some loc)
	   else if GdkEvent.get_type ev = `MOTION_NOTIFY then begin
	     Tags.refresh_last_colored [new_tag];
	     new_tag#set_properties 
	       [`BACKGROUND (get_bc "pr_hilight"); 
		`FOREGROUND (get_fc "pr_hilight")]
	   end;
	   false));
    add_gtktag t new_tag
  end

let create_all_tags (tbuf:GText.buffer) = 
  Hashtbl.iter (create_tag tbuf) Tags.loctags

let print_oblig fmt (ctx,concl) = 
  let print_pure_type, print_predicate = 
    if is_active () 
    then Astprinter.print_pure_type, Astpprinter.print_predicate
    else Astprinter.print_pure_type, Astnprinter.print_predicate
  in 
  let ctx, concl = intros ctx concl in
  let rec print_list print = function
    | [] -> ()
    | p::r -> print p; fprintf fmt "@\n"; print_list print r 
  and print_name fmt id =
    let hypo_nb = hypo (Ident.string id) in
    fprintf fmt "%s" (hypothesis hypo_nb)
  and print_hyp fmt = function
    | Svar (id, t) ->
	fprintf fmt "@[@{<var>%a:@}@ @{<cc_type>%a@}@]" 
	  Ident.print id print_pure_type t
    | Spred (id, p) ->
	fprintf fmt "@[@{<hypothesis>%a:@} @{<predicate>%a@}@]" 
	  print_name id print_predicate p
  in
  print_list (print_hyp fmt) ctx

let is_buffer_saved = 
  Hashtbl.mem obligs

let save_buffer s (tbuf:GText.buffer) pprint = 
  Hashtbl.replace obligs s tbuf;
  Hashtbl.replace pprinter s pprint

let get_buffer = 
  Hashtbl.find obligs

let color_lines tags =
  let buf = !tv_source#buffer in
  let top = buf#start_iter in
  let orange_bg = buf#create_tag ~name:"orange_bg" [`BACKGROUND "orange"] in
  (*
  buf#remove_tag_by_name ~start:buf#start_iter ~stop:buf#end_iter "orange_bg";
  *)
  let color_one t = 
    let loc = Hashtbl.find loctags t in
    let l = int_of_string loc.line in
    let start = top#forward_lines l in
    let stop = start#forward_line in
    buf#apply_tag ~start ~stop orange_bg
  in
  List.iter color_one tags
  
let print_all (tbuf:GText.buffer) s p = 
  insert_text tbuf "title" (s^"\n\n");
  (* 1. we print the text in a string, which fills the table loctags *)
  let fmt = Format.str_formatter in
  pp_set_tags fmt true;
  let str = 
    fprintf fmt "@[%a@]" print_oblig p;
    flush_str_formatter ()
  in
  (* 2. then we create the GTK tags and map them to the tag names *)
  create_all_tags tbuf;
  (* 3. then we fill the GTK text buffer using Tagsplit.split *)
  let _utags = split tbuf (Lexing.from_string str) in
  let (_,concl) = p in
  let mytag = 
    tbuf#create_tag
      [`UNDERLINE `DOUBLE;
       `FOREGROUND (get_fc "separator"); 
       `BACKGROUND (get_bc "separator")] 
  in
  tbuf#insert ~tags:[mytag] ~iter:tbuf#end_iter 
    "_                                                        _\n\n";
  let conclusion = 
    let print_predicate = 
      if is_active () 
      then Astpprinter.print_predicate
      else Astnprinter.print_predicate
    in 
    fprintf fmt "@[@{<conclusion>%a@}@]" print_predicate concl;
    create_all_tags tbuf;
    flush_str_formatter () 
  in
  let _utags' = split tbuf (Lexing.from_string conclusion) in
  (*color_lines (utags @ utags');*)
  ()

let unchanged s pprint = 
  (not (Colors.has_changed ())) &&
  (is_buffer_saved s) 
  && (try 
	(Hashtbl.find pprinter s) = pprint
      with Not_found -> pprint)

let is_ident_char s = String.length s = 1 && match s.[0] with
  | 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' -> true
  | _ -> false

let show_definition (tv:GText.view) (tv_s:GText.view) = 
  let buf = tv#buffer in
  let find_backward (it:GText.iter) = 
    let rec find start stop = 
      if start = buf#start_iter then
	start 
      else
	let c = buf#get_text ~start ~stop () in
	if is_ident_char c then find (start#backward_char) start else stop
    in 
    find (it#backward_char) it
  in
  let find_forward (it:GText.iter) = 
    let rec find start stop = 
      if stop = buf#end_iter then
	stop
      else
	let c = buf#get_text ~start ~stop () in
	if is_ident_char c then find stop (stop#forward_char) else start
    in 
    find it (it#forward_char)
  in
  let buf = tv#buffer in
  let win = match tv#get_window `WIDGET with
    | None -> assert false
    | Some w -> w
  in
  let x,y = Gdk.Window.get_pointer_location win in
  let b_x,b_y = tv#window_to_buffer_coords ~tag:`WIDGET ~x ~y in
  let it = tv#get_iter_at_location ~x:b_x ~y:b_y in
  let start = if (it = buf#start_iter) then it else find_backward it in
  let stop = if (it = buf#end_iter) then it else find_forward it in
  let text = buf#get_text ~start ~stop () in
  if start <> stop && text <> "" then begin
    try 
      let (f,l,b,e) = Loc.ident text in
      let loc = {file=f; 
		 line=(string_of_int l); 
		 sp=(string_of_int b); 
		 ep=(string_of_int e)} 
      in 
      (*
       * print_endline (text ^ "  " ^ (print_loc (Some(loc)))); 
       * flush stdout;
       *)
      move_to_source (Some loc)
    with Not_found -> ()
  end
    
let text_of_obligation (tv:GText.view) (o,expl,s,p) = 
  let p = p.Env.scheme_type in
  last_fct := s;
  if (unchanged s (is_active ())) then 
    tv#set_buffer (get_buffer s)
  else begin
    let tbuf = GText.buffer () in
    tv#set_buffer tbuf;
    let _ = 
      tv#event#connect#button_release 
	~callback:(fun ev -> 
		     if GdkEvent.Button.button ev = 3 then
		       show_definition tv !tv_source; 
		     false)
    in
    print_all tbuf s p;
    save_buffer s tbuf (is_active ());
  end