open Abstract_syntax_tree
open Util
open Value_domain
open Environment_domain
module NonRelational (V : VALUE_DOMAIN) : ENVIRONMENT_DOMAIN = struct
type env = V.t VarMap.t
type t = Env of env | Bot
let init = Env VarMap.empty
let bottom = Bot
let get_var env id =
try VarMap.find id env
with Not_found -> V.top
(* utilities *)
let rec eval env expr =
begin match fst expr with
| AST_identifier (id, _) -> get_var env id
| AST_int_const (s, _) -> V.const (Z.of_string s)
| AST_int_rand ((s, _), (t, _)) -> V.rand (Z.of_string s) (Z.of_string t)
| AST_unary (AST_UNARY_PLUS, e) -> eval env e
| AST_unary (AST_UNARY_MINUS, e) -> V.neg (eval env e)
| AST_unary (_, e) -> V.bottom
| AST_binary (op, e1, e2) ->
let f = match op with
| AST_PLUS -> V.add
| AST_MINUS -> V.sub
| AST_MULTIPLY -> V.mul
| AST_DIVIDE -> V.div
| AST_MODULO -> V.rem
| _ -> fun _ _ -> V.bottom
in f (eval env e1) (eval env e2)
| _ -> assert false (* unimplemented extension *)
end
let strict env = (* env -> t *)
if VarMap.exists (fun _ x -> x = V.bottom) env
then Bot
else Env env
let strict_apply f = function (* (env -> t) -> t -> t *)
| Bot -> Bot
| Env e -> match f e with
| Bot -> Bot
| Env e -> strict e
(* implementation *)
let is_bot env = match env with
| Bot -> true
| Env env -> strict env = Bot
let addvar x id = strict_apply (fun y -> Env (VarMap.add id V.top y)) x
let rmvar x id = strict_apply (fun y -> Env (VarMap.remove id y)) x
let assign x id expr = strict_apply
(fun env -> Env (VarMap.add id (eval env expr) env))
x
let compare f x e1 e2 =
strict_apply (fun env -> match fst e1, fst e2 with
| AST_identifier(a, _), AST_identifier(b, _) ->
let v1, v2 = get_var env a, get_var env b in
let v1', v2' = f v1 v2 in
Env (VarMap.add a v1' (VarMap.add b v2' env))
| AST_identifier(a, _), _ ->
let v1, v2 = get_var env a, eval env e2 in
let v1', v2' = f v1 v2 in
if V.bottom = v2'
then Bot
else Env (VarMap.add a v1' env)
| _, AST_identifier(b, _) ->
let v1, v2 = eval env e1, get_var env b in
let v1', v2' = f v1 v2 in
if V.bottom = v1'
then Bot
else Env (VarMap.add b v2' env)
| _ ->
let v1, v2 = eval env e1, eval env e2 in
let v1', v2' = f v1 v2 in
if V.bottom = v1' || V.bottom = v2'
then Bot
else Env env)
x
let compare_leq = compare V.leq
let compare_eq = compare (fun x y -> let r = V.meet x y in r, r)
let join a b = match a, b with
| Bot, x | x, Bot -> x
| Env m, Env n ->
strict (VarMap.map2z (fun _ a b -> V.join a b) m n)
let meet a b = match a, b with
| Bot, _ | _, Bot -> Bot
| Env m, Env n ->
strict (VarMap.map2z (fun _ a b -> V.meet a b) m n)
let widen a b = match a, b with
| Bot, x | x, Bot -> x
| Env m, Env n ->
strict (VarMap.map2z (fun _ a b -> V.widen a b) m n)
let subset a b = match a, b with
| Bot, x -> true
| Env _, Bot -> false
| Env m, Env n ->
VarMap.for_all2o
(fun _ _ -> true)
(fun _ v -> v = V.top)
(fun _ a b -> V.subset a b)
m n
let eq a b = match a, b with
| Bot, Bot -> true
| Env m, Env n ->
VarMap.for_all2o
(fun _ _ -> false)
(fun _ _ -> false)
(fun _ a b -> a = b)
m n
| _ -> false
(* pretty-printing *)
let var_str env vars =
match env with
| Bot -> "bottom"
| Env env ->
let v = List.fold_left
(fun s id ->
(if s = "" then s else s ^ ", ") ^
id ^ " in " ^ (V.to_string (get_var env id))
)
""
vars
in
"[ " ^ v ^ " ]"
let vars env = match env with
| Bot -> []
| Env env -> List.map fst (VarMap.bindings env)
end