heptagon/global/static.ml

164 lines
5.1 KiB
OCaml

(** This module defines static expressions, used in arrays definition
and anywhere a static value is expected. For instance:
const n: int = 3;
var x : int^n; var y : int^(n + 2);
x[n - 1], x[1 + 3],...
*)
open Names
open Format
type op = | SPlus | SMinus | STimes | SDiv
type size_exp =
| SConst of int | SVar of name | SOp of op * size_exp * size_exp
(** Constraints on size expressions. *)
type size_constr =
| Equal of size_exp * size_exp (* e1 = e2*)
| LEqual of size_exp * size_exp (* e1 <= e2 *)
| False
(* unsatisfiable constraint *)
exception Instanciation_failed
exception Not_static
(** Returns the op from an operator full name. *)
let op_from_app_name n =
match n with
| Modname { qual = "Pervasives"; id = "+" } | Name "+" -> SPlus
| Modname { qual = "Pervasives"; id = "-" } | Name "-" -> SMinus
| Modname { qual = "Pervasives"; id = "*" } | Name "*" -> STimes
| Modname { qual = "Pervasives"; id = "/" } | Name "/" -> SDiv
| _ -> raise Not_static
(** [simplify env e] returns e simplified with the
variables values taken from env (mapping vars to integers).
Variables are replaced with their values and every operator
that can be computed is replaced with the value of the result. *)
let rec simplify env =
function
| SConst n -> SConst n
| SVar id -> (try simplify env (NamesEnv.find id env) with | _ -> SVar id)
| SOp (op, e1, e2) ->
let e1 = simplify env e1 in
let e2 = simplify env e2
in
(match (e1, e2) with
| (SConst n1, SConst n2) ->
let n =
(match op with
| SPlus -> n1 + n2
| SMinus -> n1 - n2
| STimes -> n1 * n2
| SDiv ->
if n2 = 0 then raise Instanciation_failed else n1 / n2)
in SConst n
| (_, _) -> SOp (op, e1, e2))
(** [int_of_size_exp env e] returns the value of the expression
[e] in the environment [env], mapping vars to integers. Raises
Instanciation_failed if it cannot be computed (if a var has no value).*)
let int_of_size_exp env e =
match simplify env e with | SConst n -> n | _ -> raise Instanciation_failed
(** [is_true env constr] returns whether the constraint is satisfied
in the environment (or None if this can be decided)
and a simplified constraint. *)
let is_true env =
function
| Equal (e1, e2) when e1 = e2 ->
((Some true), (Equal (simplify env e1, simplify env e2)))
| Equal (e1, e2) ->
let e1 = simplify env e1 in
let e2 = simplify env e2
in
(match (e1, e2) with
| (SConst n1, SConst n2) -> ((Some (n1 = n2)), (Equal (e1, e2)))
| (_, _) -> (None, (Equal (e1, e2))))
| LEqual (e1, e2) ->
let e1 = simplify env e1 in
let e2 = simplify env e2
in
(match (e1, e2) with
| (SConst n1, SConst n2) -> ((Some (n1 <= n2)), (LEqual (e1, e2)))
| (_, _) -> (None, (LEqual (e1, e2))))
| False -> (None, False)
exception Solve_failed of size_constr
(** [solve env constr_list solves a list of constraints. It
removes equations that can be decided and simplify others.
If one equation cannot be satisfied, it raises Solve_failed. ]*)
let rec solve const_env =
function
| [] -> []
| c :: l ->
let l = solve const_env l in
let (res, c) = is_true const_env c
in
(match res with
| None -> c :: l
| Some v -> if not v then raise (Solve_failed c) else l)
(** Substitutes variables in the size exp with their value
in the map (mapping vars to size exps). *)
let rec size_exp_subst m =
function
| SVar n -> (try List.assoc n m with | Not_found -> SVar n)
| SOp (op, e1, e2) -> SOp (op, size_exp_subst m e1, size_exp_subst m e2)
| s -> s
(** Substitutes variables in the constraint list with their value
in the map (mapping vars to size exps). *)
let instanciate_constr m constr =
let replace_one m =
function
| Equal (e1, e2) -> Equal (size_exp_subst m e1, size_exp_subst m e2)
| LEqual (e1, e2) -> LEqual (size_exp_subst m e1, size_exp_subst m e2)
| False -> False
in List.map (replace_one m) constr
let op_to_string =
function | SPlus -> "+" | SMinus -> "-" | STimes -> "*" | SDiv -> "/"
let rec print_size_exp ff =
function
| SConst i -> fprintf ff "%d" i
| SVar id -> fprintf ff "%s" id
| SOp (op, e1, e2) ->
(fprintf ff "@[(";
print_size_exp ff e1;
fprintf ff " %s " (op_to_string op);
print_size_exp ff e2;
fprintf ff ")@]")
let rec print_list ff print sep l =
match l with
| [] -> ()
| [ x ] -> print ff x
| x :: l -> (print ff x; fprintf ff "%s@ " sep; print_list ff print sep l)
let print_size_constr ff =
function
| Equal (e1, e2) ->
(fprintf ff "@[";
print_size_exp ff e1;
fprintf ff " = ";
print_size_exp ff e2;
fprintf ff "@]")
| LEqual (e1, e2) ->
(fprintf ff "@[";
print_size_exp ff e1;
fprintf ff " <= ";
print_size_exp ff e2;
fprintf ff "@]")
| False -> fprintf ff "False"
let psize_constr oc c =
let ff = formatter_of_out_channel oc
in (print_size_constr ff c; fprintf ff "@?")