    {-# LANGUAGE FlexibleContexts  #-}
    {- |
    Module      : Text.Pandoc.Lua.Filter
    Copyright   : © 2012–2020 John MacFarlane,
                  © 2017-2020 Albert Krewinkel
    License     : GNU GPL, version 2 or above
    Maintainer  : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
    Stability   : alpha

    Types and functions for running Lua filters.
    -}
    module Text.Pandoc.Lua.Filter ( LuaFilterFunction
                                  , LuaFilter
                                  , runFilterFile
                                  , walkInlines
                                  , walkBlocks
                                  , module Text.Pandoc.Lua.Walk
                                  ) where
    import Control.Applicative ((<|>))
    import Control.Monad (mplus, (>=>))
    import Control.Monad.Catch (finally)
    import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf,
                      showConstr, toConstr, tyconUQname)
    import Data.Foldable (foldrM)
    import Data.Map (Map)
    import Data.Maybe (fromMaybe)
    import Foreign.Lua (Lua, Peekable, Pushable)
    import Text.Pandoc.Definition
    import Text.Pandoc.Lua.Marshaling ()
    import Text.Pandoc.Lua.Marshaling.List (List (..))
    import Text.Pandoc.Lua.Walk (SingletonsList (..))
    import Text.Pandoc.Walk (Walkable (walkM))

    import qualified Data.Map.Strict as Map
    import qualified Foreign.Lua as Lua
    import qualified Text.Pandoc.Lua.Util as LuaUtil

    -- | Transform document using the filter defined in the given file.
    runFilterFile :: FilePath -> Pandoc -> Lua Pandoc
    runFilterFile :: FilePath -> Pandoc -> Lua Pandoc
    runFilterFile filterPath :: FilePath
    filterPath doc :: Pandoc
    doc = do
      StackIndex
    top <- Lua StackIndex
    Lua.gettop
      Status
    stat <- FilePath -> Lua Status
    LuaUtil.dofileWithTraceback FilePath
    filterPath
      if Status
    stat Status -> Status -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Status
    Lua.OK
        then Lua Pandoc
    forall a. Lua a
    Lua.throwTopMessage
        else do
          StackIndex
    newtop <- Lua StackIndex
    Lua.gettop
          -- Use the returned filters, or the implicitly defined global
          -- filter if nothing was returned.
          [LuaFilter]
    luaFilters <- if StackIndex
    newtop StackIndex -> StackIndex -> StackIndex
    forall a. Num a => a -> a -> a
    - StackIndex
    top StackIndex -> StackIndex -> Bool
    forall a. Ord a => a -> a -> Bool
    >= 1
                        then StackIndex -> Lua [LuaFilter]
    forall a. Peekable a => StackIndex -> Lua a
    Lua.peek StackIndex
    Lua.stackTop
                        else Lua ()
    Lua.pushglobaltable Lua () -> Lua [LuaFilter] -> Lua [LuaFilter]
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> (LuaFilter -> [LuaFilter]) -> Lua LuaFilter -> Lua [LuaFilter]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (LuaFilter -> [LuaFilter] -> [LuaFilter]
    forall a. a -> [a] -> [a]
    :[]) Lua LuaFilter
    forall a. Peekable a => Lua a
    Lua.popValue
          [LuaFilter] -> Pandoc -> Lua Pandoc
    runAll [LuaFilter]
    luaFilters Pandoc
    doc

    runAll :: [LuaFilter] -> Pandoc -> Lua Pandoc
    runAll :: [LuaFilter] -> Pandoc -> Lua Pandoc
    runAll = (LuaFilter -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc)
    -> (Pandoc -> Lua Pandoc) -> [LuaFilter] -> Pandoc -> Lua Pandoc
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr ((Pandoc -> Lua Pandoc)
    -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    (>=>) ((Pandoc -> Lua Pandoc)
     -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc)
    -> (LuaFilter -> Pandoc -> Lua Pandoc)
    -> LuaFilter
    -> (Pandoc -> Lua Pandoc)
    -> Pandoc
    -> Lua Pandoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . LuaFilter -> Pandoc -> Lua Pandoc
    walkMWithLuaFilter) Pandoc -> Lua Pandoc
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    -- | Filter function stored in the registry
    newtype LuaFilterFunction = LuaFilterFunction Lua.Reference

    -- | Collection of filter functions (at most one function per element
    -- constructor)
    newtype LuaFilter = LuaFilter (Map String LuaFilterFunction)

    instance Peekable LuaFilter where
      peek :: StackIndex -> Lua LuaFilter
    peek idx :: StackIndex
    idx = do
        let constrs :: [FilePath]
    constrs = FilePath
    listOfInlinesFilterName
                    FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : FilePath
    listOfBlocksFilterName
                    FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : FilePath
    metaFilterName
                    FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : [FilePath]
    pandocFilterNames
                    [FilePath] -> [FilePath] -> [FilePath]
    forall a. [a] -> [a] -> [a]
    ++ [FilePath]
    blockElementNames
                    [FilePath] -> [FilePath] -> [FilePath]
    forall a. [a] -> [a] -> [a]
    ++ [FilePath]
    inlineElementNames
        let go :: FilePath
    -> Map FilePath LuaFilterFunction
    -> Lua (Map FilePath LuaFilterFunction)
    go constr :: FilePath
    constr acc :: Map FilePath LuaFilterFunction
    acc = do
              StackIndex -> FilePath -> Lua ()
    Lua.getfield StackIndex
    idx FilePath
    constr
              Maybe LuaFilterFunction
    filterFn <- Lua (Maybe LuaFilterFunction)
    registerFilterFunction
              Map FilePath LuaFilterFunction
    -> Lua (Map FilePath LuaFilterFunction)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Map FilePath LuaFilterFunction
     -> Lua (Map FilePath LuaFilterFunction))
    -> Map FilePath LuaFilterFunction
    -> Lua (Map FilePath LuaFilterFunction)
    forall a b. (a -> b) -> a -> b
    $ case Maybe LuaFilterFunction
    filterFn of
                Nothing -> Map FilePath LuaFilterFunction
    acc
                Just fn :: LuaFilterFunction
    fn -> FilePath
    -> LuaFilterFunction
    -> Map FilePath LuaFilterFunction
    -> Map FilePath LuaFilterFunction
    forall k a. Ord k => k -> a -> Map k a -> Map k a
    Map.insert FilePath
    constr LuaFilterFunction
    fn Map FilePath LuaFilterFunction
    acc
        Map FilePath LuaFilterFunction -> LuaFilter
    LuaFilter (Map FilePath LuaFilterFunction -> LuaFilter)
    -> Lua (Map FilePath LuaFilterFunction) -> Lua LuaFilter
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (FilePath
     -> Map FilePath LuaFilterFunction
     -> Lua (Map FilePath LuaFilterFunction))
    -> Map FilePath LuaFilterFunction
    -> [FilePath]
    -> Lua (Map FilePath LuaFilterFunction)
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> b -> m b) -> b -> t a -> m b
    foldrM FilePath
    -> Map FilePath LuaFilterFunction
    -> Lua (Map FilePath LuaFilterFunction)
    go Map FilePath LuaFilterFunction
    forall k a. Map k a
    Map.empty [FilePath]
    constrs

    -- | Register the function at the top of the stack as a filter function in the
    -- registry.
    registerFilterFunction :: Lua (Maybe LuaFilterFunction)
    registerFilterFunction :: Lua (Maybe LuaFilterFunction)
    registerFilterFunction = do
      Bool
    isFn <- StackIndex -> Lua Bool
    Lua.isfunction StackIndex
    Lua.stackTop
      if Bool
    isFn
        then LuaFilterFunction -> Maybe LuaFilterFunction
    forall a. a -> Maybe a
    Just (LuaFilterFunction -> Maybe LuaFilterFunction)
    -> (Reference -> LuaFilterFunction)
    -> Reference
    -> Maybe LuaFilterFunction
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Reference -> LuaFilterFunction
    LuaFilterFunction (Reference -> Maybe LuaFilterFunction)
    -> Lua Reference -> Lua (Maybe LuaFilterFunction)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> StackIndex -> Lua Reference
    Lua.ref StackIndex
    Lua.registryindex
        else Maybe LuaFilterFunction
    forall a. Maybe a
    Nothing Maybe LuaFilterFunction -> Lua () -> Lua (Maybe LuaFilterFunction)
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ StackIndex -> Lua ()
    Lua.pop 1

    -- | Retrieve filter function from registry and push it to the top of the stack.
    pushFilterFunction :: LuaFilterFunction -> Lua ()
    pushFilterFunction :: LuaFilterFunction -> Lua ()
    pushFilterFunction (LuaFilterFunction fnRef :: Reference
    fnRef) =
      StackIndex -> Reference -> Lua ()
    Lua.getref StackIndex
    Lua.registryindex Reference
    fnRef

    -- | Fetch either a list of elements from the stack. If there is a single
    -- element instead of a list, fetch that element as a singleton list. If the top
    -- of the stack is nil, return the default element that was passed to this
    -- function. If none of these apply, raise an error.
    elementOrList :: Peekable a => a -> Lua [a]
    elementOrList :: a -> Lua [a]
    elementOrList x :: a
    x = do
      let topOfStack :: StackIndex
    topOfStack = StackIndex
    Lua.stackTop
      Bool
    elementUnchanged <- StackIndex -> Lua Bool
    Lua.isnil StackIndex
    topOfStack
      if Bool
    elementUnchanged
        then [a
    x] [a] -> Lua () -> Lua [a]
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ StackIndex -> Lua ()
    Lua.pop 1
        else do
           Either FilePath a
    mbres <- StackIndex -> Lua (Either FilePath a)
    forall a. Peekable a => StackIndex -> Lua (Either FilePath a)
    Lua.peekEither StackIndex
    topOfStack
           case Either FilePath a
    mbres of
             Right res :: a
    res -> [a
    res] [a] -> Lua () -> Lua [a]
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ StackIndex -> Lua ()
    Lua.pop 1
             Left _    -> StackIndex -> Lua [a]
    forall a. Peekable a => StackIndex -> Lua [a]
    Lua.peekList StackIndex
    topOfStack Lua [a] -> Lua () -> Lua [a]
    forall (m :: * -> *) a b. MonadMask m => m a -> m b -> m a
    `finally` StackIndex -> Lua ()
    Lua.pop 1

    -- | Pop and return a value from the stack; if the value at the top of
    -- the stack is @nil@, return the fallback element.
    popOption :: Peekable a => a -> Lua a
    popOption :: a -> Lua a
    popOption fallback :: a
    fallback = a -> Maybe a -> a
    forall a. a -> Maybe a -> a
    fromMaybe a
    fallback (Maybe a -> a) -> (Optional a -> Maybe a) -> Optional a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Optional a -> Maybe a
    forall a. Optional a -> Maybe a
    Lua.fromOptional (Optional a -> a) -> Lua (Optional a) -> Lua a
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Lua (Optional a)
    forall a. Peekable a => Lua a
    Lua.popValue

    -- | Apply filter on a sequence of AST elements. Both lists and single
    -- value are accepted as filter function return values.
    runOnSequence :: (Data a, Peekable a, Pushable a)
                  => LuaFilter -> SingletonsList a -> Lua (SingletonsList a)
    runOnSequence :: LuaFilter -> SingletonsList a -> Lua (SingletonsList a)
    runOnSequence (LuaFilter fnMap :: Map FilePath LuaFilterFunction
    fnMap) (SingletonsList xs :: [a]
    xs) =
      [a] -> SingletonsList a
    forall a. [a] -> SingletonsList a
    SingletonsList ([a] -> SingletonsList a) -> Lua [a] -> Lua (SingletonsList a)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (a -> Lua [a]) -> [a] -> Lua [a]
    forall (m :: * -> *) a. Monad m => (a -> m [a]) -> [a] -> m [a]
    mconcatMapM a -> Lua [a]
    forall a. (Data a, Peekable a, Pushable a) => a -> Lua [a]
    tryFilter [a]
    xs
     where
      tryFilter :: (Data a, Peekable a, Pushable a) => a -> Lua [a]
      tryFilter :: a -> Lua [a]
    tryFilter x :: a
    x =
        let filterFnName :: FilePath
    filterFnName = Constr -> FilePath
    showConstr (a -> Constr
    forall a. Data a => a -> Constr
    toConstr a
    x)
            catchAllName :: FilePath
    catchAllName = FilePath -> FilePath
    tyconUQname (FilePath -> FilePath) -> FilePath -> FilePath
    forall a b. (a -> b) -> a -> b
    $ DataType -> FilePath
    dataTypeName (a -> DataType
    forall a. Data a => a -> DataType
    dataTypeOf a
    x)
        in case FilePath
    -> Map FilePath LuaFilterFunction -> Maybe LuaFilterFunction
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup FilePath
    filterFnName Map FilePath LuaFilterFunction
    fnMap Maybe LuaFilterFunction
    -> Maybe LuaFilterFunction -> Maybe LuaFilterFunction
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> FilePath
    -> Map FilePath LuaFilterFunction -> Maybe LuaFilterFunction
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup FilePath
    catchAllName Map FilePath LuaFilterFunction
    fnMap of
             Just fn :: LuaFilterFunction
    fn -> LuaFilterFunction -> a -> Lua ()
    forall a. Pushable a => LuaFilterFunction -> a -> Lua ()
    runFilterFunction LuaFilterFunction
    fn a
    x Lua () -> Lua [a] -> Lua [a]
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> a -> Lua [a]
    forall a. Peekable a => a -> Lua [a]
    elementOrList a
    x
             Nothing -> [a] -> Lua [a]
    forall (m :: * -> *) a. Monad m => a -> m a
    return [a
    x]

    -- | Try filtering the given value without type error corrections on
    -- the return value.
    runOnValue :: (Data a, Peekable a, Pushable a)
               => String -> LuaFilter -> a -> Lua a
    runOnValue :: FilePath -> LuaFilter -> a -> Lua a
    runOnValue filterFnName :: FilePath
    filterFnName (LuaFilter fnMap :: Map FilePath LuaFilterFunction
    fnMap) x :: a
    x =
      case FilePath
    -> Map FilePath LuaFilterFunction -> Maybe LuaFilterFunction
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup FilePath
    filterFnName Map FilePath LuaFilterFunction
    fnMap of
        Just fn :: LuaFilterFunction
    fn -> LuaFilterFunction -> a -> Lua ()
    forall a. Pushable a => LuaFilterFunction -> a -> Lua ()
    runFilterFunction LuaFilterFunction
    fn a
    x Lua () -> Lua a -> Lua a
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> a -> Lua a
    forall a. Peekable a => a -> Lua a
    popOption a
    x
        Nothing -> a -> Lua a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    x

    -- | Push a value to the stack via a lua filter function. The filter function is
    -- called with given element as argument and is expected to return an element.
    -- Alternatively, the function can return nothing or nil, in which case the
    -- element is left unchanged.
    runFilterFunction :: Pushable a => LuaFilterFunction -> a -> Lua ()
    runFilterFunction :: LuaFilterFunction -> a -> Lua ()
    runFilterFunction lf :: LuaFilterFunction
    lf x :: a
    x = do
      LuaFilterFunction -> Lua ()
    pushFilterFunction LuaFilterFunction
    lf
      a -> Lua ()
    forall a. Pushable a => a -> Lua ()
    Lua.push a
    x
      NumArgs -> NumResults -> Lua ()
    LuaUtil.callWithTraceback 1 1

    walkMWithLuaFilter :: LuaFilter -> Pandoc -> Lua Pandoc
    walkMWithLuaFilter :: LuaFilter -> Pandoc -> Lua Pandoc
    walkMWithLuaFilter f :: LuaFilter
    f =
          LuaFilter -> Pandoc -> Lua Pandoc
    forall a.
    Walkable (SingletonsList Inline) a =>
    LuaFilter -> a -> Lua a
    walkInlines LuaFilter
    f
      (Pandoc -> Lua Pandoc)
    -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> LuaFilter -> Pandoc -> Lua Pandoc
    forall a. Walkable (List Inline) a => LuaFilter -> a -> Lua a
    walkInlineLists LuaFilter
    f
      (Pandoc -> Lua Pandoc)
    -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> LuaFilter -> Pandoc -> Lua Pandoc
    forall a.
    Walkable (SingletonsList Block) a =>
    LuaFilter -> a -> Lua a
    walkBlocks LuaFilter
    f
      (Pandoc -> Lua Pandoc)
    -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> LuaFilter -> Pandoc -> Lua Pandoc
    forall a. Walkable (List Block) a => LuaFilter -> a -> Lua a
    walkBlockLists LuaFilter
    f
      (Pandoc -> Lua Pandoc)
    -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> LuaFilter -> Pandoc -> Lua Pandoc
    walkMeta LuaFilter
    f
      (Pandoc -> Lua Pandoc)
    -> (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> LuaFilter -> Pandoc -> Lua Pandoc
    walkPandoc LuaFilter
    f

    mconcatMapM :: (Monad m) => (a -> m [a]) -> [a] -> m [a]
    mconcatMapM :: (a -> m [a]) -> [a] -> m [a]
    mconcatMapM f :: a -> m [a]
    f = ([[a]] -> [a]) -> m [[a]] -> m [a]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap [[a]] -> [a]
    forall a. Monoid a => [a] -> a
    mconcat (m [[a]] -> m [a]) -> ([a] -> m [[a]]) -> [a] -> m [a]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (a -> m [a]) -> [a] -> m [[a]]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM a -> m [a]
    f

    hasOneOf :: LuaFilter -> [String] -> Bool
    hasOneOf :: LuaFilter -> [FilePath] -> Bool
    hasOneOf (LuaFilter fnMap :: Map FilePath LuaFilterFunction
    fnMap) = (FilePath -> Bool) -> [FilePath] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (\k :: FilePath
    k -> FilePath -> Map FilePath LuaFilterFunction -> Bool
    forall k a. Ord k => k -> Map k a -> Bool
    Map.member FilePath
    k Map FilePath LuaFilterFunction
    fnMap)

    contains :: LuaFilter -> String -> Bool
    contains :: LuaFilter -> FilePath -> Bool
    contains (LuaFilter fnMap :: Map FilePath LuaFilterFunction
    fnMap) = (FilePath -> Map FilePath LuaFilterFunction -> Bool
    forall k a. Ord k => k -> Map k a -> Bool
    `Map.member` Map FilePath LuaFilterFunction
    fnMap)

    walkInlines :: Walkable (SingletonsList Inline) a => LuaFilter -> a -> Lua a
    walkInlines :: LuaFilter -> a -> Lua a
    walkInlines lf :: LuaFilter
    lf =
      let f :: SingletonsList Inline -> Lua (SingletonsList Inline)
          f :: SingletonsList Inline -> Lua (SingletonsList Inline)
    f = LuaFilter -> SingletonsList Inline -> Lua (SingletonsList Inline)
    forall a.
    (Data a, Peekable a, Pushable a) =>
    LuaFilter -> SingletonsList a -> Lua (SingletonsList a)
    runOnSequence LuaFilter
    lf
      in if LuaFilter
    lf LuaFilter -> [FilePath] -> Bool
    `hasOneOf` [FilePath]
    inlineElementNames
         then (SingletonsList Inline -> Lua (SingletonsList Inline))
    -> a -> Lua a
    forall a b (m :: * -> *).
    (Walkable a b, Monad m, Applicative m, Functor m) =>
    (a -> m a) -> b -> m b
    walkM SingletonsList Inline -> Lua (SingletonsList Inline)
    f
         else a -> Lua a
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    walkInlineLists :: Walkable (List Inline) a => LuaFilter -> a -> Lua a
    walkInlineLists :: LuaFilter -> a -> Lua a
    walkInlineLists lf :: LuaFilter
    lf =
      let f :: List Inline -> Lua (List Inline)
          f :: List Inline -> Lua (List Inline)
    f = FilePath -> LuaFilter -> List Inline -> Lua (List Inline)
    forall a.
    (Data a, Peekable a, Pushable a) =>
    FilePath -> LuaFilter -> a -> Lua a
    runOnValue FilePath
    listOfInlinesFilterName LuaFilter
    lf
      in if LuaFilter
    lf LuaFilter -> FilePath -> Bool
    `contains` FilePath
    listOfInlinesFilterName
         then (List Inline -> Lua (List Inline)) -> a -> Lua a
    forall a b (m :: * -> *).
    (Walkable a b, Monad m, Applicative m, Functor m) =>
    (a -> m a) -> b -> m b
    walkM List Inline -> Lua (List Inline)
    f
         else a -> Lua a
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    walkBlocks :: Walkable (SingletonsList Block) a => LuaFilter -> a -> Lua a
    walkBlocks :: LuaFilter -> a -> Lua a
    walkBlocks lf :: LuaFilter
    lf =
      let f :: SingletonsList Block -> Lua (SingletonsList Block)
          f :: SingletonsList Block -> Lua (SingletonsList Block)
    f = LuaFilter -> SingletonsList Block -> Lua (SingletonsList Block)
    forall a.
    (Data a, Peekable a, Pushable a) =>
    LuaFilter -> SingletonsList a -> Lua (SingletonsList a)
    runOnSequence LuaFilter
    lf
      in if LuaFilter
    lf LuaFilter -> [FilePath] -> Bool
    `hasOneOf` [FilePath]
    blockElementNames
         then (SingletonsList Block -> Lua (SingletonsList Block)) -> a -> Lua a
    forall a b (m :: * -> *).
    (Walkable a b, Monad m, Applicative m, Functor m) =>
    (a -> m a) -> b -> m b
    walkM SingletonsList Block -> Lua (SingletonsList Block)
    f
         else a -> Lua a
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    walkBlockLists :: Walkable (List Block) a => LuaFilter -> a -> Lua a
    walkBlockLists :: LuaFilter -> a -> Lua a
    walkBlockLists lf :: LuaFilter
    lf =
      let f :: List Block -> Lua (List Block)
          f :: List Block -> Lua (List Block)
    f = FilePath -> LuaFilter -> List Block -> Lua (List Block)
    forall a.
    (Data a, Peekable a, Pushable a) =>
    FilePath -> LuaFilter -> a -> Lua a
    runOnValue FilePath
    listOfBlocksFilterName LuaFilter
    lf
      in if LuaFilter
    lf LuaFilter -> FilePath -> Bool
    `contains` FilePath
    listOfBlocksFilterName
         then (List Block -> Lua (List Block)) -> a -> Lua a
    forall a b (m :: * -> *).
    (Walkable a b, Monad m, Applicative m, Functor m) =>
    (a -> m a) -> b -> m b
    walkM List Block -> Lua (List Block)
    f
         else a -> Lua a
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    walkMeta :: LuaFilter -> Pandoc -> Lua Pandoc
    walkMeta :: LuaFilter -> Pandoc -> Lua Pandoc
    walkMeta lf :: LuaFilter
    lf (Pandoc m :: Meta
    m bs :: [Block]
    bs) = do
      Meta
    m' <- FilePath -> LuaFilter -> Meta -> Lua Meta
    forall a.
    (Data a, Peekable a, Pushable a) =>
    FilePath -> LuaFilter -> a -> Lua a
    runOnValue "Meta" LuaFilter
    lf Meta
    m
      Pandoc -> Lua Pandoc
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Pandoc -> Lua Pandoc) -> Pandoc -> Lua Pandoc
    forall a b. (a -> b) -> a -> b
    $ Meta -> [Block] -> Pandoc
    Pandoc Meta
    m' [Block]
    bs

    walkPandoc :: LuaFilter -> Pandoc -> Lua Pandoc
    walkPandoc :: LuaFilter -> Pandoc -> Lua Pandoc
    walkPandoc (LuaFilter fnMap :: Map FilePath LuaFilterFunction
    fnMap) =
      case (Maybe LuaFilterFunction
     -> Maybe LuaFilterFunction -> Maybe LuaFilterFunction)
    -> Maybe LuaFilterFunction
    -> [Maybe LuaFilterFunction]
    -> Maybe LuaFilterFunction
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl Maybe LuaFilterFunction
    -> Maybe LuaFilterFunction -> Maybe LuaFilterFunction
    forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
    mplus Maybe LuaFilterFunction
    forall a. Maybe a
    Nothing ((FilePath -> Maybe LuaFilterFunction)
    -> [FilePath] -> [Maybe LuaFilterFunction]
    forall a b. (a -> b) -> [a] -> [b]
    map (FilePath
    -> Map FilePath LuaFilterFunction -> Maybe LuaFilterFunction
    forall k a. Ord k => k -> Map k a -> Maybe a
    `Map.lookup` Map FilePath LuaFilterFunction
    fnMap) [FilePath]
    pandocFilterNames) of
        Just fn :: LuaFilterFunction
    fn -> \x :: Pandoc
    x -> LuaFilterFunction -> Pandoc -> Lua ()
    forall a. Pushable a => LuaFilterFunction -> a -> Lua ()
    runFilterFunction LuaFilterFunction
    fn Pandoc
    x Lua () -> Lua Pandoc -> Lua Pandoc
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> Pandoc -> Lua Pandoc
    forall a. Peekable a => a -> Lua a
    singleElement Pandoc
    x
        Nothing -> Pandoc -> Lua Pandoc
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    constructorsFor :: DataType -> [String]
    constructorsFor :: DataType -> [FilePath]
    constructorsFor x :: DataType
    x = (Constr -> FilePath) -> [Constr] -> [FilePath]
    forall a b. (a -> b) -> [a] -> [b]
    map Constr -> FilePath
    forall a. Show a => a -> FilePath
    show (DataType -> [Constr]
    dataTypeConstrs DataType
    x)

    inlineElementNames :: [String]
    inlineElementNames :: [FilePath]
    inlineElementNames = "Inline" FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : DataType -> [FilePath]
    constructorsFor (Inline -> DataType
    forall a. Data a => a -> DataType
    dataTypeOf (Text -> Inline
    Str Text
    forall a. Monoid a => a
    mempty))

    blockElementNames :: [String]
    blockElementNames :: [FilePath]
    blockElementNames = "Block" FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : DataType -> [FilePath]
    constructorsFor (Block -> DataType
    forall a. Data a => a -> DataType
    dataTypeOf ([Inline] -> Block
    Para []))

    listOfInlinesFilterName :: String
    listOfInlinesFilterName :: FilePath
    listOfInlinesFilterName = "Inlines"

    listOfBlocksFilterName :: String
    listOfBlocksFilterName :: FilePath
    listOfBlocksFilterName = "Blocks"

    metaFilterName :: String
    metaFilterName :: FilePath
    metaFilterName = "Meta"

    pandocFilterNames :: [String]
    pandocFilterNames :: [FilePath]
    pandocFilterNames = ["Pandoc", "Doc"]

    singleElement :: Peekable a => a -> Lua a
    singleElement :: a -> Lua a
    singleElement x :: a
    x = do
      Bool
    elementUnchanged <- StackIndex -> Lua Bool
    Lua.isnil (-1)
      if Bool
    elementUnchanged
        then a
    x a -> Lua () -> Lua a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ StackIndex -> Lua ()
    Lua.pop 1
        else do
        Either FilePath a
    mbres <- StackIndex -> Lua (Either FilePath a)
    forall a. Peekable a => StackIndex -> Lua (Either FilePath a)
    Lua.peekEither (-1)
        case Either FilePath a
    mbres of
          Right res :: a
    res -> a
    res a -> Lua () -> Lua a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ StackIndex -> Lua ()
    Lua.pop 1
          Left err :: FilePath
    err  -> do
            StackIndex -> Lua ()
    Lua.pop 1
            FilePath -> Lua a
    forall a. FilePath -> Lua a
    Lua.throwException (FilePath -> Lua a) -> FilePath -> Lua a
    forall a b. (a -> b) -> a -> b
    $
              "Error while trying to get a filter's return " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++
              "value from lua stack.\n" FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    err