-
Virgile Prevosto authoredVirgile Prevosto authored
convert_acsl.ml 30.50 KiB
(**************************************************************************)
(* *)
(* This file is part of Frama-Clang *)
(* *)
(* Copyright (C) 2012-2022 *)
(* CEA (Commissariat à l'énergie atomique et aux énergies *)
(* 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 LICENSE). *)
(* *)
(**************************************************************************)
open Intermediate_format
open Logic_ptree
let convert_var env is_extern_c vi =
match vi.logic_var_lv_kind with
| LVGlobal | LVCGlobal ->
if is_extern_c then vi.logic_var_lv_name.decl_name
else
let n, tk
= Convert_env.typedef_normalize env vi.logic_var_lv_name TStandard
in Mangling.mangle n tk None
| LVFormal | LVQuant | LVLocal | LVCLocal | LVBuiltin ->
vi.logic_var_lv_name.decl_name
let convert_logic_label = function
| StmtLabel s -> s
| LogicLabel s -> s
let convert_logic_label_opt = function
| Some lab -> Some (convert_logic_label lab)
| None -> None
let convert_ikind = function
| IBool -> Cil_types.IBool
| IChar_u -> Cil_types.IChar
| IChar_s -> Cil_types.IChar
| IUChar -> Cil_types.IUChar
| ISChar -> Cil_types.ISChar
| IChar16 -> Cil.intKindForSize 2 true
| IChar32 -> Cil.intKindForSize 4 true
| IWChar_u
| IWChar_s
| IWUChar
| IWSChar -> Cil.theMachine.Cil.wcharKind
| IChar -> Cil_types.IChar
| IWChar -> Cil.theMachine.Cil.wcharKind
| IShort -> Cil_types.IShort
| IUShort -> Cil_types.IUShort
| IInt -> Cil_types.IInt
| IUInt -> Cil_types.IUInt
| ILong -> Cil_types.ILong
| IULong -> Cil_types.IULong
| ILongLong -> Cil_types.ILongLong
| IULongLong -> Cil_types.IULongLong
let convert_fkind = function
| FFloat -> Cil_types.FFloat
| FDouble -> Cil_types.FDouble
| FLongDouble -> Cil_types.FLongDouble
let convert_logic_constant = function
| LCInt v -> IntConstant v
| LStr s -> StringConstant s
| LWStr _s ->
Frama_Clang_option.not_yet_implemented "Wide string support in logic"
| LChr c -> IntConstant (string_of_int c)
| LWChr c -> IntConstant (string_of_int c)
| LCReal s -> FloatConstant s
| LCEnum (v,_) -> IntConstant (Int64.to_string v)
(* TODO: add support into ACSL for that? *)
let convert_cst_array_size env = function
| LCInt v -> ASinteger v
| LChr c | LWChr c -> ASinteger (string_of_int c)
| LCEnum (_,s) ->
let n, tk = Convert_env.typedef_normalize env s TStandard in
let cname = Mangling.mangle n tk None in
ASidentifier cname
| LStr _ | LWStr _ | LCReal _ ->
Frama_Clang_option.fatal "Unexpected value as array dimension"
let rec convert_logic_type env = function
| Lvoid -> LTvoid
| Lint ik -> LTint (convert_ikind ik)
| Lfloat fk -> LTfloat (convert_fkind fk)
| Larray (t,dim) ->
let t = convert_logic_type env t in
let dim =
match dim with
| Some dim -> convert_cst_array_size env dim
| None -> ASnone
in
LTarray(t,dim)
| Lpointer t | Lreference t ->
let t = convert_logic_type env t in
LTpointer t
| Lenum e ->
let e, tk = Convert_env.typedef_normalize env e TStandard
in LTenum (Mangling.mangle e tk None)
| Lstruct (s,t) ->
let s,t = Convert_env.typedef_normalize env s t in
let cname =
if Convert_env.is_extern_c_aggregate env s t then s.decl_name
else Mangling.mangle s t None
in
LTstruct cname
| Lunion (u,t) ->
let u, t = Convert_env.typedef_normalize env u t in
let cname =
if Convert_env.is_extern_c_aggregate env u t then u.decl_name
else Mangling.mangle u t None
in
LTunion cname
| LCnamed (n,extern_c) ->
let name = if extern_c then n.decl_name
else (* change only the template parameters in the qualification *)
let n, tk = Convert_env.typedef_normalize env n TStandard
in Mangling.mangle n tk None
in
LTnamed (name,[])
| Lnamed({ prequalification = [QNamespace "Utf8_logic"];
decl_name = "boolean"},_,[]) ->
LTnamed (Utf8_logic.boolean,[])
| Lnamed(t,extern_c,args) ->
let name =
if extern_c then t.decl_name
else
let t, tk = Convert_env.typedef_normalize env t TStandard
in Mangling.mangle t tk None
in
let args = List.map (convert_logic_type env) args in
LTnamed(name,args)
| Lvariable s -> LTnamed(s.decl_name,[])
| Linteger -> LTinteger
| Lreal -> LTreal
| Larrow(args,rt) ->
let args = List.map (convert_logic_type env) args in
let rt = convert_logic_type env rt in
LTarrow(args, rt)
let convert_logic_param env p = (convert_logic_type env p.la_type, p.la_name)
type bkind = Relation | Logic | Arithmetic
let bo_kind = function
| BOPlus | BOMinus | BOTimes | BODivide | BOModulo | BOBitOr | BOBitAnd
| BOBitExclusiveOr | BOLeftShift | BORightShift
-> Arithmetic
| BOLess | BOLessOrEqual | BOEqual | BODifferent
| BOGreaterOrEqual | BOGreater
-> Relation
| BOLogicalAnd | BOLogicalOr -> Logic
| BOComma -> Frama_Clang_option.fatal "Comma operator in ACSL++ expression"
let convert_bop_arith = function
| BOPlus -> Badd
| BOMinus -> Bsub
| BOTimes -> Bmul
| BODivide -> Bdiv
| BOModulo -> Bmod
| BOBitOr -> Bbw_or
| BOBitAnd -> Bbw_and
| BOBitExclusiveOr -> Bbw_xor
| BOLeftShift -> Blshift
| BORightShift -> Brshift
| _ -> Frama_Clang_option.fatal "not a binary arithmetic operation"
let convert_bop_relation = function
| BOLess -> Lt
| BOLessOrEqual -> Le
| BOEqual -> Eq
| BODifferent -> Neq
| BOGreater -> Gt
| BOGreaterOrEqual -> Ge
| _ -> Frama_Clang_option.fatal "not a relation"
let convert_rel = function
| Rlt -> Lt
| Rgt -> Gt
| Rle -> Le
| Rge -> Ge
| Req -> Eq
| Rneq -> Neq
let convert_var_decl env v =
let typ = convert_logic_type env v.lv_type in
let name = v.logic_var_def_lv_name.decl_name in
(typ, name)
let convert_reference env typ e =
match typ with
| LVReference _ | RVReference _ ->
let full_e = { lexpr_loc = Convert_env.get_loc env; lexpr_node = e } in
PLunop(Ustar,full_e)
| _ -> e
let convert_logic_reference env typ e =
match typ with
| Lreference _ ->
let full_e = { lexpr_loc = Convert_env.get_loc env; lexpr_node = e } in
PLunop(Ustar, full_e)
| _ -> e
let rec convert_logic_expr env e =
let env = Convert_env.set_loc env e.loc in
let lexpr_loc = Convert_env.get_loc env in
let anonymous =
{ lexpr_loc; lexpr_node = convert_logic_expr_node env e.node }
in
List.fold_right
(fun s res -> { lexpr_loc; lexpr_node = PLnamed(s,res) })
e.names anonymous
and convert_logic_expr_node env = function
| TConst c -> PLconstant(convert_logic_constant c)
| TLval lv -> convert_logic_lval env lv
| TSizeOf t -> PLsizeof(convert_logic_type env t)
| TSizeOfStr s ->
let cs =
{ lexpr_loc = Convert_env.get_loc env;
lexpr_node = PLconstant(StringConstant s) }
in
PLsizeofE(cs)
| TUnOp((UOPostInc|UOPostDec|UOPreInc|UOPreDec),_) ->
Convert_env.fatal env "Side effect operation in ACSL++ expression"
| TUnOp((UOCastNoEffect _ | UOCastDeref | UOCastToVoid | UOCastInteger _
| UOCastDerefInit | UOCastEnum _ | UOCastFloat _ | UOCastC _),_) ->
Convert_env.fatal env
"Logic casts are not supposed to use TUnOp but TCastE"
| TUnOp(UOOpposite,e) -> PLunop(Uminus,convert_logic_expr env e)
| TUnOp(UOBitNegate,e) -> PLunop(Ubw_not,convert_logic_expr env e)
| TUnOp(UOLogicalNegate,e) -> PLnot (convert_logic_expr env e)
| TBinOp(bo,e1,e2) when bo_kind bo = Arithmetic ->
let cbo = convert_bop_arith bo in
let ce1 = convert_logic_expr env e1 in
let ce2 = convert_logic_expr env e2 in
PLbinop(ce1,cbo,ce2)
| TBinOp(bo,e1,e2) when bo_kind bo = Relation ->
let cbo = convert_bop_relation bo in
let ce1 = convert_logic_expr env e1 in
let ce2 = convert_logic_expr env e2 in
PLrel(ce1,cbo,ce2)
| TBinOp(BOLogicalAnd,e1,e2) ->
let ce1 = convert_logic_expr env e1 in
let ce2 = convert_logic_expr env e2 in
PLand(ce1,ce2)
| TBinOp(BOLogicalOr,e1,e2) ->
let ce1 = convert_logic_expr env e1 in
let ce2 = convert_logic_expr env e2 in
PLor(ce1,ce2)
| TBinOp _ -> Convert_env.fatal env "Unknown binary operator in logic"
| TCastE(typ,e) ->
let ctyp = convert_logic_type env typ in
let ce = convert_logic_expr env e in
PLcast(ctyp,ce)
| TAddrOf lv | TStartOf lv ->
let e = convert_logic_lval env lv in
(* simplify memory accesses introduced by handling of references *)
(match e with
| PLunop(Ustar,t) -> t.lexpr_node
| _ ->
let e = { lexpr_node = e; lexpr_loc = Convert_env.get_loc env } in
PLunop(Uamp,e))
| TFieldAccess (e,(TField(f,TNoOffset)|TModel(f,TNoOffset))) ->
let ce = convert_logic_expr env e in PLdot(ce,f)
| TFieldAccess _ ->
Convert_env.fatal env "Unexpected offset in field access"
| TFalse -> PLfalse
| TTrue -> PLtrue
| TApp(f,l,args,extern_c) ->
(* TODO: if f is an extern C (or built-in), do not mangle it *)
let fname = if extern_c then f.decl_name
else
let f, t = Convert_env.typedef_normalize env f TStandard
in Mangling.mangle f t None in
let labels = List.map (fun l -> convert_logic_label l.snd) l in
let args = List.map (convert_logic_expr env) args in
PLapp(fname,labels,args)
| TLambda (vars,t) ->
let quants = List.map (convert_var_decl env) vars in
let e = convert_logic_expr env t in
PLlambda(quants,e)
| TDataCons(name,args) ->
let name, t = Convert_env.typedef_normalize env name TStandard in
let name = Mangling.mangle name t None in
let args = List.map (convert_logic_expr env) args in
PLapp(name,[],args)
| TIf(cond,etrue,efalse) ->
let ccond = convert_logic_expr env cond in
let cetrue = convert_logic_expr env etrue in
let cefalse = convert_logic_expr env efalse in
PLif(ccond,cetrue,cefalse)
| TAt(t,l) ->
let t = convert_logic_expr env t in
let l = convert_logic_label l in
PLat(t,l)
| TBase_addr(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLbase_addr(l,t)
| TOffset(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLoffset(l,t)
| TBlock_length(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLblock_length(l,t)
| TNull -> PLnull
| TLogic_coerce(_,t) ->
(* should be transparent at the parsed logic tree level. *)
(convert_logic_expr env t).lexpr_node
| TUpdate(obj,off,t) ->
let obj = convert_logic_expr env obj in
let path = path_of_offset env off in
let value = convert_logic_expr env t in
PLupdate(obj,path,PLupdateTerm value)
| TEmpty_set -> PLempty
| TUnion l ->
let l = List.map (convert_logic_expr env) l in
PLunion l
| TInter l ->
let l = List.map (convert_logic_expr env) l in
PLinter l
| TComprehension (t,quants,pred) ->
let quants = List.map (convert_var_decl env) quants in
let t = convert_logic_expr env t in
let pred = Option.map (convert_pred_named env) pred in
PLcomprehension (t,quants,pred)
| TRange(l,h) ->
let l = Option.map (convert_logic_expr env) l in
let h = Option.map (convert_logic_expr env) h in
PLrange(l,h)
| TLet(info,t) ->
let body = convert_inner_body env info in
let name = info.li_name.decl_name in
let rest = convert_logic_expr env t in
PLlet(name,body,rest)
| TCoerce _ | TCoerceE _ ->
Frama_Clang_option.not_yet_implemented "coercions"
and convert_logic_lval env lv =
let base = convert_logic_lhost env lv.base_support in
convert_logic_offset env base lv.offset
and convert_logic_lhost env = function
| TVar v ->
(match v.logic_var_lv_kind with
| LVCGlobal ->
let is_extern_c, typ =
Convert_env.get_global_var env v.logic_var_lv_name
in
let var = PLvar (convert_var env is_extern_c v) in
convert_reference env typ var
| LVCLocal ->
let var = PLvar v.logic_var_lv_name.decl_name in
let typ = Convert_env.get_local_var env v.logic_var_lv_name.decl_name in
convert_reference env typ var
| _ ->
PLvar v.logic_var_lv_name.decl_name
)
| TCFun(n,s) ->
let n, t = Convert_env.typedef_normalize env n TStandard
in PLvar (Mangling.mangle n t (Some (FKFunction,s)))
| TResult typ -> convert_logic_reference env typ PLresult
| TMem t -> let t = convert_logic_expr env t in PLunop(Ustar,t)
and convert_logic_offset env base = function
| TNoOffset -> base
| TField(s,o) | TModel(s,o) ->
let e = { lexpr_loc = Convert_env.get_loc env; lexpr_node = base } in
let base = PLdot(e,s) in
convert_logic_offset env base o
| TBase(b,t,o) ->
let e = { lexpr_loc = Convert_env.get_loc env; lexpr_node = base } in
let b, t = Convert_env.typedef_normalize env b t in
let base = PLdot(e,("_frama_c_" ^ Mangling.mangle b t None)) in
convert_logic_offset env base o
| TVirtualBase(b,t,o) ->
let e = { lexpr_loc = Convert_env.get_loc env; lexpr_node = base } in
let b, t = Convert_env.typedef_normalize env b t in
let base = PLdot(e,("_frama_c_" ^ Mangling.mangle b t None)) in
convert_logic_offset env base o
| TDerived(_ (* d *),_ (* td *),_ (* b *),_ (* tb *),_ (* o *)) ->
Convert_env.fatal env
"casts to derived classes are not supported for the moment"
| TIndex(t,o) ->
let e = { lexpr_loc = Convert_env.get_loc env; lexpr_node = base } in
let i = convert_logic_expr env t in
let base = PLarrget(e,i) in
convert_logic_offset env base o
and path_of_offset env = function
| TNoOffset -> []
| TField(s,o) | TModel(s,o) ->
let path = path_of_offset env o in
PLpathField s :: path
| TBase(b,t,o) ->
let path = path_of_offset env o in
let b, t = Convert_env.typedef_normalize env b t in
PLpathField ("_frama_c_" ^ Mangling.mangle b t None) :: path
| TVirtualBase(b,t,o) ->
let path = path_of_offset env o in
let b, t = Convert_env.typedef_normalize env b t in
PLpathField ("_frama_c_" ^ Mangling.mangle b t None) :: path
| TDerived(_ (* d *),_ (* td *),_ (* b *),_ (* tb *),_ (* o *)) ->
Convert_env.fatal env
"casts to derived classes are not supported for the moment"
| TIndex(t,o) ->
let i = convert_logic_expr env t in
let path = path_of_offset env o in
PLpathIndex(i) :: path
and convert_pred_named env p =
let env = Convert_env.set_loc env p.pred_loc in
let pred_loc = Convert_env.get_loc env in
let cp = convert_pred env p.pred_content in
let cp =
List.fold_right
(fun s acc -> PLnamed(s,{ lexpr_node = acc; lexpr_loc = pred_loc }))
p.pred_name cp
in
{ lexpr_node = cp; lexpr_loc = pred_loc }
and convert_pred env = function
| Pfalse -> PLfalse
| Ptrue -> PLtrue
| PApp(p,labs,args,is_extern_c) ->
let pname = if is_extern_c then p.decl_name
else
let p, t = Convert_env.typedef_normalize env p TStandard in
Mangling.mangle p t None
in let clabs = List.map (fun l -> convert_logic_label l.snd) labs in
let cargs = List.map (convert_logic_expr env) args in
PLapp(pname,clabs,cargs)
| Pseparated l ->
let l = List.map (convert_logic_expr env) l in
PLseparated l
| Prel(rel,t1,t2) ->
let rel = convert_rel rel in
let t1 = convert_logic_expr env t1 in
let t2 = convert_logic_expr env t2 in
PLrel(t1,rel,t2)
| Pand(p1,p2) ->
let p1 = convert_pred_named env p1 in
let p2 = convert_pred_named env p2 in
PLand(p1,p2)
| Por(p1,p2) ->
let p1 = convert_pred_named env p1 in
let p2 = convert_pred_named env p2 in
PLor(p1,p2)
| Pxor(p1,p2) ->
let p1 = convert_pred_named env p1 in
let p2 = convert_pred_named env p2 in
PLxor(p1,p2)
| Pimplies(p1,p2) ->
let p1 = convert_pred_named env p1 in
let p2 = convert_pred_named env p2 in
PLimplies(p1,p2)
| Piff(p1,p2) ->
let p1 = convert_pred_named env p1 in
let p2 = convert_pred_named env p2 in
PLiff(p1,p2)
| Pnot p ->
let p = convert_pred_named env p in
PLnot p
| Pif(cond,ptrue,pfalse) ->
let cond = convert_logic_expr env cond in
let ptrue = convert_pred_named env ptrue in
let pfalse = convert_pred_named env pfalse in
PLif(cond,ptrue,pfalse)
| Plet(li,p) ->
let body = convert_inner_body env li in
let p = convert_pred_named env p in
PLlet(li.li_name.decl_name,body,p)
| Pforall (x,p) ->
let quants = List.map (convert_var_decl env) x in
let p = convert_pred_named env p in
PLforall(quants,p)
| Pexists(x,p) ->
let quants = List.map (convert_var_decl env) x in
let p = convert_pred_named env p in
PLexists(quants,p)
| Pat(l,p) ->
let l = convert_logic_label l in
let p = convert_pred_named env p in
PLat(p,l)
| Pvalid_function(t) ->
let t = convert_logic_expr env t in
PLvalid_function(t)
| Pvalid_read(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLvalid_read(l,t)
| Pvalid(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLvalid(l,t)
| Pinitialized(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLinitialized(l,t)
| Pallocable(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLallocable(l,t)
| Pfreeable(l,t) ->
let l = convert_logic_label_opt l in
let t = convert_logic_expr env t in
PLfreeable(l,t)
| Pfresh(Some l1, Some l2,t1,t2) ->
let l1 = convert_logic_label l1 in
let l2 = convert_logic_label l2 in
let t1 = convert_logic_expr env t1 in
let t2 = convert_logic_expr env t2 in
PLfresh (Some(l1,l2),t1,t2)
| Pfresh(None,None,t1,t2) ->
let t1 = convert_logic_expr env t1 in
let t2 = convert_logic_expr env t2 in
PLfresh (None,t1,t2)
| Pfresh(_,_,_,_) -> Frama_Clang_option.fatal
"zero or two labels needed in fresh construct"
| Psubtype _ -> Frama_Clang_option.not_yet_implemented "subtyping relation"
and convert_inner_body env li =
let body =
match li.fun_body with
| LBnone -> Convert_env.fatal env "local binding without body"
| LBreads _ -> Convert_env.fatal env "local binding with read clause"
| LBinductive _ -> Convert_env.fatal env "local inductive definition"
| LBterm t -> convert_logic_expr env t
| LBpred p -> convert_pred_named env p
in
match li.profile with
| [] -> body
| prms ->
let convert_arg_decl a =
let typ = convert_logic_type env a.la_type in
let v = a.la_name in
typ, v
in
let prms = List.map convert_arg_decl prms in
{ lexpr_node = PLlambda(prms,body); lexpr_loc = Convert_env.get_loc env }
let convert_logic_ctor env ctor =
(* NB: we can't rely on ACSL overloading for constructor. Maybe we
should get the whole signature? *)
let name =
if ctor.logic_ctor_info_is_extern_c then
ctor.ctor_name.decl_name
else
let ctor_name, t
= Convert_env.typedef_normalize env ctor.ctor_name TStandard in
Mangling.mangle ctor_name t None
in
let prms = List.map (convert_logic_type env) ctor.ctor_params in
(name,prms)
let convert_logic_type_def env = function
| LTsum ctors -> TDsum (List.map (convert_logic_ctor env) ctors)
| LTsyn t -> TDsyn (convert_logic_type env t)
let convert_extended env e =
(e.ext_name, List.map (convert_pred_named env) e.predicates)
let convert_allocation env = function
| Intermediate_format.FreeAlloc(f,a) ->
Logic_ptree.FreeAlloc
(List.map (convert_logic_expr env) f, List.map (convert_logic_expr env) a)
| Intermediate_format.FreeAllocAny -> Logic_ptree.FreeAllocAny
let convert_deps env = function
| Intermediate_format.From l ->
Logic_ptree.From (List.map (convert_logic_expr env) l)
| Intermediate_format.FromAny -> Logic_ptree.FromAny
let convert_from env f =
convert_logic_expr env f.floc, convert_deps env f.vars
let convert_assigns env = function
| Intermediate_format.WritesAny -> Logic_ptree.WritesAny
| Intermediate_format.Writes l ->
Logic_ptree.Writes (List.map (convert_from env) l)
let convert_pred_tp env ?(kind=Cil_types.Assert) p =
(* TODO: support check and admit in ACSL++. *)
let tp_statement = convert_pred_named env p in
{ tp_kind = kind; tp_statement }
let convert_termination_kind = function
| Intermediate_format.Normal -> Cil_types.Normal
| Intermediate_format.Exits -> Cil_types.Exits
| Intermediate_format.Breaks -> Cil_types.Breaks
| Intermediate_format.Continues -> Cil_types.Continues
| Intermediate_format.Returns -> Cil_types.Returns
let convert_post_cond env p =
convert_termination_kind p.tkind, convert_pred_tp env p.pred
let convert_behavior env bhv =
let b_name = bhv.beh_name in
let b_requires = List.map (convert_pred_tp env) bhv.requires in
let b_assumes = List.map (convert_pred_named env) bhv.assumes in
let b_post_cond = List.map (convert_post_cond env) bhv.post_cond in
let b_assigns = convert_assigns env bhv.assignements in
let b_allocation = convert_allocation env bhv.alloc in
let b_extended = List.map (convert_extended env) bhv.extended in
{ b_name; b_requires; b_assumes; b_post_cond;
b_assigns; b_allocation; b_extended }
let convert_variant env v = convert_logic_expr env v.vbody, v.vname
let convert_function_contract env contract =
let spec_behavior = List.map (convert_behavior env) contract.behavior in
let spec_variant = Option.map (convert_variant env) contract.variant in
let spec_terminates =
Option.map (convert_pred_named env) contract.terminates
in
let spec_complete_behaviors =
List.map (fun c -> c.behaviors) contract.complete_behaviors
in
let spec_disjoint_behaviors =
List.map (fun c -> c.behaviors) contract.disjoint_behaviors
in
{ spec_behavior; spec_variant; spec_terminates; spec_complete_behaviors;
spec_disjoint_behaviors }
let convert_inv_kind = function
| InvariantAsAssertion -> false
| NormalLoop -> true
let convert_loop_pragma env = function
| Intermediate_format.Unroll_specs l ->
Logic_ptree.Unroll_specs (List.map (convert_logic_expr env) l)
| Intermediate_format.Widen_hints l ->
Logic_ptree.Unroll_specs (List.map(convert_logic_expr env) l)
| Intermediate_format.Widen_variables l ->
Logic_ptree.Widen_variables (List.map (convert_logic_expr env) l)
let convert_slice_pragma env = function
| Intermediate_format.SPexpr e ->
Logic_ptree.SPexpr (convert_logic_expr env e)
| Intermediate_format.SPctrl -> Logic_ptree.SPctrl
| Intermediate_format.SPstmt -> Logic_ptree.SPstmt
let convert_impact_pragma env = function
| Intermediate_format.IPexpr e ->
Logic_ptree.IPexpr (convert_logic_expr env e)
| Intermediate_format.IPstmt -> Logic_ptree.IPstmt
let convert_pragma env = function
| Intermediate_format.Loop_pragma p ->
Logic_ptree.Loop_pragma (convert_loop_pragma env p)
| Intermediate_format.Slice_pragma p ->
Logic_ptree.Slice_pragma (convert_slice_pragma env p)
| Intermediate_format.Impact_pragma p ->
Logic_ptree.Impact_pragma (convert_impact_pragma env p)
let convert_code_annot env = function
| Intermediate_format.Assert(bhvs,pred) ->
AAssert(bhvs, convert_pred_tp env pred)
| StmtSpec(bhvs,spec) -> AStmtSpec(bhvs,convert_function_contract env spec)
| Invariant(bhvs,kind,inv) ->
let kind = convert_inv_kind kind in
let inv = convert_pred_tp env inv in
AInvariant(bhvs,kind,inv)
| Variant v -> AVariant (convert_variant env v)
| Assigns (bhvs,a) -> AAssigns(bhvs,convert_assigns env a)
| Allocation(bhvs,a) -> AAllocation(bhvs,convert_allocation env a)
| Pragma p -> APragma (convert_pragma env p)
let rec convert_annot env annot =
let annot, env =
match annot with
| Dfun_or_pred (loc,info) ->
let env = Convert_env.set_loc env loc in
(* we don't necessarily need to mangle according to the signature,
as ACSL itself feature overloading. If we decide to have unique
names, we'll need to adapt mangling to accomodate for logic types.
*)
let name =
if info.li_extern_c then
info.li_name.decl_name
else
let info_name, t
= Convert_env.typedef_normalize env info.li_name TStandard in
Mangling.mangle info_name t None
in
let labels = List.map convert_logic_label info.arg_labels in
let rt = Option.map (convert_logic_type env) info.returned_type in
let params = List.map (convert_logic_param env) info.profile in
(match info.fun_body,rt with
| LBnone, None ->
LDpredicate_reads(name,labels,info.tparams,params,None)
| LBnone, Some rt ->
LDlogic_reads(name,labels,info.tparams,rt,params,None)
| LBreads l, None ->
let reads = List.map (convert_logic_expr env) l in
LDpredicate_reads(name,labels,info.tparams,params,Some reads)
| LBreads l, Some rt ->
let reads = List.map (convert_logic_expr env) l in
LDlogic_reads(name,labels,info.tparams,rt,params,Some reads)
| LBterm _, None ->
Convert_env.fatal env "predicate definition with a term as body"
| LBterm body, Some rt ->
let body = convert_logic_expr env body in
LDlogic_def(name,labels,info.tparams,rt,params,body)
| LBpred _, Some _ ->
Convert_env.fatal env
"logic function definition with a predicate as body"
| LBpred body, None ->
let body = convert_pred_named env body in
LDpredicate_def(name,labels,info.tparams,params,body)
| LBinductive _, Some _ ->
Convert_env.fatal env
"logic function definition with inductive body"
| LBinductive body, None ->
let inductive_case ind =
let labs = List.map convert_logic_label ind.labels in
let def = convert_pred_named env ind.def in
(ind.def_name,labs,ind.arguments,def)
in
let body = List.map inductive_case body in
LDinductive_def(name,labels,info.tparams,params,body)
), env
| Dvolatile(loc,mem,read,write) ->
let env = Convert_env.set_loc env loc in
let mem = List.map (convert_logic_expr env) mem in
(* NB: should we have the real type of the arguments of the functions?*)
let mangle name signature =
let name, t = Convert_env.typedef_normalize env name TStandard in
Mangling.mangle name t signature in
let read = Option.map (Extlib.swap mangle None)
read in
let write = Option.map (Extlib.swap mangle None)
write in
LDvolatile(mem,(read,write)), env
| Daxiomatic(loc,s,annots) ->
let env = Convert_env.set_loc env loc in
let annots = List.map (convert_annot env) annots in
LDaxiomatic(s,annots), env
| Dtype(loc,lt_info) ->
let env = Convert_env.set_loc env loc in
let name =
if lt_info.logic_type_info_is_extern_c then
lt_info.type_name.decl_name
else
let info_name, t = Convert_env.typedef_normalize
env lt_info.type_name TStandard in
Mangling.mangle info_name t None
in
let def = Option.map (convert_logic_type_def env)
lt_info.definition in
LDtype(name, lt_info.params, def), env
| Dlemma(loc,name,is_axiom,labs,params,body) ->
let env = Convert_env.set_loc env loc in
let labs = List.map convert_logic_label labs in
let kind = if is_axiom then Cil_types.Admit else Assert in
let body = convert_pred_tp env ~kind body in
LDlemma(name,labs,params,body), env
| Dinvariant(loc,body) ->
let env = Convert_env.set_loc env loc in
let name =
if body.li_extern_c then
body.li_name.decl_name
else
let body_name, t = Convert_env.typedef_normalize
env body.li_name TStandard in
Mangling.mangle body_name t None
in
let body =
match body.fun_body with
| LBpred p ->
convert_pred_named env p
| _ ->
Convert_env.fatal env "unexpected body for a global invariant"
in
LDinvariant(name, body), env
| Dtype_annot (loc, body) ->
let env = Convert_env.set_loc env loc in
let inv_name =
if body.li_extern_c then
body.li_name.decl_name
else
let body_name, t = Convert_env.typedef_normalize
env body.li_name TStandard in
Mangling.mangle body_name t None
in
let this_type, this_name =
match body.profile with
| [ { la_type = t; la_name = s } ] -> convert_logic_type env t, s
| _ ->
Convert_env.fatal env
"unexpected number of parameters \
in definition of type invariant"
in
let inv =
match body.fun_body with
| LBpred p -> convert_pred_named env p
| _ -> Convert_env.fatal env "unexpected body for a type invariant"
in
LDtype_annot { inv_name; this_type; this_name; inv }, env
| Dmodel_annot(loc,model) ->
let env = Convert_env.set_loc env loc in
let model_name = model.Intermediate_format.model_name in
let model_type = convert_logic_type env model.field_type in
let model_for_type = convert_logic_type env model.base_type in
LDmodel_annot { model_for_type; model_type; model_name }, env
in
{ decl_node = annot; decl_loc = Convert_env.get_loc env; }