register.ml 32.64 KiB
(**************************************************************************)
(* *)
(* This file is part of WP plug-in of Frama-C. *)
(* *)
(* Copyright (C) 2007-2019 *)
(* CEA (Commissariat a l'energie atomique et aux energies *)
(* alternatives) *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License as published by the Free Software *)
(* Foundation, version 2.1. *)
(* *)
(* It 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 Lesser General Public License for more details. *)
(* *)
(* See the GNU Lesser General Public License version 2.1 *)
(* for more details (enclosed in the file licenses/LGPLv2.1). *)
(* *)
(**************************************************************************)
open Factory
let dkey_main = Wp_parameters.register_category "main"
let dkey_raised = Wp_parameters.register_category "raised"
let dkey_shell = Wp_parameters.register_category "shell"
(* --------- Command Line ------------------- *)
let cmdline () : setup =
begin
match Wp_parameters.Model.get () with
| ["Runtime"] ->
Wp_parameters.abort
"Model 'Runtime' is no more available.@\nIt will be reintroduced \
in a future release."
| ["Logic"] ->
Wp_parameters.warning ~once:true
"Deprecated 'Logic' model.@\nUse 'Typed' with option '-wp-ref' \
instead." ;
{
mheap = Factory.Typed MemTyped.Fits ;
mvar = Factory.Ref ;
cint = Cint.Natural ;
cfloat = Cfloat.Real ;
}
| ["Store"] ->
Wp_parameters.warning ~once:true
"Deprecated 'Store' model.@\nUse 'Typed' instead." ;
{
mheap = Factory.Typed MemTyped.Fits ;
mvar = Factory.Var ;
cint = Cint.Natural ;
cfloat = Cfloat.Real ;
}
| spec -> Factory.parse spec
end
let set_model (s:setup) =
Wp_parameters.Model.set [Factory.ident s]
(* --------- WP Computer -------------------- *)
let computer () =
if Wp_parameters.Model.get () = ["Dump"]
then CfgDump.create ()
else CfgWP.computer (cmdline ()) (Driver.load_driver ())
(* ------------------------------------------------------------------------ *)
(* --- Memory Model Hypotheses --- *)
(* ------------------------------------------------------------------------ *)
module Models = Set.Make(WpContext.MODEL)
module Fmap = Kernel_function.Map
let wp_iter_model ?ip ?index job =
begin
let pool : Models.t Fmap.t ref = ref Fmap.empty in
Wpo.iter ?ip ?index ~on_goal:(fun wpo ->
match Wpo.get_index wpo with
| Wpo.Axiomatic _ -> ()
| Wpo.Function(kf,_) ->
let m = Wpo.get_model wpo in
let ms = try Fmap.find kf !pool with Not_found -> Models.empty in
if not (Models.mem m ms) then
pool := Fmap.add kf (Models.add m ms) !pool ;
) () ;
Fmap.iter (fun kf ms -> Models.iter (fun m -> job kf m) ms) !pool
end
let wp_print_memory_context kf m hyp fmt =
begin
let printer = new Printer.extensible_printer () in
let pp_vdecl = printer#without_annot printer#vdecl in
Format.fprintf fmt
"@[<hv 0>@[<hv 3>/*@@@ behavior %s:" (WpContext.MODEL.id m) ;
List.iter (MemoryContext.pp_clause fmt) hyp ;
let vkf = Kernel_function.get_vi kf in
Format.fprintf fmt "@ @]*/@]@\n@[<hov 2>%a;@]@\n"
pp_vdecl vkf ;
end
let wp_warn_memory_context () =
begin
wp_iter_model
begin fun kf m ->
let hyp = WpContext.compute_hypotheses m kf in
if hyp <> [] then
Wp_parameters.warning
~current:false
"@[<hv 0>Memory model hypotheses for function '%s':@ %t@]"
(Kernel_function.get_name kf)
(wp_print_memory_context kf m hyp)
end
end
(* ------------------------------------------------------------------------ *)
(* --- Printing informations --- *)
(* ------------------------------------------------------------------------ *)
let do_wp_print () =
(* Printing *)
if Wp_parameters.Print.get () then
try
Wpo.iter ~on_goal:(fun _ -> raise Exit) () ;
Wp_parameters.result "No proof obligations"
with Exit ->
Log.print_on_output
(fun fmt ->
Wpo.iter
~on_axiomatics:(Wpo.pp_axiomatics fmt)
~on_behavior:(Wpo.pp_function fmt)
~on_goal:(Wpo.pp_goal_flow fmt) ())
let do_wp_print_for goals =
if Wp_parameters.Print.get () then
if Bag.is_empty goals
then Wp_parameters.result "No proof obligations"
else Log.print_on_output
(fun fmt -> Bag.iter (Wpo.pp_goal_flow fmt) goals)
let do_wp_report () =
begin
let reports = Wp_parameters.Report.get () in
let jreport = Wp_parameters.ReportJson.get () in
if reports <> [] || jreport <> "" then
begin
let stats = WpReport.fcstat () in
begin
match String.split_on_char ':' jreport with
| [] | [""] -> ()
| [joutput] ->
WpReport.export_json stats ~joutput () ;
| [jinput;joutput] ->
WpReport.export_json stats ~jinput ~joutput () ;
| _ ->
Wp_parameters.error "Invalid format for option -wp-report-json"
end ;
List.iter (WpReport.export stats) reports ;
end ;
if Wp_parameters.MemoryContext.get () then
wp_warn_memory_context ()
end
(* ------------------------------------------------------------------------ *)
(* --- Wp Results --- *)
(* ------------------------------------------------------------------------ *)
let pp_warnings fmt wpo =
let ws = Wpo.warnings wpo in
if ws <> [] then
let n = List.length ws in
let s = List.exists (fun w -> w.Warning.severe) ws in
begin
match s , n with
| true , 1 -> Format.fprintf fmt " (Degenerated)"
| true , _ -> Format.fprintf fmt " (Degenerated, %d warnings)" n
| false , 1 -> Format.fprintf fmt " (Stronger)"
| false , _ -> Format.fprintf fmt " (Stronger, %d warnings)" n
end
let launch task =
let server = ProverTask.server () in
(** Do on_server_stop save why3 session *)
Task.spawn server (Task.thread task) ;
Task.launch server
(* ------------------------------------------------------------------------ *)
(* --- Prover Stats --- *)
(* ------------------------------------------------------------------------ *)
let do_wpo_display goal =
let result = if Wpo.is_trivial goal then "trivial" else "not tried" in
Wp_parameters.feedback "Goal %s : %s" (Wpo.get_gid goal) result
module PM =
FCMap.Make(struct
type t = VCS.prover
let compare = VCS.cmp_prover
end)
type pstat = {
mutable proved : int ;
mutable unknown : int ;
mutable interrupted : int ;
mutable incache : int ;
mutable failed : int ;
mutable n_time : int ; (* nbr of measured times *)
mutable a_time : float ; (* sum of measured times *)
mutable u_time : float ; (* max time *)
mutable d_time : float ; (* min time *)
mutable steps : int ;
}
module GOALS = Wpo.S.Set
let scheduled = ref 0
let exercised = ref 0
let spy = ref false
let session = ref GOALS.empty
let proved = ref GOALS.empty
let provers = ref PM.empty
let begin_session () = session := GOALS.empty ; spy := true
let clear_session () = session := GOALS.empty
let end_session () = session := GOALS.empty ; spy := false
let iter_session f = GOALS.iter f !session
let clear_scheduled () =
begin
scheduled := 0 ;
exercised := 0 ;
proved := GOALS.empty ;
provers := PM.empty ;
end
let get_pstat p =
try PM.find p !provers with Not_found ->
let s = {
proved = 0 ;
unknown = 0 ;
interrupted = 0 ;
failed = 0 ;
steps = 0 ;
incache = 0 ;
n_time = 0 ;
a_time = 0.0 ;
u_time = 0.0 ;
d_time = max_float ;
} in provers := PM.add p s !provers ; s
let add_step s n =
if n > s.steps then s.steps <- n
let add_time s t =
if t > 0.0 then
begin
s.n_time <- succ s.n_time ;
s.a_time <- t +. s.a_time ;
if t < s.d_time then s.d_time <- t ;
if t > s.u_time then s.u_time <- t ;
end
let do_list_scheduled iter_on_goals =
if not (Wp_parameters.has_dkey VCS.dkey_no_goals_info) then
begin
clear_scheduled () ;
iter_on_goals
(fun goal ->
begin
incr scheduled ;
if !spy then session := GOALS.add goal !session ;
end) ;
let n = !scheduled in
if n > 1
then Wp_parameters.feedback "%d goals scheduled" n
else Wp_parameters.feedback "%d goal scheduled" n ;
end
let dkey_prover = Wp_parameters.register_category "prover"
let do_wpo_start goal =
begin
incr exercised ;
if Wp_parameters.has_dkey dkey_prover then
Wp_parameters.feedback "[Qed] Goal %s preprocessing" (Wpo.get_gid goal) ;
end
let do_wpo_wait () =
Wp_parameters.feedback ~ontty:`Transient "[wp] Waiting provers..."
let do_progress goal msg =
begin
if !scheduled > 0 then
let pp = int_of_float (100.0 *. float !exercised /. float !scheduled) in
let pp = max 0 (min 100 pp) in
Wp_parameters.feedback ~ontty:`Transient "[%02d%%] %s (%s)"
pp goal.Wpo.po_sid msg ;
end
(* ------------------------------------------------------------------------ *)
(* --- Caching --- *)
(* ------------------------------------------------------------------------ *)
let do_report_cache_usage mode =
if !exercised > 0 &&
not (Wp_parameters.has_dkey dkey_shell) &&
not (Wp_parameters.has_dkey VCS.dkey_no_cache_info)
then
let hits = ProverWhy3.get_hits () in
let miss = ProverWhy3.get_miss () in
if hits <= 0 && miss <= 0 then
Wp_parameters.result "[Cache] not used"
else
Wp_parameters.result "[Cache]%t"
begin fun fmt ->
let sep = ref " " in
let pp_cache fmt n job =
if n > 0 then
( Format.fprintf fmt "%s%s:%d" !sep job n ; sep := ", " ) in
match mode with
| ProverWhy3.NoCache -> ()
| ProverWhy3.Replay ->
pp_cache fmt hits "found" ;
pp_cache fmt miss "missed" ;
Format.pp_print_newline fmt () ;
| ProverWhy3.Offline ->
pp_cache fmt hits "found" ;
pp_cache fmt miss "failed" ;
Format.pp_print_newline fmt () ;
| ProverWhy3.Update | ProverWhy3.Cleanup ->
pp_cache fmt hits "found" ;
pp_cache fmt miss "updated" ;
Format.pp_print_newline fmt () ;
| ProverWhy3.Rebuild ->
pp_cache fmt hits "replaced" ;
pp_cache fmt miss "updated" ;
Format.pp_print_newline fmt () ;
end
(* -------------------------------------------------------------------------- *)
(* --- Prover Results --- *)
(* -------------------------------------------------------------------------- *)
let do_wpo_stat goal prover res =
let s = get_pstat prover in
let open VCS in
if res.cached then s.incache <- succ s.incache ;
match res.verdict with
| Checked | NoResult | Computing _ | Invalid | Unknown ->
s.unknown <- succ s.unknown
| Stepout | Timeout ->
s.interrupted <- succ s.interrupted
| Failed ->
s.failed <- succ s.failed
| Valid ->
if not (Wpo.is_tactic goal) then
proved := GOALS.add goal !proved ;
s.proved <- succ s.proved ;
add_step s res.prover_steps ;
add_time s res.prover_time ;
if prover <> Qed then
add_time (get_pstat Qed) res.solver_time
let do_wpo_result goal prover res =
if VCS.is_verdict res then
begin
if Wp_parameters.Check.get () then
begin
let open VCS in
let ontty = if res.verdict = Checked then `Feedback else `Message in
Wp_parameters.feedback ~ontty
"[%a] Goal %s : %a"
VCS.pp_prover prover (Wpo.get_gid goal)
VCS.pp_result res ;
end ;
if prover = VCS.Qed then do_progress goal "Qed" ;
do_wpo_stat goal prover res ;
end
let do_wpo_success goal s =
if not (Wp_parameters.Check.get ()) then
if Wp_parameters.Generate.get () then
match s with
| None -> ()
| Some prover ->
Wp_parameters.feedback ~ontty:`Silent
"[%a] Goal %s : Valid" VCS.pp_prover prover (Wpo.get_gid goal)
else
match s with
| None ->
begin
match Wpo.get_results goal with
| [p,r] ->
Wp_parameters.result "[%a] Goal %s : %a%a"
VCS.pp_prover p (Wpo.get_gid goal)
VCS.pp_result r pp_warnings goal
| pres ->
Wp_parameters.result "[Failed] Goal %s%t" (Wpo.get_gid goal)
begin fun fmt ->
pp_warnings fmt goal ;
List.iter
(fun (p,r) ->
Format.fprintf fmt "@\n%8s: @[<hv>%a@]"
(VCS.title_of_prover p) VCS.pp_result r
) pres ;
end
end
| Some (VCS.Tactical as p) ->
Wp_parameters.feedback ~ontty:`Silent
"[%a] Goal %s : Valid"
VCS.pp_prover p (Wpo.get_gid goal)
| Some p ->
let r = Wpo.get_result goal p in
Wp_parameters.feedback ~ontty:`Silent
"[%a] Goal %s : %a"
VCS.pp_prover p (Wpo.get_gid goal)
VCS.pp_result r
let do_report_time fmt s =
begin
if s.n_time > 0 &&
s.u_time > Rformat.epsilon &&
not (Wp_parameters.has_dkey VCS.dkey_no_time_info) &&
not (Wp_parameters.has_dkey VCS.dkey_success_only)
then
let mean = s.a_time /. float s.n_time in
let epsilon = 0.05 *. mean in
let delta = s.u_time -. s.d_time in
if delta < epsilon then
Format.fprintf fmt " (%a)" Rformat.pp_time mean
else
let middle = (s.u_time +. s.d_time) *. 0.5 in
if abs_float (middle -. mean) < epsilon then
Format.fprintf fmt " (%a-%a)"
Rformat.pp_time s.d_time
Rformat.pp_time s.u_time
else
Format.fprintf fmt " (%a-%a-%a)"
Rformat.pp_time s.d_time
Rformat.pp_time mean
Rformat.pp_time s.u_time
end
let do_report_steps fmt s =
begin
if s.steps > 0 &&
not (Wp_parameters.has_dkey VCS.dkey_no_step_info) &&
not (Wp_parameters.has_dkey VCS.dkey_success_only)
then
Format.fprintf fmt " (%d)" s.steps ;
end
let do_report_stopped fmt s =
if Wp_parameters.has_dkey VCS.dkey_success_only then
begin
let n = s.interrupted + s.unknown in
if n > 0 then
Format.fprintf fmt " (unsuccess: %d)" n ;
end
else
begin
if s.interrupted > 0 then
Format.fprintf fmt " (interrupted: %d)" s.interrupted ;
if s.unknown > 0 then
Format.fprintf fmt " (unknown: %d)" s.unknown ;
if s.incache > 0 then
Format.fprintf fmt " (cached: %d)" s.incache ;
end
let do_report_prover_stats pp_prover fmt (p,s) =
begin
let name = VCS.title_of_prover p in
Format.fprintf fmt "%a %4d " pp_prover name s.proved ;
do_report_time fmt s ;
do_report_steps fmt s ;
do_report_stopped fmt s ;
if s.failed > 0 then
Format.fprintf fmt " (failed: %d)" s.failed ;
Format.fprintf fmt "@\n" ;
end
let do_report_scheduled () =
if not (Wp_parameters.has_dkey VCS.dkey_no_goals_info) then
if Wp_parameters.Generate.get () then
let plural = if !exercised > 1 then "s" else "" in
Wp_parameters.result "%d goal%s generated" !exercised plural
else
let proved = GOALS.cardinal !proved in
let mode = ProverWhy3.get_mode () in
if mode <> ProverWhy3.NoCache then do_report_cache_usage mode ;
Wp_parameters.result "%t"
begin fun fmt ->
Format.fprintf fmt "Proved goals: %4d / %d@\n" proved !scheduled ;
Pretty_utils.pp_items
~min:12 ~align:`Left
~title:(fun (prover,_) -> VCS.title_of_prover prover)
~iter:(fun f -> PM.iter (fun p s -> f (p,s)) !provers)
~pp_title:(fun fmt a -> Format.fprintf fmt "%s:" a)
~pp_item:do_report_prover_stats fmt ;
end
let do_list_scheduled_result () =
begin
do_report_scheduled () ;
clear_scheduled () ;
end
(* ------------------------------------------------------------------------ *)
(* --- Proving --- *)
(* ------------------------------------------------------------------------ *)
type mode = {
mutable tactical : bool ;
mutable update : bool ;
mutable depth : int ;
mutable width : int ;
mutable backtrack : int ;
mutable auto : Strategy.heuristic list ;
mutable provers : (VCS.mode * VCS.prover) list ;
}
let spawn_wp_proofs_iter ~mode iter_on_goals =
if mode.tactical || mode.provers<>[] then
begin
let server = ProverTask.server () in
ignore (Wp_parameters.Share.dir ()); (* To prevent further errors *)
iter_on_goals
(fun goal ->
if mode.tactical
&& not (Wpo.is_trivial goal)
&& (mode.auto <> [] || ProofSession.exists goal)
then
ProverScript.spawn
~failed:false
~auto:mode.auto
~depth:mode.depth
~width:mode.width
~backtrack:mode.backtrack
~provers:(List.map snd mode.provers)
~start:do_wpo_start
~progress:do_progress
~result:do_wpo_result
~success:do_wpo_success
goal
else
Prover.spawn goal
~delayed:false
~start:do_wpo_start
~progress:do_progress
~result:do_wpo_result
~success:do_wpo_success
mode.provers
) ;
Task.on_server_wait server do_wpo_wait ;
Task.launch server
end
let get_prover_names () =
match Wp_parameters.Provers.get () with [] -> [ "alt-ergo" ] | pnames -> pnames
let compute_provers ~mode =
mode.provers <- List.fold_right
(fun pname prvs ->
match VCS.prover_of_name pname with
| None -> prvs
| Some VCS.Tactical ->
mode.tactical <- true ;
if pname = "tip" then mode.update <- true ;
prvs
| Some prover ->
(VCS.mode_of_prover_name pname , prover) :: prvs)
(get_prover_names ()) []
let dump_strategies =
let once = ref true in
fun () ->
if !once then
( once := false ;
Wp_parameters.result "Registered strategies for -wp-auto:%t"
(fun fmt ->
Strategy.iter (fun h ->
Format.fprintf fmt "@\n '%s': %s" h#id h#title
)))
let default_mode () = {
tactical = false ; update=false ; provers = [] ;
depth=0 ; width = 0 ; auto=[] ; backtrack = 0 ;
}
let compute_auto ~mode =
mode.auto <- [] ;
mode.width <- Wp_parameters.AutoWidth.get () ;
mode.depth <- Wp_parameters.AutoDepth.get () ;
mode.backtrack <- max 0 (Wp_parameters.BackTrack.get ()) ;
let auto = Wp_parameters.Auto.get () in
if mode.depth <= 0 || mode.width <= 0 then
( if auto <> [] then
Wp_parameters.feedback
"Auto-search deactivated because of 0-depth or 0-width" )
else
begin
List.iter
(fun id ->
if id = "?" then dump_strategies ()
else
try mode.auto <- Strategy.lookup ~id :: mode.auto
with Not_found ->
Wp_parameters.error ~current:false
"Strategy -wp-auto '%s' unknown (ignored)." id
) auto ;
mode.auto <- List.rev mode.auto ;
if mode.auto <> [] then mode.tactical <- true ;
end
let do_update_session mode iter =
if mode.update then
begin
let removed = ref 0 in
let updated = ref 0 in
let invalid = ref 0 in
iter
begin fun goal ->
let results = Wpo.get_results goal in
let autoproof (p,r) =
(p=VCS.Qed) || (VCS.is_auto p && VCS.is_valid r && VCS.autofit r) in
if List.exists autoproof results then
begin
if ProofSession.exists goal then
(incr removed ; ProofSession.remove goal)
end
else
let scripts = ProofEngine.script (ProofEngine.proof ~main:goal) in
if scripts <> [] then
begin
let keep = function
| ProofScript.Prover(p,r) -> VCS.is_auto p && VCS.is_valid r
| ProofScript.Tactic(n,_,_) -> n=0
| ProofScript.Error _ -> false in
let strategy = List.filter keep scripts in
if strategy <> [] then
begin
incr updated ;
ProofSession.save goal (ProofScript.encode strategy)
end
else
if not (ProofSession.exists goal) then
begin
incr invalid ;
ProofSession.save goal (ProofScript.encode scripts)
end
end
end ;
let r = !removed in
let u = !updated in
let f = !invalid in
( if r = 0 && u = 0 && f = 0 then
Wp_parameters.result "No updated script." ) ;
( if r > 0 then
let s = if r > 1 then "s" else "" in
Wp_parameters.result "Updated session with %d new automated proof%s." r s );
( if u > 0 then
let s = if u > 1 then "s" else "" in
Wp_parameters.result "Updated session with %d new valid script%s." u s ) ;
( if f > 0 then
let s = if f > 1 then "s" else "" in
Wp_parameters.result "Updated session with %d new script%s to complete." f s );
end
let do_wp_proofs_iter ?provers ?tip iter =
let mode = default_mode () in
compute_provers ~mode ;
compute_auto ~mode ;
begin match provers with None -> () | Some prvs ->
mode.provers <- List.map (fun dp -> VCS.BatchMode , VCS.Why3 dp) prvs
end ;
begin match tip with None -> () | Some tip ->
mode.tactical <- tip ;
mode.update <- tip ;
end ;
let spawned = mode.tactical || mode.provers <> [] in
begin
if spawned then do_list_scheduled iter ;
spawn_wp_proofs_iter ~mode iter ;
if spawned then
begin
do_list_scheduled_result () ;
do_update_session mode iter ;
end
else if not (Wp_parameters.Print.get ()) then
iter do_wpo_display
end
let do_wp_proofs () = do_wp_proofs_iter (fun f -> Wpo.iter ~on_goal:f ())
let do_wp_proofs_for goals = do_wp_proofs_iter (fun f -> Bag.iter f goals)
(* registered at frama-c (normal) exit *)
let do_cache_cleanup () =
begin
let mode = ProverWhy3.get_mode () in
ProverWhy3.cleanup_cache ~mode ;
let removed = ProverWhy3.get_removed () in
if removed > 0 &&
not (Wp_parameters.has_dkey dkey_shell) &&
not (Wp_parameters.has_dkey VCS.dkey_no_cache_info)
then
Wp_parameters.result "[Cache] removed:%d" removed
end
(* ------------------------------------------------------------------------ *)
(* --- Secondary Entry Points --- *)
(* ------------------------------------------------------------------------ *)
(* Deprecated entry point in Dynamic. *)
let deprecated_wp_compute kf bhv ipopt =
let model = computer () in
let goals =
match ipopt with
| None -> Generator.compute_kf model ?kf ~bhv ()
| Some ip -> Generator.compute_ip model ip
in do_wp_proofs_for goals
let deprecated_wp_compute_kf kf bhv prop =
let model = computer () in
do_wp_proofs_for (Generator.compute_kf model ?kf ~bhv ~prop ())
let deprecated_wp_compute_ip ip =
Wp_parameters.warning ~once:true "Dynamic 'wp_compute_ip' is now deprecated." ;
let model = computer () in
do_wp_proofs_for (Generator.compute_ip model ip)
let deprecated_wp_compute_call stmt =
Wp_parameters.warning ~once:true "Dynamic 'wp_compute_ip' is now deprecated." ;
do_wp_proofs_for (Generator.compute_call (computer ()) stmt)
let deprecated_wp_clear () =
Wp_parameters.warning ~once:true "Dynamic 'wp_compute_ip' is now deprecated." ;
Wpo.clear ()
(* ------------------------------------------------------------------------ *)
(* --- Command-line Entry Points --- *)
(* ------------------------------------------------------------------------ *)
let dkey_logicusage = Wp_parameters.register_category "logicusage"
let dkey_refusage = Wp_parameters.register_category "refusage"
let dkey_builtins = Wp_parameters.register_category "builtins"
let cmdline_run () =
let wp_main fct =
Wp_parameters.feedback ~ontty:`Feedback "Running WP plugin...";
Ast.compute ();
Dyncall.compute ();
if Wp_parameters.has_dkey dkey_logicusage then
begin
LogicUsage.compute ();
LogicUsage.dump ();
end ;
if Wp_parameters.has_dkey dkey_refusage then
begin
RefUsage.compute ();
RefUsage.dump ();
end ;
let bhv = Wp_parameters.Behaviors.get () in
let prop = Wp_parameters.Properties.get () in
(** TODO entry point *)
let computer = computer () in
if Wp_parameters.has_dkey dkey_builtins then
begin
WpContext.on_context (computer#model,WpContext.Global)
LogicBuiltins.dump ();
end ;
Generator.compute_selection computer ~fct ~bhv ~prop ()
in
let fct = Wp_parameters.get_wp () in
match fct with
| Wp_parameters.Fct_none -> ()
| Wp_parameters.Fct_all ->
begin
ignore (wp_main fct);
do_wp_proofs ();
do_wp_print ();
do_wp_report ();
end
| _ ->
begin
let goals = wp_main fct in
do_wp_proofs_for goals ;
do_wp_print_for goals ;
do_wp_report () ;
end
(* ------------------------------------------------------------------------ *)
(* --- Register external functions --- *)
(* ------------------------------------------------------------------------ *)
let deprecated name =
Wp_parameters.warning ~once:true ~current:false
"Dynamic '%s' now is deprecated. Use `Wp.VC` api instead." name
let register name ty code =
let _ignore =
Dynamic.register ~plugin:"Wp" name ty
~journalize:false (*LC: Because of Property is not journalizable. *)
(fun x -> deprecated name ; code x)
in ()
(* DEPRECATED *)
let () =
let module OLS = Datatype.List(Datatype.String) in
let module OKF = Datatype.Option(Kernel_function) in
let module OP = Datatype.Option(Property) in
register "wp_compute"
(Datatype.func3 OKF.ty OLS.ty OP.ty Datatype.unit)
deprecated_wp_compute
let () =
let module OKF = Datatype.Option(Kernel_function) in
let module OLS = Datatype.List(Datatype.String) in
register "wp_compute_kf"
(Datatype.func3 OKF.ty OLS.ty OLS.ty Datatype.unit)
deprecated_wp_compute_kf
let () =
register "wp_compute_ip"
(Datatype.func Property.ty Datatype.unit)
deprecated_wp_compute_ip
let () =
register "wp_compute_call"
(Datatype.func Cil_datatype.Stmt.ty Datatype.unit)
deprecated_wp_compute_call
let () =
register "wp_clear"
(Datatype.func Datatype.unit Datatype.unit)
deprecated_wp_clear
let run = Dynamic.register ~plugin:"Wp" "run"
(Datatype.func Datatype.unit Datatype.unit)
~journalize:true
cmdline_run
let () =
let open Datatype in
begin
let t_job = func Unit.ty Unit.ty in
let t_iter = func (func Wpo.S.ty Unit.ty) Unit.ty in
let register name ty f =
ignore (Dynamic.register name ty ~plugin:"Wp" ~journalize:false f)
in
register "wp_begin_session" t_job begin_session ;
register "wp_end_session" t_job end_session ;
register "wp_clear_session" t_job clear_session ;
register "wp_iter_session" t_iter iter_session ;
end
(* ------------------------------------------------------------------------ *)
(* --- Tracing WP Invocation --- *)
(* ------------------------------------------------------------------------ *)
let pp_wp_parameters fmt =
begin
Format.pp_print_string fmt "# frama-c -wp" ;
if Wp_parameters.RTE.get () then Format.pp_print_string fmt " -wp-rte" ;
let spec = Wp_parameters.Model.get () in
if spec <> [] && spec <> ["Typed"] then
( let descr = Factory.descr (Factory.parse spec) in
Format.fprintf fmt " -wp-model '%s'" descr ) ;
if not (Wp_parameters.Let.get ()) then Format.pp_print_string fmt
" -wp-no-let" ;
if Wp_parameters.Let.get () && not (Wp_parameters.Prune.get ())
then Format.pp_print_string fmt " -wp-no-prune" ;
if Wp_parameters.Split.get () then Format.pp_print_string fmt " -wp-split" ;
let tm = Wp_parameters.Timeout.get () in
if tm <> 10 then Format.fprintf fmt " -wp-timeout %d" tm ;
let st = Wp_parameters.Steps.get () in
if st > 0 then Format.fprintf fmt " -wp-steps %d" st ;
if not (Kernel.SignedOverflow.get ()) then
Format.pp_print_string fmt " -no-warn-signed-overflow" ;
if Kernel.UnsignedOverflow.get () then
Format.pp_print_string fmt " -warn-unsigned-overflow" ;
if Kernel.SignedDowncast.get () then
Format.pp_print_string fmt " -warn-signed-downcast" ;
if Kernel.UnsignedDowncast.get () then
Format.pp_print_string fmt " -warn-unsigned-downcast" ;
if not (Wp_parameters.Volatile.get ()) then
Format.pp_print_string fmt " -wp-no-volatile" ;
Format.pp_print_string fmt " [...]" ;
Format.pp_print_newline fmt () ;
end
let () = Cmdline.run_after_setting_files
(fun _ ->
if Wp_parameters.has_dkey dkey_shell then
Log.print_on_output pp_wp_parameters)
(* -------------------------------------------------------------------------- *)
(* --- Prover Configuration & Detection --- *)
(* -------------------------------------------------------------------------- *)
let () = Cmdline.run_after_configuring_stage Why3Provers.configure
let do_prover_detect () =
if not !Config.is_gui && Wp_parameters.Detect.get () then
let provers = Why3Provers.provers () in
if provers = [] then
Wp_parameters.result "No Why3 provers detected."
else
let open Why3.Whyconf in
let shortcuts = get_prover_shortcuts (Why3Provers.config ()) in
let print_prover_shortcuts_for fmt p =
Why3.Wstdlib.Mstr.iter
(fun name p' -> if Prover.equal p p' then
Format.fprintf fmt "%s|" name)
shortcuts in
List.iter
(fun p ->
Wp_parameters.result "Prover %10s %-6s [%a%a]"
p.prover_name p.prover_version
print_prover_shortcuts_for p
print_prover_parseable_format p
) provers
(* ------------------------------------------------------------------------ *)
(* --- Main Entry Points --- *)
(* ------------------------------------------------------------------------ *)
let rec try_sequence jobs () = match jobs with
| [] -> ()
| head :: tail ->
Extlib.try_finally ~finally:(try_sequence tail) head ()
let sequence jobs () =
if Wp_parameters.has_dkey dkey_raised
then List.iter (fun f -> f ()) jobs
else try_sequence jobs ()
let tracelog () =
let active_keys = Wp_parameters.get_debug_keys () in
if active_keys <> [] then begin
let pp_sep fmt () = Format.pp_print_string fmt "," in
Wp_parameters.(
debug "Logging keys: %a."
(Format.pp_print_list ~pp_sep pp_category) active_keys)
end
let main = sequence [
(fun () -> Wp_parameters.debug ~dkey:dkey_main "Start WP plugin...@.") ;
do_prover_detect ;
cmdline_run ;
tracelog ;
Wp_parameters.reset ;
(fun () -> Wp_parameters.debug ~dkey:dkey_main "Stop WP plugin...@.") ;
]
let () = Cmdline.at_normal_exit do_cache_cleanup
let () = Db.Main.extend main
(* ------------------------------------------------------------------------ *)