Newer
Older
(**************************************************************************)
(* *)
(* This file is part of WP plug-in of Frama-C. *)
(* *)
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
(* 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). *)
(* *)
(**************************************************************************)
(* -------------------------------------------------------------------------- *)
(* Registry for ACSL Builtins --- *)
(* -------------------------------------------------------------------------- *)
open Cil_types
open Ctypes
open Qed
open Lang
type category = Lang.lfun Qed.Logic.category
type builtin =
| ACSLDEF
| LFUN of lfun
| HACK of (F.term list -> F.term)
type kind =
| Z (* integer *)
| R (* real *)
| I of Ctypes.c_int
| F of Ctypes.c_float
| A (* abstract data *)
(* [LC] kinds can be compared by Stdlib.compare *)
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
let okind = function
| C_int i -> I i
| C_float f -> F f
| _ -> A
let ckind typ = okind (object_of typ)
let skind = function
| I _ | Z -> Logic.Sint
| F _ | R -> Logic.Sreal
| A -> Logic.Sdata
let rec lkind t =
match Logic_utils.unroll_type ~unroll_typedef:false t with
| Ctype ty -> ckind ty
| Ltype({lt_name="set"},[t]) -> lkind t
| Lreal -> R
| Linteger -> Z
| Ltype _ | Larrow _ | Lvar _ -> A
let kind_of_tau = function
| Qed.Logic.Int -> Z
| Qed.Logic.Real -> R
| _ -> A
let pp_kind fmt = function
| I i -> Ctypes.pp_int fmt i
| F f -> Ctypes.pp_float fmt f
| Z -> Format.pp_print_string fmt "int"
| R -> Format.pp_print_string fmt "real"
| A -> Format.pp_print_string fmt "_"
let pp_kinds fmt = function
| [] -> ()
| t::ts ->
Format.fprintf fmt "(%a" pp_kind t ;
List.iter (fun t -> Format.fprintf fmt ",%a" pp_kind t) ts ;
Format.fprintf fmt ")"
let pp_libs fmt = function
| [] -> ()
| t::ts ->
Format.fprintf fmt ": %s" t ;
List.iter (fun t -> Format.fprintf fmt ",%s" t) ts
let pp_link fmt = function
| ACSLDEF -> Format.pp_print_string fmt "(ACSL)"
| HACK _ -> Format.pp_print_string fmt "(HACK)"
| LFUN f -> Fun.pretty fmt f
(* -------------------------------------------------------------------------- *)
(* --- Driver & Lookup & Registry --- *)
(* -------------------------------------------------------------------------- *)
type sigfun = kind list * builtin
type driver = {
driverid : string;
description : string;
includes : string list;
hlogic : (string , sigfun list) Hashtbl.t;
htypes : (string , t_builtin) Hashtbl.t;
hdeps : (string, string list) Hashtbl.t;
hoptions :
(string (* library *) * string (* group *) * string (* name *), string list)
Hashtbl.t;
mutable locked: bool
let lock driver = driver.locked <- true
let id d = d.driverid
let descr d = d.description
let is_default d = (d.driverid = "")
let compare d d' = String.compare d.driverid d'.driverid
let driver = Context.create "driver"
let cdriver_ro () = Context.get driver
let cdriver_rw () =
let driver = Context.get driver in
if driver.locked then
Wp_parameters.failure "Attempt to modify locked: %s" driver.driverid ;
driver
let lookup_driver name kinds =
try
let sigs = Hashtbl.find (cdriver_ro ()).hlogic name in
try List.assoc kinds sigs
with Not_found ->
Wp_parameters.feedback ~once:true
"Use -wp-msg-key 'driver' for debugging drivers" ;
if kinds=[]
then Warning.error "Builtin %s undefined as a constant" name
else Warning.error "Builtin %s undefined with signature %a" name
pp_kinds kinds
with Not_found ->
if Logic_env.is_builtin_logic_function name
|| Logic_env.is_builtin_logic_ctor name
then
Warning.error "Builtin %s%a not defined" name pp_kinds kinds
else
ACSLDEF
let hacks = Hashtbl.create 8
let hack name phi = Hashtbl.replace hacks name phi
let lookup name kinds =
try
let hack = Hashtbl.find hacks name in
let compute es =
try hack es with Not_found ->
match lookup_driver name kinds with
| ACSLDEF | HACK _ -> Warning.error "No fallback for hacked '%s'" name
| LFUN p -> F.e_fun p es
in HACK compute
with Not_found -> lookup_driver name kinds
let register ?source name kinds link =
let driver = cdriver_rw () in
let sigs = try Hashtbl.find driver.hlogic name with Not_found -> [] in
if List.exists (fun (s,_) -> s = kinds) sigs then
Wp_parameters.warning ?source "Redefinition of logic %s%a"
name pp_kinds kinds ;
let entry = (kinds,link) in
Hashtbl.add driver.hlogic name (entry::sigs)
let register_type ?source name builtin =
let driver = cdriver_rw () in
if Hashtbl.mem driver.htypes name then
Wp_parameters.warning ?source "Redifinition of type %s" name ;
Hashtbl.add driver.htypes name builtin
let iter_table f =
let items = ref [] in
Hashtbl.iter
(fun a sigs -> List.iter (fun (ks,lnk) -> items := (a,ks,lnk)::!items) sigs)

Andre Maroneze
committed
List.iter f (List.sort Stdlib.compare !items)
let iter_libs f =
let items = ref [] in
Hashtbl.iter
(fun a libs -> items := (a,libs) :: !items)

Andre Maroneze
committed
List.iter f (List.sort Stdlib.compare !items)
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
let dump () =
Log.print_on_output
begin fun fmt ->
Format.fprintf fmt "Builtins:@\n" ;
iter_libs
(fun (name,libs) -> Format.fprintf fmt " * Library %s%a@\n"
name pp_libs libs) ;
iter_table
(fun (name,k,lnk) -> Format.fprintf fmt " * Logic %s%a = %a@\n"
name pp_kinds k pp_link lnk) ;
end
(* -------------------------------------------------------------------------- *)
(* --- Implemented Builtins --- *)
(* -------------------------------------------------------------------------- *)
let logic phi =
lookup phi.l_var_info.lv_name
(List.map (fun v -> lkind v.lv_type) phi.l_profile)
let ctor phi =
lookup phi.ctor_name (List.map lkind phi.ctor_params)
let constant name =
lookup name []
(* -------------------------------------------------------------------------- *)
(* --- Declaration of Builtins --- *)
(* -------------------------------------------------------------------------- *)
let dependencies lib =
Hashtbl.find (cdriver_ro ()).hdeps lib
let add_library lib deps =
let others = try dependencies lib with Not_found -> [] in
Hashtbl.add (cdriver_rw ()).hdeps lib (others @ deps)
let add_alias ~source name kinds ~alias () =
register ~source name kinds (lookup alias kinds)
let add_logic ~source result name kinds ~library ?category ~link () =
let sort = skind result in
let params = List.map skind kinds in
let lfun = Lang.extern_s ~library ?category ~sort ~params ~link name in
register ~source name kinds (LFUN lfun)
let add_predicate ~source name kinds ~library ~link () =
let params = List.map skind kinds in
let lfun = Lang.extern_fp ~library ~params ~link link in
register ~source name kinds (LFUN lfun)
let add_ctor ~source name kinds ~library ~link () =
let category = Logic.Constructor in
let params = List.map skind kinds in
let lfun = Lang.extern_s ~library ~category ~params ~link name in
register ~source name kinds (LFUN lfun)
let add_type ?source name ~library ?(link=name) () =
let mdt = Lang.extern_t name ~link ~library in
register_type ?source name (E_mdt mdt)
let hack_type name poly =
register_type name (E_poly poly)
type sanitizer = driver_dir:string -> string -> string
let sanitizers : ( string * string , sanitizer ) Hashtbl.t = Hashtbl.create 10
exception Unknown_option of string * string
let sanitize ~driver_dir group name v =
try
(Hashtbl.find sanitizers (group,name)) ~driver_dir v
with Not_found -> raise (Unknown_option(group,name))
type doption = string * string
let create_option ~sanitizer group name =
let option = (group,name) in
Hashtbl.replace sanitizers option sanitizer ;
option
let get_option (group,name) ~library =
try Hashtbl.find (cdriver_ro ()).hoptions (library,group,name)
with Not_found -> []
let set_option ~driver_dir group name ~library value =
let value = sanitize ~driver_dir group name value in
Hashtbl.replace (cdriver_rw ()).hoptions (library,group,name) [value]
let add_option ~driver_dir group name ~library value =
let value = sanitize ~driver_dir group name value in
let l = get_option (group,name) ~library in
Hashtbl.replace (cdriver_rw ()).hoptions (library,group,name) (l @ [value])
(** Includes *)
let find_lib file =
if Sys.file_exists file then file else
let rec lookup file = function
| [] -> Wp_parameters.abort "File '%s' not found" file
| dir::dirs ->
let path = Printf.sprintf "%s/%s" dir file in
if Sys.file_exists path then path else lookup file dirs
lookup file (cdriver_ro ()).includes
(* -------------------------------------------------------------------------- *)
(* --- Implemented Builtins --- *)
(* -------------------------------------------------------------------------- *)
let builtin_driver = {
driverid = "builtin driver";
description = "builtin driver";
includes = [];
hlogic = Hashtbl.create 131;
htypes = Hashtbl.create 131;
hdeps = Hashtbl.create 31;
hoptions = Hashtbl.create 131;
}
let add_builtin name kinds lfun =
let phi = LFUN lfun in
if Context.defined driver then
register name kinds phi
else
Context.bind driver builtin_driver (register name kinds) phi
let add_type ?source name ~library ?link () =
if Context.defined driver then
add_type ?source name ~library ?link ()
else
Context.bind driver builtin_driver
(add_type ?source name ~library ?link) ()
let hack_type name poly =
if Context.defined driver then hack_type name poly
else Context.bind driver builtin_driver hack_type name poly
let find_type name =
Hashtbl.find (cdriver_ro ()).htypes name
let find_type name =
if Context.defined driver then find_type name
else Context.bind driver builtin_driver find_type name
let () = Context.set Lang.builtin_types find_type
let new_driver ~id ?(base=builtin_driver)
?(descr=id) ?(includes=[]) ?(configure=fun () -> ()) () =
lock base ;
let new_driver = {
driverid = id ;
description = descr ;
includes = includes @ base.includes ;
hlogic = Hashtbl.copy base.hlogic ;
htypes = Hashtbl.copy base.htypes ;
hdeps = Hashtbl.copy base.hdeps ;
hoptions = Hashtbl.copy base.hoptions ;
} in
let old = Context.push driver new_driver in
configure () ;
Context.pop driver old ;
new_driver
(* -------------------------------------------------------------------------- *)