packages feed

judge-0.1.2.0: app/Main.hs

{-|
Module      : Main
Description : Main module
Copyright   : (c) 2017, 2018 N Steenbergen
License     : GPL-3
Maintainer  : ns@slak.ws
Stability   : experimental
-}

{-# LANGUAGE PackageImports #-}
{-# LANGUAGE OverloadedStrings #-}

import "base" GHC.IO.Handle (Handle, hClose)
import "base" GHC.IO.Handle.FD (stdout, stderr)
import "base" Control.Monad (forM_)
import "base" Data.Maybe (fromJust)
import "text" Data.Text (Text, pack, unpack)
import qualified "yaml" Data.Yaml as Y
import qualified "unordered-containers" Data.HashMap.Strict as M2
import qualified "ansi-wl-pprint" Text.PrettyPrint.ANSI.Leijen as PP

import qualified CLI

import qualified Logic.Judge.Formula as F
import qualified Logic.Judge.Prover.Yaml as TY
import qualified Logic.Judge.Prover.Tableau as T
import qualified Logic.Judge.Prover.Tableau.Analytics as TX
import qualified Logic.Judge.Writer as W


main :: IO ()
main = do
    arg <- CLI.arguments
    filename <- CLI.infile arg
    
    W.prettyprint stderr $ 
        PP.bold (PP.string "Selected logical system:") PP.<+> 
        PP.string filename

    yaml <- deserialiseGeneric filename

    case yaml .: "logic" of
        "justification" -> case yaml .: "system" of
            "tableau" -> do
                sys <- addAssumptions 
                    <$> (deserialise yaml :: IO (T.TableauSystem F.Justification))
                    <*> (CLI.assumptions arg :: IO [F.FormulaJL])

                -- Tableau system is not prettyprinted well, so won't be shown
                -- even in verbose mode for now
                --if CLI.verbose arg
                --    then write stderr $ pretty sys
                --    else return ()

                targets <- CLI.goals arg :: IO [F.FormulaJL]
                file <- CLI.outfile arg
                let format = CLI.format arg 

                W.writeHeader file format
                forM_ targets $ \φ -> do

                    if CLI.verbose arg
                        then W.prettyprint stderr $ TX.analysis sys φ
                        else return ()
                    
                    W.writeBody file format (T.decide sys φ)
                W.writeFooter file format

                if file /= stdout
                    then hClose file
                    else return ()


            value -> unknown value "system"
        value -> unknown value "logic"
    

    where

    addAssumptions :: T.TableauSystem ext -> [F.Formula ext] -> T.TableauSystem ext
    addAssumptions system assumptions = 
        system { T.assumptions' = assumptions ++ T.assumptions' system }

    unknown :: Text -> Text -> IO ()
    unknown value key =
        fail $ "value '" ++ unpack value ++ "' for '" ++ unpack key ++ "' is unknown."


-- | Get value from a YAML map at a key. If it doesn't exist, return @"undefined"@.
(.:) :: Y.Value -> Text -> Text
(Y.Object object) .: key = 
    let asText (Y.String s) = Just s
        asText _            = Nothing
    in maybe "undefined" id $ M2.lookup key object >>= asText 
_ .: _ = "undefined"


-- | Read a filename into a generic YAML value.
deserialiseGeneric :: String -> IO Y.Value
deserialiseGeneric path = either report return =<< Y.decodeFileEither path
    where report = fail . Y.prettyPrintParseException
-- make into handle

-- | Evaluate generic YAML into a typed value.
deserialise :: Y.FromJSON a => Y.Value -> IO a
deserialise = either (fail . show) return . Y.parseEither Y.parseJSON