packages feed

liquid-fixpoint-0.1.0.0: external/fixpoint/hornToInterproc.ml

module F  = Format
module BS = BNstats
module Co = Constants 
module SM = Misc.StringMap 
module H  = Ast.Horn
module Misc = FixMisc open Misc.Ops


let tmpname1 = "tmp"

(***************************************************************************)
(************************* Parse Horn Clauses ******************************)
(***************************************************************************)

let clean f =
  Misc.map_lines_of_file f tmpname1 begin fun s ->
    if String.length s > 3 && String.sub s 0 3 = "hc(" then
        let ss = Misc.chop s ", " in
        match ss with
        | [s1; s2; _] -> Printf.sprintf "%s, %s).\n\n" s1 s2
        | ss          -> assertf "bad string: %s" (String.concat "####" ss)
    else ""
  end;
  tmpname1

let parse f : H.t list = 
  let ic = f |> clean >> Errorline.startFile |> open_in in
  let rv = Lexing.from_channel ic |> HornParse.horns HornLex.token in
  let _  = close_in ic in
  rv

(****************************************************************************)
(******************* Preprocess HC to get global information ****************)
(****************************************************************************)

type t = {
  aritym : int SM.t;            (* k -> arity *)
  bindm  : string list SM.t;    (* k -> local bindings *)
  argn   : int;                 (* max-fun-args across all ks *)
  cm     : H.t list SM.t;       (* k -> cs *)
}

let create (cs: H.t list) : t =
  let cm = cs |> Misc.kgroupby (fun ((k,_),_) -> k) 
              |> List.fold_left (fun cm (k,cs) -> SM.add k cs cm) SM.empty in
  let aritym = SM.map (function ((k, xs),_)::_ -> 
                         let n = List.length xs in
                         (* let _ = Printf.printf "Arity(%s) using %s is %d \n" k
                         (String.concat "," xs) n in *)
                      n) cm in
  let bindm  = SM.map ((Misc.flap H.support) <+> Misc.sort_and_compact) cm in
  let argn   = SM.fold (fun _ a n -> max a n) aritym 0 in
  { aritym = aritym; bindm = bindm; argn = argn; cm = cm }

(****************************************************************************)
(**************************** Generic Sequencers ****************************)
(****************************************************************************)

let gen f sep xs =
  xs |> Misc.map f |> String.concat sep

let geni f sep xs = 
  xs |> Misc.mapi f |> String.concat sep

let defn x n =
  geni (fun i _ -> Printf.sprintf "%s%d : int" x i) ", " (Misc.range 0 n)

(****************************************************************************)
(********************************* Translation ******************************)
(****************************************************************************)

let tx_gd = function
  | H.C p       -> Printf.sprintf "    assume %s;" (Misc.fsprintf Ast.Predicate.print p)
  | H.K (k, xs) -> Printf.sprintf "%s\n    () = %s(%s);" 
                     (geni (Printf.sprintf "    a%d = %s;") "\n" xs)
                     k
                     (geni (fun i _ -> Printf.sprintf "a%d" i) "," xs)

let tx_hd = function 
  | "error", _ -> "    fail;"
  | _, xs      -> Printf.sprintf "    assume %s;" 
                     (geni (fun i x -> Printf.sprintf " z%d == %s " i x) " and " xs)

let tx_t k (head, guards) : string =
  Printf.sprintf "  if brandom then\n%s\n%s\n  else" (gen tx_gd "\n" guards) (tx_hd head)

let tx_def me = function
  | "error" -> 
      ""
  | k -> 
      let n = try SM.find k me.aritym with Not_found -> assertf "ERROR:no arity for %s" k in
      let _ = Printf.printf "Arity(%s) := %d \n" k n in 
      Printf.sprintf "proc %s(%s) returns ()" k (defn "z" n) 

let tx_k me (k, cs) =  
  Printf.sprintf 
"
%s
var %s, %s;
begin
%s
    halt;
  %s  
end
" 
(tx_def me k) 
(defn "a" me.argn) 
(gen (Printf.sprintf "%s : int") ", " (SM.find k me.bindm)) 
(gen (tx_t me) "\n" cs)
(gen (fun _ -> "endif;") " " cs)

let rewrite_eq s = 
  if Misc.is_substring s "assume" then 
    Misc.replace_substring " = " " == " s 
  else s

let tx cs = 
  let me = create cs in
  me.cm 
  |> Misc.sm_to_list
  |> List.map (tx_k me)
  |> String.concat "\n\n"
  |> Misc.flip Misc.chop "\n" 
  |> List.map rewrite_eq
  |> String.concat "\n"

(***************************************************************************)
(***************************** Output Clauses ******************************)
(***************************************************************************)

let dump f cs =
  cs >> Format.printf "*************Horn Clauses************\n\n%a\n\n\n" (Misc.pprint_many true "\n" H.print)
     |> tx 
     >> Format.printf "***********Interproc Program*********\n\n%s\n\n\n" 
     |> Misc.write_to_file (f^".ipc")

let usage = "hornToInterproc.native [filename.pl]"

let main usage = 
  print_now "\n \n \n \n \n";
  print_now "========================================================\n";
  print_now "© Copyright 2009 Regents of the University of California.\n";
  print_now "All Rights Reserved.\n";
  print_now "========================================================\n";
  print_now (Sys.argv |> Array.to_list |> String.concat " ");
  print_now "\n========================================================\n";
  let fs = ref [] in
  let _  = Arg.parse Co.arg_spec (fun s -> fs := s::!fs) usage in
  match !fs with 
  | [f] -> parse f |> dump f 
  | _   -> assertf "I choke on too many/few files!" 

let _ = main usage