    {-# LANGUAGE ViewPatterns #-}
    {-# LANGUAGE OverloadedStrings #-}

    module Data.SCargot.Parse
      ( -- * Parsing
        decode
      , decodeOne
        -- * Parsing Control
      , SExprParser
      , Reader
      , Comment
      , mkParser
      , setCarrier
      , addReader
      , setComment
        -- * Specific SExprParser Conversions
      , asRich
      , asWellFormed
      , withQuote
      ) where

    #if !MIN_VERSION_base(4,8,0)
    import Control.Applicative ((<$>), (<*), pure)
    #endif
    import           Control.Monad ((>=>))
    import           Data.Map.Strict (Map)
    import qualified Data.Map.Strict as M
    import           Data.Text (Text)
    import           Data.String (IsString)
    import           Text.Parsec ( (<|>)
                                 , (<?>)
                                 , char
                                 , eof
                                 , lookAhead
                                 , many1
                                 , runParser
                                 , skipMany
                                 )
    import           Text.Parsec.Char (anyChar, space)
    import           Text.Parsec.Text (Parser)

    import           Data.SCargot.Repr ( SExpr(..)
                                       , RichSExpr
                                       , WellFormedSExpr
                                       , toRich
                                       , toWellFormed
                                       )

    type ReaderMacroMap atom = Map Char (Reader atom)

    -- | A 'Reader' represents a reader macro: it takes a parser for
    --   the S-Expression type and performs as much or as little
    --   parsing as it would like, and then returns an S-expression.
    type Reader atom = (Parser (SExpr atom) -> Parser (SExpr atom))

    -- | A 'Comment' represents any kind of skippable comment. This
    --   parser __must__ be able to fail if a comment is not being
    --   recognized, and it __must__ not consume any input in case
    --   of failure.
    type Comment = Parser ()

    -- | A 'SExprParser' describes a parser for a particular value
    --   that has been serialized as an s-expression. The @atom@ parameter
    --   corresponds to a Haskell type used to represent the atoms,
    --   and the @carrier@ parameter corresponds to the parsed S-Expression
    --   structure.
    data SExprParser atom carrier = SExprParser
      { forall atom carrier. SExprParser atom carrier -> Parser atom
    sesPAtom   :: Parser atom
      , forall atom carrier.
    SExprParser atom carrier -> ReaderMacroMap atom
    readerMap  :: ReaderMacroMap atom
      , forall atom carrier. SExprParser atom carrier -> Maybe Comment
    comment    :: Maybe Comment
      , forall atom carrier.
    SExprParser atom carrier -> SExpr atom -> Either String carrier
    postparse  :: SExpr atom -> Either String carrier
      }

    -- | Create a basic 'SExprParser' when given a parser
    --   for an atom type.
    --
    --   >>> import Text.Parsec (alphaNum, many1)
    --   >>> let parser = mkParser (many1 alphaNum)
    --   >>> decode parser "(ele phant)"
    --   Right [SCons (SAtom "ele") (SCons (SAtom "phant") SNil)]
    mkParser :: Parser atom -> SExprParser atom (SExpr atom)
    mkParser :: forall atom. Parser atom -> SExprParser atom (SExpr atom)
    mkParser Parser atom
    parser = SExprParser
      { sesPAtom :: Parser atom
    sesPAtom   = Parser atom
    parser
      , readerMap :: ReaderMacroMap atom
    readerMap  = ReaderMacroMap atom
    forall k a. Map k a
    M.empty
      , comment :: Maybe Comment
    comment    = Maybe Comment
    forall a. Maybe a
    Nothing
      , postparse :: SExpr atom -> Either String (SExpr atom)
    postparse  = SExpr atom -> Either String (SExpr atom)
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
      }

    -- | Modify the carrier type for a 'SExprParser'. This is
    --   used internally to convert between various 'SExpr' representations,
    --   but could also be used externally to add an extra conversion layer
    --   onto a 'SExprParser'.
    --
    -- >>> import Text.Parsec (alphaNum, many1)
    -- >>> import Data.SCargot.Repr (toRich)
    -- >>> let parser = setCarrier (return . toRich) (mkParser (many1 alphaNum))
    -- >>> decode parser "(ele phant)"
    -- Right [RSlist [RSAtom "ele",RSAtom "phant"]]
    setCarrier :: (b -> Either String c) -> SExprParser a b -> SExprParser a c
    setCarrier :: forall b c a.
    (b -> Either String c) -> SExprParser a b -> SExprParser a c
    setCarrier b -> Either String c
    f SExprParser a b
    spec = SExprParser a b
    spec { postparse = postparse spec >=> f }

    -- | Convert the final output representation from the 'SExpr' type
    --   to the 'RichSExpr' type.
    --
    -- >>> import Text.Parsec (alphaNum, many1)
    -- >>> let parser = asRich (mkParser (many1 alphaNum))
    -- >>> decode parser "(ele phant)"
    -- Right [RSlist [RSAtom "ele",RSAtom "phant"]]
    asRich :: SExprParser a (SExpr b) -> SExprParser a (RichSExpr b)
    asRich :: forall a b. SExprParser a (SExpr b) -> SExprParser a (RichSExpr b)
    asRich = (SExpr b -> Either String (RichSExpr b))
    -> SExprParser a (SExpr b) -> SExprParser a (RichSExpr b)
    forall b c a.
    (b -> Either String c) -> SExprParser a b -> SExprParser a c
    setCarrier (RichSExpr b -> Either String (RichSExpr b)
    forall a. a -> Either String a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (RichSExpr b -> Either String (RichSExpr b))
    -> (SExpr b -> RichSExpr b)
    -> SExpr b
    -> Either String (RichSExpr b)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SExpr b -> RichSExpr b
    forall atom. SExpr atom -> RichSExpr atom
    toRich)

    -- | Convert the final output representation from the 'SExpr' type
    --   to the 'WellFormedSExpr' type.
    --
    -- >>> import Text.Parsec (alphaNum, many1)
    -- >>> let parser = asWellFormed (mkParser (many1 alphaNum))
    -- >>> decode parser "(ele phant)"
    -- Right [WFSList [WFSAtom "ele",WFSAtom "phant"]]
    asWellFormed :: SExprParser a (SExpr b) -> SExprParser a (WellFormedSExpr b)
    asWellFormed :: forall a b.
    SExprParser a (SExpr b) -> SExprParser a (WellFormedSExpr b)
    asWellFormed = (SExpr b -> Either String (WellFormedSExpr b))
    -> SExprParser a (SExpr b) -> SExprParser a (WellFormedSExpr b)
    forall b c a.
    (b -> Either String c) -> SExprParser a b -> SExprParser a c
    setCarrier SExpr b -> Either String (WellFormedSExpr b)
    forall atom. SExpr atom -> Either String (WellFormedSExpr atom)
    toWellFormed

    -- | Add the ability to execute some particular reader macro, as
    --   defined by its initial character and the 'Parser' which returns
    --   the parsed S-Expression. The 'Reader' is passed a 'Parser' which
    --   can be recursively called to parse more S-Expressions, and begins
    --   parsing after the reader character has been removed from the
    --   stream.
    --
    -- >>> import Text.Parsec (alphaNum, char, many1)
    -- >>> let vecReader p = (char ']' *> pure SNil) <|> (SCons <$> p <*> vecReader p)
    -- >>> let parser = addReader '[' vecReader (mkParser (many1 alphaNum))
    -- >>> decode parser "(an [ele phant])"
    -- Right [SCons (SAtom "an") (SCons (SCons (SAtom "ele") (SCons (SAtom "phant") SNil)) SNil)]

    addReader :: Char -> Reader a -> SExprParser a c -> SExprParser a c
    addReader :: forall a c. Char -> Reader a -> SExprParser a c -> SExprParser a c
    addReader Char
    c Reader a
    reader SExprParser a c
    spec = SExprParser a c
    spec
      { readerMap = M.insert c reader (readerMap spec) }

    -- | Add the ability to ignore some kind of comment. This gets
    --   factored into whitespace parsing, and it's very important that
    --   the parser supplied __be able to fail__ (as otherwise it will
    --   cause an infinite loop), and also that it __not consume any input__
    --   (which may require it to be wrapped in 'try'.)
    --
    -- >>> import Text.Parsec (alphaNum, anyChar, manyTill, many1, string)
    -- >>> let comment = string "//" *> manyTill anyChar newline *> pure ()
    -- >>> let parser = setComment comment (mkParser (many1 alphaNum))
    -- >>> decode parser "(ele //a comment\n  phant)"
    -- Right [SCons (SAtom "ele") (SCons (SAtom "phant") SNil)]

    setComment :: Comment -> SExprParser a c -> SExprParser a c
    setComment :: forall a c. Comment -> SExprParser a c -> SExprParser a c
    setComment Comment
    c SExprParser a c
    spec = SExprParser a c
    spec { comment = Just (c <?> "comment") }

    -- | Add the ability to understand a quoted S-Expression.
    --   Many Lisps use @'sexpr@ as sugar for @(quote sexpr)@. This
    --   assumes that the underlying atom type implements the "IsString"
    --   class, and will create the @quote@ atom using @fromString "quote"@.
    --
    -- >>> import Text.Parsec (alphaNum, many1)
    -- >>> let parser = withQuote (mkParser (many1 alphaNum))
    -- >>> decode parser "'elephant"
    -- Right [SCons (SAtom "quote") (SCons (SAtom "foo") SNil)]
    withQuote :: IsString t => SExprParser t (SExpr t) -> SExprParser t (SExpr t)
    withQuote :: forall t.
    IsString t =>
    SExprParser t (SExpr t) -> SExprParser t (SExpr t)
    withQuote = Char
    -> Reader t -> SExprParser t (SExpr t) -> SExprParser t (SExpr t)
    forall a c. Char -> Reader a -> SExprParser a c -> SExprParser a c
    addReader Char
    '\'' ((SExpr t -> SExpr t) -> Reader t
    forall a b.
    (a -> b)
    -> ParsecT Text () Identity a -> ParsecT Text () Identity b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap SExpr t -> SExpr t
    forall {atom}. IsString atom => SExpr atom -> SExpr atom
    go)
      where go :: SExpr atom -> SExpr atom
    go SExpr atom
    s  = SExpr atom -> SExpr atom -> SExpr atom
    forall atom. SExpr atom -> SExpr atom -> SExpr atom
    SCons SExpr atom
    "quote" (SExpr atom -> SExpr atom -> SExpr atom
    forall atom. SExpr atom -> SExpr atom -> SExpr atom
    SCons SExpr atom
    s SExpr atom
    forall atom. SExpr atom
    SNil)

    peekChar :: Parser (Maybe Char)
    peekChar :: Parser (Maybe Char)
    peekChar = Char -> Maybe Char
    forall a. a -> Maybe a
    Just (Char -> Maybe Char)
    -> ParsecT Text () Identity Char -> Parser (Maybe Char)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> ParsecT Text () Identity Char -> ParsecT Text () Identity Char
    forall s (m :: * -> *) t u a.
    Stream s m t =>
    ParsecT s u m a -> ParsecT s u m a
    lookAhead ParsecT Text () Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    anyChar Parser (Maybe Char) -> Parser (Maybe Char) -> Parser (Maybe Char)
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
    <|> Maybe Char -> Parser (Maybe Char)
    forall a. a -> ParsecT Text () Identity a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Maybe Char
    forall a. Maybe a
    Nothing

    parseGenericSExpr ::
      Parser atom  -> ReaderMacroMap atom -> Parser () -> Parser (SExpr atom)
    parseGenericSExpr :: forall atom.
    Parser atom
    -> ReaderMacroMap atom -> Comment -> Parser (SExpr atom)
    parseGenericSExpr Parser atom
    atom ReaderMacroMap atom
    reader Comment
    skip = do
      let sExpr :: ParsecT Text () Identity (SExpr atom)
    sExpr = Parser atom
    -> ReaderMacroMap atom
    -> Comment
    -> ParsecT Text () Identity (SExpr atom)
    forall atom.
    Parser atom
    -> ReaderMacroMap atom -> Comment -> Parser (SExpr atom)
    parseGenericSExpr Parser atom
    atom ReaderMacroMap atom
    reader Comment
    skip ParsecT Text () Identity (SExpr atom)
    -> String -> ParsecT Text () Identity (SExpr atom)
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> String -> ParsecT s u m a
    <?> String
    "s-expr"
      Comment
    skip
      c <- Parser (Maybe Char)
    peekChar
      r <- case c of
        Maybe Char
    Nothing -> String -> ParsecT Text () Identity (SExpr atom)
    forall a. String -> ParsecT Text () Identity a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "Unexpected end of input"
        Just Char
    '(' -> Char -> ParsecT Text () Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '(' ParsecT Text () Identity Char -> Comment -> Comment
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Comment
    skip Comment
    -> ParsecT Text () Identity (SExpr atom)
    -> ParsecT Text () Identity (SExpr atom)
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> ParsecT Text () Identity (SExpr atom)
    -> Comment -> ParsecT Text () Identity (SExpr atom)
    forall atom. Parser (SExpr atom) -> Comment -> Parser (SExpr atom)
    parseList ParsecT Text () Identity (SExpr atom)
    sExpr Comment
    skip
        Just ((Char
     -> ReaderMacroMap atom
     -> Maybe
          (ParsecT Text () Identity (SExpr atom)
           -> ParsecT Text () Identity (SExpr atom)))
    -> ReaderMacroMap atom
    -> Char
    -> Maybe
         (ParsecT Text () Identity (SExpr atom)
          -> ParsecT Text () Identity (SExpr atom))
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Char
    -> ReaderMacroMap atom
    -> Maybe
         (ParsecT Text () Identity (SExpr atom)
          -> ParsecT Text () Identity (SExpr atom))
    forall k a. Ord k => k -> Map k a -> Maybe a
    M.lookup ReaderMacroMap atom
    reader -> Just ParsecT Text () Identity (SExpr atom)
    -> ParsecT Text () Identity (SExpr atom)
    r) -> ParsecT Text () Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    anyChar ParsecT Text () Identity Char
    -> ParsecT Text () Identity (SExpr atom)
    -> ParsecT Text () Identity (SExpr atom)
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> ParsecT Text () Identity (SExpr atom)
    -> ParsecT Text () Identity (SExpr atom)
    r ParsecT Text () Identity (SExpr atom)
    sExpr
        Maybe Char
    _ -> atom -> SExpr atom
    forall atom. atom -> SExpr atom
    SAtom (atom -> SExpr atom)
    -> Parser atom -> ParsecT Text () Identity (SExpr atom)
    forall a b.
    (a -> b)
    -> ParsecT Text () Identity a -> ParsecT Text () Identity b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` Parser atom
    atom
      skip
      return r

    parseList :: Parser (SExpr atom) -> Parser () -> Parser (SExpr atom)
    parseList :: forall atom. Parser (SExpr atom) -> Comment -> Parser (SExpr atom)
    parseList Parser (SExpr atom)
    sExpr Comment
    skip = do
      i <- Parser (Maybe Char)
    peekChar
      case i of
        Maybe Char
    Nothing  -> String -> Parser (SExpr atom)
    forall a. String -> ParsecT Text () Identity a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "Unexpected end of input"
        Just Char
    ')' -> Char -> ParsecT Text () Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    ')' ParsecT Text () Identity Char
    -> Parser (SExpr atom) -> Parser (SExpr atom)
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> SExpr atom -> Parser (SExpr atom)
    forall a. a -> ParsecT Text () Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return SExpr atom
    forall atom. SExpr atom
    SNil
        Maybe Char
    _        -> do
          car <- Parser (SExpr atom)
    sExpr
          skip
          c <- peekChar
          case c of
            Just Char
    '.' -> do
              _ <- Char -> ParsecT Text () Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    '.'
              cdr <- sExpr
              skip
              _ <- char ')'
              skip
              return (SCons car cdr)
            Just Char
    ')' -> do
              _ <- Char -> ParsecT Text () Identity Char
    forall s (m :: * -> *) u.
    Stream s m Char =>
    Char -> ParsecT s u m Char
    char Char
    ')'
              skip
              return (SCons car SNil)
            Maybe Char
    _ -> do
              cdr <- Parser (SExpr atom) -> Comment -> Parser (SExpr atom)
    forall atom. Parser (SExpr atom) -> Comment -> Parser (SExpr atom)
    parseList Parser (SExpr atom)
    sExpr Comment
    skip
              return (SCons car cdr)

    -- | Given a CommentMap, create the corresponding parser to
    --   skip those comments (if they exist).
    buildSkip :: Maybe (Parser ()) -> Parser ()
    buildSkip :: Maybe Comment -> Comment
    buildSkip Maybe Comment
    Nothing  = ParsecT Text () Identity Char -> Comment
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
    skipMany ParsecT Text () Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    space
    buildSkip (Just Comment
    c) = Comment
    alternate
      where alternate :: Comment
    alternate = ParsecT Text () Identity Char -> Comment
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
    skipMany ParsecT Text () Identity Char
    forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
    space Comment -> Comment -> Comment
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> ((Comment
    c Comment -> Comment -> Comment
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Comment
    alternate) Comment -> Comment -> Comment
    forall s u (m :: * -> *) a.
    ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
    <|> () -> Comment
    forall a. a -> ParsecT Text () Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ())

    doParse :: Parser a -> Text -> Either String a
    doParse :: forall a. Parser a -> Text -> Either String a
    doParse Parser a
    p Text
    t = case Parser a -> () -> String -> Text -> Either ParseError a
    forall s t u a.
    Stream s Identity t =>
    Parsec s u a -> u -> String -> s -> Either ParseError a
    runParser Parser a
    p () String
    "" Text
    t of
      Left ParseError
    err -> String -> Either String a
    forall a b. a -> Either a b
    Left (ParseError -> String
    forall a. Show a => a -> String
    show ParseError
    err)
      Right a
    x  -> a -> Either String a
    forall a b. b -> Either a b
    Right a
    x

    -- | Decode a single S-expression. If any trailing input is left after
    --   the S-expression (ignoring comments or whitespace) then this
    --   will fail: for those cases, use 'decode', which returns a list of
    --   all the S-expressions found at the top level.
    decodeOne :: SExprParser atom carrier -> Text -> Either String carrier
    decodeOne :: forall atom carrier.
    SExprParser atom carrier -> Text -> Either String carrier
    decodeOne SExprParser atom carrier
    spec = Parser (SExpr atom) -> Text -> Either String (SExpr atom)
    forall a. Parser a -> Text -> Either String a
    doParse (Parser (SExpr atom)
    parser Parser (SExpr atom) -> Comment -> Parser (SExpr atom)
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Comment
    forall s (m :: * -> *) t u.
    (Stream s m t, Show t) =>
    ParsecT s u m ()
    eof) (Text -> Either String (SExpr atom))
    -> (SExpr atom -> Either String carrier)
    -> Text
    -> Either String carrier
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> (SExprParser atom carrier -> SExpr atom -> Either String carrier
    forall atom carrier.
    SExprParser atom carrier -> SExpr atom -> Either String carrier
    postparse SExprParser atom carrier
    spec)
      where parser :: Parser (SExpr atom)
    parser = Parser atom
    -> ReaderMacroMap atom -> Comment -> Parser (SExpr atom)
    forall atom.
    Parser atom
    -> ReaderMacroMap atom -> Comment -> Parser (SExpr atom)
    parseGenericSExpr
                       (SExprParser atom carrier -> Parser atom
    forall atom carrier. SExprParser atom carrier -> Parser atom
    sesPAtom SExprParser atom carrier
    spec)
                       (SExprParser atom carrier -> ReaderMacroMap atom
    forall atom carrier.
    SExprParser atom carrier -> ReaderMacroMap atom
    readerMap SExprParser atom carrier
    spec)
                       (Maybe Comment -> Comment
    buildSkip (SExprParser atom carrier -> Maybe Comment
    forall atom carrier. SExprParser atom carrier -> Maybe Comment
    comment SExprParser atom carrier
    spec))

    -- | Decode several S-expressions according to a given 'SExprParser'. This
    --   will return a list of every S-expression that appears at the top-level
    --   of the document.
    decode :: SExprParser atom carrier -> Text -> Either String [carrier]
    decode :: forall atom carrier.
    SExprParser atom carrier -> Text -> Either String [carrier]
    decode SExprParser atom carrier
    spec =
      Parser [SExpr atom] -> Text -> Either String [SExpr atom]
    forall a. Parser a -> Text -> Either String a
    doParse (ParsecT Text () Identity (SExpr atom) -> Parser [SExpr atom]
    forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
    many1 ParsecT Text () Identity (SExpr atom)
    parser Parser [SExpr atom] -> Comment -> Parser [SExpr atom]
    forall a b.
    ParsecT Text () Identity a
    -> ParsecT Text () Identity b -> ParsecT Text () Identity a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* Comment
    forall s (m :: * -> *) t u.
    (Stream s m t, Show t) =>
    ParsecT s u m ()
    eof) (Text -> Either String [SExpr atom])
    -> ([SExpr atom] -> Either String [carrier])
    -> Text
    -> Either String [carrier]
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> (SExpr atom -> Either String carrier)
    -> [SExpr atom] -> Either String [carrier]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM (SExprParser atom carrier -> SExpr atom -> Either String carrier
    forall atom carrier.
    SExprParser atom carrier -> SExpr atom -> Either String carrier
    postparse SExprParser atom carrier
    spec)
        where parser :: ParsecT Text () Identity (SExpr atom)
    parser = Parser atom
    -> ReaderMacroMap atom
    -> Comment
    -> ParsecT Text () Identity (SExpr atom)
    forall atom.
    Parser atom
    -> ReaderMacroMap atom -> Comment -> Parser (SExpr atom)
    parseGenericSExpr
                         (SExprParser atom carrier -> Parser atom
    forall atom carrier. SExprParser atom carrier -> Parser atom
    sesPAtom SExprParser atom carrier
    spec)
                         (SExprParser atom carrier -> ReaderMacroMap atom
    forall atom carrier.
    SExprParser atom carrier -> ReaderMacroMap atom
    readerMap SExprParser atom carrier
    spec)
                         (Maybe Comment -> Comment
    buildSkip (SExprParser atom carrier -> Maybe Comment
    forall atom carrier. SExprParser atom carrier -> Maybe Comment
    comment SExprParser atom carrier
    spec))

    {-
    -- | Encode (without newlines) a single S-expression.
    encodeSExpr :: SExpr atom -> (atom -> Text) -> Text
    encodeSExpr SNil _         = "()"
    encodeSExpr (SAtom s) t    = t s
    encodeSExpr (SCons x xs) t = go xs (encodeSExpr x t)
      where go (SAtom s) rs = "(" <> rs <> " . " <> t s <> ")"
            go SNil rs      = "(" <> rs <> ")"
            go (SCons x xs) rs = go xs (rs <> " " <> encodeSExpr x t)

    -- | Emit an S-Expression in a machine-readable way. This does no
    --   pretty-printing or indentation, and produces no comments.
    encodeOne :: SExprParser atom carrier -> carrier -> Text
    encodeOne spec c = encodeSExpr (preserial spec c) (sesSAtom spec)

    encode :: SExprParser atom carrier -> [carrier] -> Text
    encode spec cs = T.concat (map (encodeOne spec) cs)
    -}