nlql / picard / src / Control / Monad / Yoctoparsec / Class.hs
Class.hs
Raw
{-# OPTIONS_GHC -Wno-orphans #-}

module Control.Monad.Yoctoparsec.Class where

import Control.Applicative (Alternative (empty))
import Control.Monad (MonadPlus, foldM, mfilter)
import Control.Monad.Trans.Free (FreeF (..), FreeT (..))
import qualified Control.Monad.Yoctoparsec as Yocto
import Data.Foldable (Foldable (..))
import Text.Parser.Char (CharParsing (..))
import Text.Parser.Combinators (Parsing (..))
import Text.Parser.Token (TokenParsing)

instance (MonadPlus b, MonadFail b) => Parsing (FreeT ((->) i) b) where
  try = id
  (<?>) = const
  unexpected = fail
  eof = pure ()
  notFollowedBy _ = pure ()

instance (MonadPlus b, MonadFail b) => CharParsing (FreeT ((->) Char) b) where
  satisfy p = mfilter p Yocto.token

instance (MonadPlus b, MonadFail b) => TokenParsing (FreeT ((->) Char) b)

data Result b i a = Partial (i -> b (Result b i a)) | Done a [i]

instance (Show a, Show i) => Show (Result b i a) where
  show (Partial _) = "Partial"
  show (Done a is) = "Done (" <> show a <> ") (" <> show is <> ")"

runParser :: forall b i a. (Monad b, Foldable b) => Yocto.Parser b i a -> b (Result b i a)
runParser p = do
  val <- runFreeT p
  pure $ case val of
    Pure a -> Done a []
    Free f -> Partial (runParser . f)

feed1 :: forall b i a. Applicative b => Result b i a -> i -> b (Result b i a)
feed1 (Partial f) i = f i
feed1 (Done a is) i = pure $ Done a (is <> [i])

feed :: forall t b i a. (Foldable t, Monad b) => Result b i a -> t i -> b (Result b i a)
feed = foldM feed1

feedOnly :: forall t b i a. (Foldable t, Monad b, Alternative b) => Result b i a -> t i -> b (Result b i a)
feedOnly r t =
  go r (toList t)
  where
    go (Partial _) [] = empty
    go (Done a is) [] = pure $ Done a is
    go r' (i : is) = do
      r'' <- feed1 r' i
      go r'' is