    -- | @futhark datacmp@
    module Futhark.CLI.Datacmp (main) where

    import Control.Exception
    import Data.ByteString.Lazy.Char8 qualified as BS
    import Futhark.Data.Compare
    import Futhark.Data.Reader
    import Futhark.Util.Options
    import System.Exit
    import System.IO

    readFileSafely :: String -> IO (Either String BS.ByteString)
    readFileSafely :: String -> IO (Either String ByteString)
    readFileSafely String
    filepath =
      (ByteString -> Either String ByteString
    forall a b. b -> Either a b
    Right (ByteString -> Either String ByteString)
    -> IO ByteString -> IO (Either String ByteString)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> IO ByteString
    BS.readFile String
    filepath) IO (Either String ByteString)
    -> (IOError -> IO (Either String ByteString))
    -> IO (Either String ByteString)
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    `catch` IOError -> IO (Either String ByteString)
    forall {f :: * -> *} {b}.
    Applicative f =>
    IOError -> f (Either String b)
    couldNotRead
      where
        couldNotRead :: IOError -> f (Either String b)
    couldNotRead IOError
    e = Either String b -> f (Either String b)
    forall a. a -> f a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (Either String b -> f (Either String b))
    -> Either String b -> f (Either String b)
    forall a b. (a -> b) -> a -> b
    $ String -> Either String b
    forall a b. a -> Either a b
    Left (String -> Either String b) -> String -> Either String b
    forall a b. (a -> b) -> a -> b
    $ IOError -> String
    forall a. Show a => a -> String
    show (IOError
    e :: IOError)

    -- | Run @futhark datacmp@
    main :: String -> [String] -> IO ()
    main :: String -> [String] -> IO ()
    main = ()
    -> [FunOptDescr ()]
    -> String
    -> ([String] -> () -> Maybe (IO ()))
    -> String
    -> [String]
    -> IO ()
    forall cfg.
    cfg
    -> [FunOptDescr cfg]
    -> String
    -> ([String] -> cfg -> Maybe (IO ()))
    -> String
    -> [String]
    -> IO ()
    mainWithOptions () [] String
    "<file> <file>" [String] -> () -> Maybe (IO ())
    f
      where
        f :: [String] -> () -> Maybe (IO ())
    f [String
    file_a, String
    file_b] () = IO () -> Maybe (IO ())
    forall a. a -> Maybe a
    Just (IO () -> Maybe (IO ())) -> IO () -> Maybe (IO ())
    forall a b. (a -> b) -> a -> b
    $ do
          Either String ByteString
    file_contents_a_maybe <- String -> IO (Either String ByteString)
    readFileSafely String
    file_a
          Either String ByteString
    file_contents_b_maybe <- String -> IO (Either String ByteString)
    readFileSafely String
    file_b
          case (Either String ByteString
    file_contents_a_maybe, Either String ByteString
    file_contents_b_maybe) of
            (Left String
    err_msg, Either String ByteString
    _) -> do
              Handle -> String -> IO ()
    hPutStrLn Handle
    stderr String
    err_msg
              IO ()
    forall a. IO a
    exitFailure
            (Either String ByteString
    _, Left String
    err_msg) -> do
              Handle -> String -> IO ()
    hPutStrLn Handle
    stderr String
    err_msg
              IO ()
    forall a. IO a
    exitFailure
            (Right ByteString
    contents_a, Right ByteString
    contents_b) -> do
              let vs_a_maybe :: Maybe [Value]
    vs_a_maybe = ByteString -> Maybe [Value]
    readValues ByteString
    contents_a
              let vs_b_maybe :: Maybe [Value]
    vs_b_maybe = ByteString -> Maybe [Value]
    readValues ByteString
    contents_b
              case (Maybe [Value]
    vs_a_maybe, Maybe [Value]
    vs_b_maybe) of
                (Maybe [Value]
    Nothing, Maybe [Value]
    _) -> do
                  Handle -> String -> IO ()
    hPutStrLn Handle
    stderr (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    "Error reading values from " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    file_a
                  IO ()
    forall a. IO a
    exitFailure
                (Maybe [Value]
    _, Maybe [Value]
    Nothing) -> do
                  Handle -> String -> IO ()
    hPutStrLn Handle
    stderr (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    "Error reading values from " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    file_b
                  IO ()
    forall a. IO a
    exitFailure
                (Just [Value]
    vs_a, Just [Value]
    vs_b) ->
                  case Tolerance -> [Value] -> [Value] -> [Mismatch]
    compareSeveralValues (Double -> Tolerance
    Tolerance Double
    0.002) [Value]
    vs_a [Value]
    vs_b of
                    [] -> () -> IO ()
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ()
                    [Mismatch]
    es -> do
                      (Mismatch -> IO ()) -> [Mismatch] -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Mismatch -> IO ()
    forall a. Show a => a -> IO ()
    print [Mismatch]
    es
                      ExitCode -> IO ()
    forall a. ExitCode -> IO a
    exitWith (ExitCode -> IO ()) -> ExitCode -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Int -> ExitCode
    ExitFailure Int
    2
        f [String]
    _ ()
    _ =
          Maybe (IO ())
    forall a. Maybe a
    Nothing