-- |
-- MonadPlus utilities.
-- For instance, they can be applied with parsing libraries.
module VectorBuilder.MonadPlus where

import qualified Data.Vector.Generic as C
import qualified VectorBuilder.Builder as A
import VectorBuilder.Prelude
import qualified VectorBuilder.Vector as B

{-# INLINEABLE many #-}
many :: (MonadPlus m, C.Vector vector element) => m element -> m (vector element)
many :: forall (m :: * -> *) (vector :: * -> *) element.
(MonadPlus m, Vector vector element) =>
m element -> m (vector element)
many m element
m =
  (Builder element -> vector element)
-> m (Builder element) -> m (vector element)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Builder element -> vector element
forall (vector :: * -> *) element.
Vector vector element =>
Builder element -> vector element
B.build (m element -> m (Builder element)
forall (m :: * -> *) element.
MonadPlus m =>
m element -> m (Builder element)
manyBuilder m element
m)

{-# INLINEABLE manyBuilder #-}
manyBuilder :: (MonadPlus m) => m element -> m (A.Builder element)
manyBuilder :: forall (m :: * -> *) element.
MonadPlus m =>
m element -> m (Builder element)
manyBuilder m element
m =
  Builder element -> m (Builder element)
loop Builder element
forall a. Monoid a => a
mempty
  where
    loop :: Builder element -> m (Builder element)
loop !Builder element
builder =
      m (Builder element) -> m (Builder element) -> m (Builder element)
forall a. m a -> m a -> m a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
mplus
        ( do
            !element <- m element
m
            loop (builder <> A.singleton element)
        )
        (Builder element -> m (Builder element)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Builder element
builder)

{-# INLINEABLE many1 #-}
many1 :: (MonadPlus m, C.Vector vector element) => m element -> m (vector element)
many1 :: forall (m :: * -> *) (vector :: * -> *) element.
(MonadPlus m, Vector vector element) =>
m element -> m (vector element)
many1 m element
m =
  do
    firstElement <- m element
m
    builder <- manyBuilder m
    return (B.build (A.singleton firstElement <> builder))

{-# INLINEABLE sepBy #-}
sepBy :: (MonadPlus m, C.Vector vector element) => m element -> m separator -> m (vector element)
sepBy :: forall (m :: * -> *) (vector :: * -> *) element separator.
(MonadPlus m, Vector vector element) =>
m element -> m separator -> m (vector element)
sepBy m element
elementM m separator
separatorM =
  m (vector element) -> m (vector element) -> m (vector element)
forall a. m a -> m a -> m a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
mplus (m element -> m separator -> m (vector element)
forall (m :: * -> *) (vector :: * -> *) element separator.
(MonadPlus m, Vector vector element) =>
m element -> m separator -> m (vector element)
sepBy1 m element
elementM m separator
separatorM) (vector element -> m (vector element)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return vector element
forall (v :: * -> *) a. Vector v a => v a
C.empty)

{-# INLINEABLE sepBy1 #-}
sepBy1 :: (MonadPlus m, C.Vector vector element) => m element -> m separator -> m (vector element)
sepBy1 :: forall (m :: * -> *) (vector :: * -> *) element separator.
(MonadPlus m, Vector vector element) =>
m element -> m separator -> m (vector element)
sepBy1 m element
elementM m separator
separatorM =
  do
    firstElement <- m element
elementM
    builder <- loop (A.singleton firstElement)
    return (B.build builder)
  where
    loop :: Builder element -> m (Builder element)
loop Builder element
builder =
      m (Builder element) -> m (Builder element) -> m (Builder element)
forall a. m a -> m a -> m a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
mplus
        ( do
            m separator
separatorM
            !element <- m element
elementM
            loop (builder <> A.singleton element)
        )
        (Builder element -> m (Builder element)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Builder element
builder)