-- |
-- Module      : AutoProof.Internal.Utils.Parser.Char
-- Copyright   : (c) Artem Mavrin, 2021
-- License     : BSD3
-- Maintainer  : artemvmavrin@gmail.com
-- Stability   : experimental
-- Portability : POSIX
--
-- Defines character- and string-related parsers.
module AutoProof.Internal.Utils.Parser.Char
  ( charIf,
    char,
    anyChar,
    spaces,
    string,
    oneOf,
  )
where

import AutoProof.Internal.Utils.Parser.Types (Parser (Parser))
import Control.Applicative (Alternative (empty, many, (<|>)))
import Data.Char (isSpace)

-- | Parse a single character if it satisfies a predicate
--
-- ==== __Examples__
--
-- >>> runParser (charIf isDigit) "123"
-- Just ("23",'1')
--
-- >>> runParser (charIf isDigit) "abc"
-- Nothing
charIf :: (Char -> Bool) -> Parser Char
charIf :: (Char -> Bool) -> Parser Char
charIf p :: Char -> Bool
p = (String -> Maybe (String, Char)) -> Parser Char
forall a. (String -> Maybe (String, a)) -> Parser a
Parser String -> Maybe (String, Char)
f
  where
    f :: String -> Maybe (String, Char)
f (c :: Char
c : cs :: String
cs) | Char -> Bool
p Char
c = (String, Char) -> Maybe (String, Char)
forall a. a -> Maybe a
Just (String
cs, Char
c)
    f _ = Maybe (String, Char)
forall a. Maybe a
Nothing

-- | Parse a specific character.
--
-- ==== __Examples__
--
-- >>> runParser (char 'a') "abc"
-- Just ("bc",'a')
--
-- >>> runParser (char 'a') "def"
-- Nothing
char :: Char -> Parser Char
char :: Char -> Parser Char
char c :: Char
c = (Char -> Bool) -> Parser Char
charIf (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c)

-- | Parse any character.
--
-- ==== __Examples__
--
-- >>> runParser anyChar "abc"
-- Just ("bc",'a')
--
-- >>> runParser anyChar ""
-- Nothing
anyChar :: Parser Char
anyChar :: Parser Char
anyChar = (Char -> Bool) -> Parser Char
charIf (Bool -> Char -> Bool
forall a b. a -> b -> a
const Bool
True)

-- | Parse one out of a list of characters.
--
-- ==== __Examples__
--
-- >>> runParser (oneOf ['a', 'b']) "bar"
-- Just ("ar",'b')
--
-- >>> runParser (oneOf ['a', 'b']) "foo"
-- Nothing
oneOf :: [Char] -> Parser Char
oneOf :: String -> Parser Char
oneOf = (Char -> Parser Char -> Parser Char)
-> Parser Char -> String -> Parser Char
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (Parser Char -> Parser Char -> Parser Char
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
(<|>) (Parser Char -> Parser Char -> Parser Char)
-> (Char -> Parser Char) -> Char -> Parser Char -> Parser Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Parser Char
char) Parser Char
forall (f :: * -> *) a. Alternative f => f a
empty

-- | Parse a specific string.
--
-- ==== __Examples__
--
-- >>> runParser (string "foo") "foobar"
-- Just ("bar","foo")
--
-- >>> runParser (string "foo") "fobar"
-- Nothing
string :: String -> Parser String
string :: String -> Parser String
string = (Char -> Parser Char) -> String -> Parser String
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Char -> Parser Char
char

-- | Parse zero or more spaces.
--
-- ==== __Examples__
--
-- >>> runParser spaces "   123"
-- Just ("123","   ")
--
-- >>> runParser spaces "123"
-- Just ("123","")
--
-- >>> runParser spaces ""
-- Just ("","")
spaces :: Parser String
spaces :: Parser String
spaces = Parser Char -> Parser String
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ((Char -> Bool) -> Parser Char
charIf Char -> Bool
isSpace)