liquid-fixpoint-0.1.0.0: external/fixpoint/toRawHorn.ml
(* Dumping constraints as Horn clauses without any simplifications *)
module C = FixConstraint
module Co = Constants
module Sy = Ast.Symbol
module Su = Ast.Subst
module P = Ast.Predicate
module E = Ast.Expression
module StrMap = Map.Make (struct type t = string let compare = compare end)
module StrSet = Set.Make (struct type t = string let compare = compare end)
module Misc = FixMisc open Misc.Ops
let raw_true = "1=1"
let raw_false = "0=1"
let sanitize_symbol s =
Str.global_replace (Str.regexp "@") "_at_" s |> Str.global_replace (Str.regexp "#") "_hash_" |>
Str.global_replace (Str.regexp "\\.") "_dot_" |> Str.global_replace (Str.regexp "'") "_q_"
let symbol_to_raw s = Sy.to_string s |> sanitize_symbol
let constant_to_raw = Ast.Constant.to_string
let bop_to_raw = function
| Ast.Plus -> "+"
| Ast.Minus -> "-"
| Ast.Times -> "*"
| Ast.Div -> "/"
let brel_to_raw = function
| Ast.Eq -> "="
| Ast.Ne -> "=\\="
| Ast.Gt -> ">"
| Ast.Ge -> ">="
| Ast.Lt -> "<"
| Ast.Le -> "=<"
let bind_to_raw (s, t) = (* Andrey: TODO support binders *)
Printf.sprintf "%s:%s" (symbol_to_raw s) (Ast.Sort.to_string t |> sanitize_symbol)
let rec expr_to_raw expr =
let e = E.unwrap expr in
match e with
| Ast.Con c -> constant_to_raw c
| Ast.Var s -> symbol_to_raw s
| Ast.App (s, es) ->
if !Co.purify_function_application then "_" else
let str = symbol_to_raw s in
if es = [] then str else
Printf.sprintf "f_%s(%s)" str (List.map expr_to_raw es |> String.concat ", ")
| Ast.Bin (e1, op, e2) ->
Printf.sprintf "(%s %s %s)"
(expr_to_raw e1) (bop_to_raw op) (expr_to_raw e2)
| Ast.Ite (ip, te, ee) ->
Printf.sprintf "ite(%s, %s, %s)"
(pred_to_raw ip) (expr_to_raw te) (expr_to_raw ee)
| Ast.Fld (s, e) ->
Printf.sprintf "fld(%s, %s)" (expr_to_raw e) (symbol_to_raw s)
| _ -> failwith (Printf.sprintf "expr_to_raw: %s" (E.to_string expr))
and pred_to_raw pred =
if P.is_tauto pred then
raw_true
else
let p = P.unwrap pred in
match p with
| Ast.True -> raw_true
| Ast.False -> raw_false
| Ast.Bexp e -> Printf.sprintf "%s = 1" (expr_to_raw e)
| Ast.Not (Ast.True, _) -> raw_false
| Ast.Not (Ast.False, _) -> raw_true
| Ast.Not p -> Printf.sprintf "neg(%s)" (pred_to_raw p)
| Ast.Imp (p1, p2) -> Printf.sprintf "imp(%s, %s)" (pred_to_raw p1) (pred_to_raw p2)
| Ast.And [] -> raw_true
| Ast.And [p] -> pred_to_raw p
| Ast.And (_::_ as ps) ->
Printf.sprintf "(%s)" (List.map pred_to_raw ps |> String.concat ", ")
| Ast.Or [] -> raw_false
| Ast.Or [p] -> pred_to_raw p
| Ast.Or (_::_ as ps) -> Printf.sprintf "(%s)" (List.map pred_to_raw ps |> String.concat "; ")
| Ast.Atom (e1, Ast.Eq, (Ast.Ite(ip, te, ee), _)) ->
let ip_str = pred_to_raw ip in
let e1_str = expr_to_raw e1 in
Printf.sprintf "((%s, %s = %s); (neg(%s), %s = %s))"
ip_str e1_str (expr_to_raw te)
ip_str e1_str (expr_to_raw ee)
| Ast.Atom (e1, r, e2) ->
Printf.sprintf "%s %s %s"
(expr_to_raw e1) (brel_to_raw r) (expr_to_raw e2)
| Ast.Forall (qs,p) -> (* Andrey: TODO support forall *)
Printf.sprintf "forall([%s], %s)"
(List.map bind_to_raw qs |> String.concat ", ")
(pred_to_raw p)
let subst_to_raw subst =
Misc.map_to_string
(fun (sym, expr) ->
Printf.sprintf "%s = %s" (symbol_to_raw sym) (expr_to_raw expr)
) (Ast.Subst.to_list subst)
let kvar_to_scope_tbl = Hashtbl.create 100
let wfs_option = ref None
let is_upper c = c = Char.uppercase c
let find_scope wfs sym =
match Misc.map_partial
(fun wf ->
let reft = C.reft_of_wf wf in
let vv = C.vv_of_reft reft in
match C.ras_of_reft reft with
| [C.Kvar (subst, sym')] when (Ast.Subst.is_empty subst) && sym = sym' ->
let vv_raw = symbol_to_raw vv in
Some (vv_raw,
StrSet.remove vv_raw
(Sy.SMap.fold (fun bv reft sofar ->
if not(C.sort_of_reft reft |> Ast.Sort.is_int)
(* is_upper (Sy.to_string bv).[0] *)
then
sofar
else
StrSet.add (symbol_to_raw bv) sofar
) (C.env_of_wf wf) StrSet.empty))
| _ -> None
) wfs with
| (vv, scope) :: _ -> vv, scope
| [] -> failwith (Printf.sprintf "Not found wf constraint for %s" (Sy.to_string sym))
let scope_of_ksym ksym =
try
Hashtbl.find kvar_to_scope_tbl ksym
with Not_found ->
begin
match !wfs_option with
| Some wfs ->
let scope = find_scope wfs ksym in
Hashtbl.add kvar_to_scope_tbl ksym scope;
scope
| None -> failwith "Uninitialized wfs_option reference"
end
let refa_to_raw = function
| C.Conc pred -> pred_to_raw pred
| C.Kvar (subst, sym) ->
let vv, scope = scope_of_ksym sym in
let subs = Ast.Subst.to_list subst in
let params =
List.map (fun param ->
try
let _, exp =
List.find (fun (v, _) ->
symbol_to_raw v = param
) subs in
match exp with
| Ast.Var param', _ -> symbol_to_raw param'
| _ -> failwith (Printf.sprintf "substition by a non-variable %s" (E.to_string exp))
with Not_found -> param
) (vv :: (StrSet.elements scope |> List.sort compare))
in
Printf.sprintf "%s(%s)" (symbol_to_raw sym) (String.concat ", " params)
let reft_to_raw reft =
if C.sort_of_reft reft |> Ast.Sort.is_func then
raw_true
else
let ras = C.ras_of_reft reft in
match ras with
| [] -> raw_true
| _ :: _ ->
Misc.map_to_string refa_to_raw ras
let subst_refa refa sym exp =
match refa with
| C.Conc pred -> C.Conc (P.subst pred sym exp)
| C.Kvar (subst, sym') -> C.Kvar (Ast.Subst.extend subst (sym, exp), sym')
let subst_reft reft sym exp =
C.make_reft
(C.vv_of_reft reft) (C.sort_of_reft reft)
(List.map (fun refa -> subst_refa refa sym exp) (C.ras_of_reft reft))
let env_to_raw env =
Sy.SMap.fold
(fun bv reft sofar ->
[subst_reft reft (C.vv_of_reft reft) (Ast.eVar bv) |> reft_to_raw] ++ sofar
) env [] |> List.filter ((<>) "1=1") |> String.concat ", "
let c_to_raw c =
Printf.sprintf "rule(%d, %s, [\n%s,\n%s,\n%s\n]).\n\n"
(C.id_of_t c)
(C.rhs_of_t c |> reft_to_raw)
(C.lhs_of_t c |> reft_to_raw)
(C.grd_of_t c |> pred_to_raw)
(C.env_of_t c |> env_to_raw)
let to_raw_horn out cs wfs sol =
let cs = FixSimplify.simplify_ts cs in
wfs_option := Some wfs;
print_endline "Translating to raw Horn clauses.";
List.iter (fun c ->
Printf.fprintf out "/*\n%s*/\n" (C.to_string c);
output_string out (c_to_raw c)
) cs