packages feed

liquid-fixpoint-0.9.6.3.4: src/Language/Fixpoint/Horn/Solve.hs

-------------------------------------------------------------------------------
-- | This module defines a function to solve NNF constraints,
--   by reducing them to the standard FInfo.
-------------------------------------------------------------------------------

module Language.Fixpoint.Horn.Solve (solveHorn, solve) where

import System.Exit ( ExitCode )
import Control.DeepSeq ( NFData )
import Control.Monad (when)
import qualified Language.Fixpoint.Misc         as Misc
import qualified Language.Fixpoint.Utils.Files  as Files
import qualified Language.Fixpoint.Solver       as Solver
import qualified Language.Fixpoint.Parse        as Parse
import qualified Language.Fixpoint.Types        as F
import qualified Language.Fixpoint.Types.Config as F
import qualified Language.Fixpoint.Horn.Types   as H

import qualified Language.Fixpoint.Horn.Parse   as H
import qualified Language.Fixpoint.Horn.SMTParse   as SH

import qualified Language.Fixpoint.Horn.Transformations as Tx
import Text.PrettyPrint.HughesPJ.Compat ( render )
import Language.Fixpoint.Horn.Info ( hornFInfo )

import System.Console.CmdArgs.Verbosity ( whenLoud )
import qualified Data.Aeson as Aeson
-- import Debug.Trace (traceM)

----------------------------------------------------------------------------------
solveHorn :: F.Config -> IO ExitCode
----------------------------------------------------------------------------------
solveHorn baseCfg0 = do
  q <- parseQuery baseCfg0
  let baseCfg = baseCfg0 { F.explicitKvars = True }
  -- If you want to set --eliminate=none, you better make it a pragma
  let cfgElim = if F.eliminate baseCfg == F.None
                  then baseCfg { F.eliminate =  F.Some }
                  else baseCfg

  cfgPragmas <- F.withPragmas cfgElim (H.qOpts q)

  when (F.save cfgPragmas) (saveHornQuery cfgPragmas q)

  r <- solve cfgPragmas q
  Solver.resultExitCode cfgPragmas r

parseQuery :: F.Config -> IO H.TagQuery
parseQuery cfg
  | F.stdin cfg = Parse.parseFromStdIn hornP
  | json        = loadFromJSON file
  | otherwise   = Parse.parseFromFile hornP file
  where
    json  = Files.isExtFile Files.Json file
    file  = F.srcFile cfg
    hornP = if F.noSmtHorn cfg then H.hornP else SH.hornP

loadFromJSON :: FilePath -> IO H.TagQuery
loadFromJSON f = do
  r <- Aeson.eitherDecodeFileStrict f
  case r of
    Right v -> return v
    Left err -> error ("Error in loadFromJSON: " ++ err)

saveHornQuery :: F.Config -> H.Query H.Tag -> IO ()
saveHornQuery cfg q = do
  saveHornSMT2 cfg q
  saveHornJSON cfg q

saveHornSMT2 :: F.ToHornSMT a => F.Config -> a -> IO ()
saveHornSMT2 cfg q = do
  let hq   = F.queryFile Files.HSmt2 cfg
  putStrLn $ "Saving Horn Query: " ++ hq ++ "\n"
  Misc.ensurePath hq
  writeFile hq $ render (F.toHornSMT q)

saveHornJSON :: F.Config -> H.Query H.Tag -> IO ()
saveHornJSON cfg q = do
  let hjson   = F.queryFile Files.HJSON cfg
  putStrLn $ "Saving Horn Query: " ++ hjson ++ "\n"
  Misc.ensurePath hjson
  Aeson.encodeFile hjson q

----------------------------------------------------------------------------------
eliminate :: (F.Fixpoint a, F.PPrint a) => F.Config -> H.Query a -> IO (H.Query a)
----------------------------------------------------------------------------------
eliminate cfg q
  | F.eliminate cfg == F.Existentials = do
    Tx.solveEbs cfg q
  | F.eliminate cfg == F.Horn = do
    let c = Tx.elim $ H.qCstr q
    whenLoud $ putStrLn "Horn Elim:"
    whenLoud $ putStrLn $ F.showpp c
    pure $ q { H.qCstr = c }
  | otherwise = pure q

----------------------------------------------------------------------------------
solve :: (F.PPrint a, NFData a, F.Loc a, Show a, F.Fixpoint a) => F.Config -> H.Query a
       -> IO (F.Result (Integer, a))
----------------------------------------------------------------------------------
solve cfg qry = do
  let c = Tx.uniq $ Tx.flatten $ H.qCstr qry
  whenLoud $ putStrLn "Horn Uniq:"
  whenLoud $ putStrLn $ F.showpp c
  q <- eliminate cfg ({- void $ -} qry { H.qCstr = c })
  Solver.solve cfg (hornFInfo cfg q)