open Util
open Abstract_syntax_tree
module CD : Domain.S =
struct
exception DivideByZero
exception TypeError
exception Bot
exception NotImplemented
type tv = (* type for a variable *)
| Top
| I of Z.t
type ts = (* type for an environment *)
| Bot
| Nb of tv VarMap.t
let top_ts = Nb VarMap.empty
let ts_union a b =
begin match a, b with
| Bot, Bot -> Bot
| Nb a, Bot -> Nb a
| Bot, Nb b -> Nb b
| Nb a, Nb b ->
Nb
(VarMap.fold
(fun var value a ->
try match VarMap.find var a with
| Top -> a
| I x ->
match value with
| I y when y = x -> a
| _ -> VarMap.add var Top a
with
| Not_found -> VarMap.add var value a)
b a)
end
(* must not raise exception *)
let ts_add_bool_constraint expr (s : ts) =
s (* TODO, not necessary... *)
(* only evaluates numerical statements, raises
TypeError when result is bool *)
let rec eval_abs expr (s : tv VarMap.t) =
match expr with
| AST_unary(op, (i, _)) ->
begin match eval_abs i s with
| Top -> Top
| I x ->
match op with
| AST_UNARY_PLUS -> I x
| AST_UNARY_MINUS -> I (Z.neg x)
| _ -> raise TypeError
end
| AST_binary(op, (a, _), (b, _)) ->
begin match eval_abs a s, eval_abs b s with
| I x, I y ->
begin match op with
| AST_PLUS -> I (Z.add x y)
| AST_MINUS -> I (Z.sub x y)
| AST_MULTIPLY -> I (Z.mul x y)
| AST_DIVIDE ->
if y = Z.zero then raise DivideByZero;
I (Z.div x y)
| AST_MODULO ->
if y = Z.zero then raise DivideByZero;
I (Z.rem x y)
| _ -> raise TypeError
end
| _ -> Top
end
| AST_identifier(id, _) ->
begin
try VarMap.find id s
with _ -> Top
end
| AST_int_const(s, _) ->
I (Z.of_string s)
| AST_bool_const(_) -> raise TypeError
| AST_int_rand _ -> Top
| _ -> raise NotImplemented (* extensions *)
(* returns true if the expression can evaluate to true
returns false if the expression always evaluates to false *)
let rec eval_bool_abs expr (s : tv VarMap.t) =
true (* TODO *)
(* must not raise exception *)
let rec interp_abs stat s =
begin match s with
| Bot -> Bot
| Nb vars ->
begin match stat with
| AST_block b ->
List.fold_left
(fun ss (st, _) -> interp_abs st ss)
s b
| AST_assign ((id, _), (exp, _)) ->
begin
try
let value = eval_abs exp vars in
Nb (VarMap.add id value vars)
with _ -> Bot
end
| AST_if ((cond, _), (tb, _), None) ->
ts_union (Nb vars)
(interp_abs tb
(ts_add_bool_constraint cond (Nb vars)))
| AST_if ((cond, l), (tb, _), Some (eb, _)) ->
ts_union
(interp_abs tb
(ts_add_bool_constraint cond (Nb vars)))
(interp_abs eb
(ts_add_bool_constraint
(AST_unary (AST_NOT, (cond, l)))
(Nb vars)))
| AST_while ((cond, _), (body, _)) ->
let f s =
ts_union
s
(ts_add_bool_constraint cond s)
in
fix f (Nb vars)
| AST_HALT -> Bot
| AST_assert (cond, _) ->
if eval_bool_abs cond vars
then Nb vars
else begin
print_string "Assert fail\n";
Bot
end
| AST_print items ->
List.iter
(fun (var, _) ->
print_string (var ^ " = ");
try
match VarMap.find var vars with
| Top -> print_string "T\n"
| I x -> print_string (Z.to_string x ^ "\n")
with _ -> print_string "T\n")
items;
Nb vars
| _ -> raise NotImplemented (* extensions *)
end
end
end