module Core.Parser
    ( -- * Parse the given file
      getHist  -- :: FilePath -> IO Items

      -- * The actual parser
    , pFile    -- :: ByteString -> Items
    ) where

import Core.Util

import Data.ByteString.Char8 qualified as BS
import Data.ByteString.Lex.Fractional (readDecimal)


-- | Read a history file (the file must exist) and parse it into a map.
getHist :: FilePath -> IO Items
getHist :: FilePath -> IO (Map ByteString Double)
getHist = (ByteString -> Map ByteString Double)
-> IO ByteString -> IO (Map ByteString Double)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> Map ByteString Double
pFile (IO ByteString -> IO (Map ByteString Double))
-> (FilePath -> IO ByteString)
-> FilePath
-> IO (Map ByteString Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. FilePath -> IO ByteString
BS.readFile

-- | Parse a history file of name-number pairs.
pFile :: ByteString -> Items
pFile :: ByteString -> Map ByteString Double
pFile = [(ByteString, Double)] -> Map ByteString Double
[Item (Map ByteString Double)] -> Map ByteString Double
forall l. IsList l => [Item l] -> l
fromList ([(ByteString, Double)] -> Map ByteString Double)
-> (ByteString -> [(ByteString, Double)])
-> ByteString
-> Map ByteString Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [(ByteString, Double)] -> ByteString -> [(ByteString, Double)]
go []
  where
    go :: [(ByteString, Double)] -> ByteString -> [(ByteString, Double)]
    go :: [(ByteString, Double)] -> ByteString -> [(ByteString, Double)]
go [(ByteString, Double)]
its ByteString
""    = [(ByteString, Double)]
its
    go [(ByteString, Double)]
its ByteString
input = [(ByteString, Double)] -> ByteString -> [(ByteString, Double)]
go ((ByteString, Double)
it (ByteString, Double)
-> [(ByteString, Double)] -> [(ByteString, Double)]
forall a. a -> [a] -> [a]
: [(ByteString, Double)]
its) ByteString
rest
      where
        ((ByteString, Double)
it, ByteString
rest) :: ((ByteString, Double), ByteString)
            = (ByteString -> (ByteString, Double))
-> (ByteString -> ByteString)
-> (ByteString, ByteString)
-> ((ByteString, Double), ByteString)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap ((ByteString -> Double)
-> (ByteString, ByteString) -> (ByteString, Double)
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (Double
-> ((Double, ByteString) -> Double)
-> Maybe (Double, ByteString)
-> Double
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Double
0 (Double, ByteString) -> Double
forall a b. (a, b) -> a
fst (Maybe (Double, ByteString) -> Double)
-> (ByteString -> Maybe (Double, ByteString))
-> ByteString
-> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ByteString -> Maybe (Double, ByteString)
forall a. Fractional a => ByteString -> Maybe (a, ByteString)
readDecimal) ((ByteString, ByteString) -> (ByteString, Double))
-> (ByteString -> (ByteString, ByteString))
-> ByteString
-> (ByteString, Double)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> Bool) -> ByteString -> (ByteString, ByteString)
spanEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
' '))
                    (Int -> ByteString -> ByteString
BS.drop Int
1)
            ((ByteString, ByteString) -> ((ByteString, Double), ByteString))
-> (ByteString -> (ByteString, ByteString))
-> ByteString
-> ((ByteString, Double), ByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> Bool) -> ByteString -> (ByteString, ByteString)
BS.span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\n')
            (ByteString -> ((ByteString, Double), ByteString))
-> ByteString -> ((ByteString, Double), ByteString)
forall a b. (a -> b) -> a -> b
$ ByteString
input

    spanEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
    spanEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString)
spanEnd Char -> Bool
p ByteString
bs = (ByteString -> ByteString
init' (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> ByteString -> ByteString
BS.dropWhileEnd Char -> Bool
p ByteString
bs, (Char -> Bool) -> ByteString -> ByteString
BS.takeWhileEnd Char -> Bool
p ByteString
bs)

    init' :: ByteString -> ByteString
    init' :: ByteString -> ByteString
init' = ByteString
-> ((ByteString, Char) -> ByteString)
-> Maybe (ByteString, Char)
-> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
"" (ByteString, Char) -> ByteString
forall a b. (a, b) -> a
fst (Maybe (ByteString, Char) -> ByteString)
-> (ByteString -> Maybe (ByteString, Char))
-> ByteString
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ByteString -> Maybe (ByteString, Char)
BS.unsnoc
{-# INLINE pFile #-}