symantic-parser-0.2.0.20210703: parsers/Parsers/Utils/Attoparsec.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
module Parsers.Utils.Attoparsec where
import Control.Applicative hiding (some)
import Control.Monad (Monad(..), MonadPlus)
import Data.Attoparsec.Combinator
import Data.Bool (Bool(..))
import Data.Char (Char)
import Data.Either (Either(..))
import Data.Eq (Eq(..))
import Data.Function (flip, ($), id)
import Data.Functor (void)
import Data.Maybe (Maybe(..), maybe)
import Data.String (String)
import Data.Word (Word8)
import qualified Data.List as List
import qualified Data.Text as T
import qualified Data.ByteString as BS
import qualified Data.Attoparsec.Internal.Types as AP
import qualified Data.Attoparsec.ByteString as AP.ByteString
import qualified Data.Attoparsec.ByteString.Char8 as AP.ByteString.Char8
import qualified Data.Attoparsec.Text as AP.Text
-- * Class 'Inputable'
class AP.Chunk inp => Inputable inp where
type Token inp
null :: inp -> Bool
empty :: inp
uncons :: inp -> Maybe (Token inp, inp)
satisfy :: (Token inp -> Bool) -> AP.Parser inp (Token inp)
char :: Char -> AP.Parser inp Char
notInClass :: String -> Token inp -> Bool
instance Inputable T.Text where
type Token T.Text = Char
null = T.null
empty = T.empty
uncons = T.uncons
satisfy = AP.Text.satisfy
char = AP.Text.char
notInClass = AP.Text.notInClass
instance Inputable BS.ByteString where
type Token BS.ByteString = Word8
null = BS.null
empty = BS.empty
uncons = BS.uncons
satisfy = AP.ByteString.satisfy
char = AP.ByteString.Char8.char
notInClass = AP.ByteString.notInClass
between :: Applicative f => f a -> f b -> f c -> f c
between o c p = o *> p <* c
match :: (Monad m, Eq a) => [a] -> m a -> (a -> m b) -> m b -> m b
match xs p f def = p >>= (\x -> if List.elem x xs then f x else def)
skipSome :: Alternative p => p a -> p ()
skipSome p = void (some p)
some :: Alternative p => p a -> p [a]
some = many1
maybeP :: Alternative p => p a -> p (Maybe a)
maybeP p = option Nothing (Just <$> p)
fromMaybeP :: Monad m => m (Maybe a) -> m a -> m a
fromMaybeP mmx d = mmx >>= maybe d return
(<+>) :: Alternative p => p a -> p b -> p (Either a b)
p <+> q = Left <$> p <|> Right <$> q
(<:>) :: Applicative p => p a -> p [a] -> p [a]
(<:>) = liftA2 (:)
(<~>) :: Applicative p => p a -> p b -> p (a, b)
(<~>) = liftA2 (,)
pfoldl1 :: Alternative p => (b -> a -> b) -> b -> p a -> p b
pfoldl1 f k p = List.foldl' f k <$> some p
(>?>) :: MonadPlus m => m a -> (a -> Bool) -> m a
m >?> f = m >>= \x -> if f x then return x else Control.Applicative.empty
chainPre :: Alternative p => p (a -> a) -> p a -> p a
chainPre op p = flip (List.foldr ($)) <$> many op <*> p
chainPost :: Alternative p => p a -> p (a -> a) -> p a
chainPost p op = List.foldl' (flip ($)) <$> p <*> many op
chainl1 :: Alternative p => p a -> p (a -> a -> a) -> p a
chainl1 p op = chainPost p (flip <$> op <*> p)
chainr1 :: Alternative p => p a -> p (a -> a -> a) -> p a
chainr1 p op = let go = p <**> ((flip <$> op <*> go) <|> pure id) in go
data Level p s a
= InfixL [p (a -> a -> a)]
| InfixR [p (a -> a -> a)]
| Prefix [p (a -> a)]
| Postfix [p (a -> a)]
precedence :: Alternative p => [Level p s a] -> p a -> p a
precedence levels atom = List.foldl' convert atom levels
where
convert x (InfixL ops) = chainl1 x (choice ops)
convert x (InfixR ops) = chainr1 x (choice ops)
convert x (Prefix ops) = chainPre (choice ops) x
convert x (Postfix ops) = chainPost x (choice ops)