-- |
-- Module      :  Text.Microstache.Parser
-- Copyright   :  © 2016–2017 Stack Builders
-- License     :  BSD 3 clause
--
-- Maintainer  :  Mark Karpov <markkarpov@openmailbox.org>
-- Stability   :  experimental
-- Portability :  portable
--
-- Megaparsec parser for Mustache templates. You don't usually need to
-- import the module, because "Text.Microstache" re-exports everything you may
-- need, import that module instead.

module Text.Microstache.Parser
  ( parseMustache )
where

import Control.Applicative   hiding (many)
import Control.Monad
import Data.Char             (isAlphaNum, isSpace)
import Data.Functor.Identity
import Data.List             (intercalate)
import Data.Maybe            (catMaybes)
import Data.Text.Lazy        (Text)
import Data.Word             (Word)
import Text.Microstache.Type
import Text.Parsec           hiding ((<|>))
import Text.Parsec.Char ()

import qualified Data.Text as T

----------------------------------------------------------------------------
-- Parser

-- | Parse given Mustache template.

parseMustache
  :: FilePath
     -- ^ Location of file to parse
  -> Text
     -- ^ File contents (Mustache template)
  -> Either ParseError [Node]
     -- ^ Parsed nodes or parse error
parseMustache :: FilePath -> Text -> Either ParseError [Node]
parseMustache FilePath
name Text
contents = Identity (Either ParseError [Node]) -> Either ParseError [Node]
forall a. Identity a -> a
runIdentity (ParsecT Text Delimiters Identity [Node]
-> Delimiters
-> FilePath
-> Text
-> Identity (Either ParseError [Node])
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> u -> FilePath -> s -> m (Either ParseError a)
runParserT (Parser () -> ParsecT Text Delimiters Identity [Node]
pMustache Parser ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof) (FilePath -> FilePath -> Delimiters
Delimiters FilePath
"{{" FilePath
"}}") FilePath
name Text
contents)

pMustache :: Parser () -> Parser [Node]
pMustache :: Parser () -> ParsecT Text Delimiters Identity [Node]
pMustache = ([Maybe Node] -> [Node])
-> ParsecT Text Delimiters Identity [Maybe Node]
-> ParsecT Text Delimiters Identity [Node]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Maybe Node] -> [Node]
forall a. [Maybe a] -> [a]
catMaybes (ParsecT Text Delimiters Identity [Maybe Node]
 -> ParsecT Text Delimiters Identity [Node])
-> (Parser () -> ParsecT Text Delimiters Identity [Maybe Node])
-> Parser ()
-> ParsecT Text Delimiters Identity [Node]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT Text Delimiters Identity (Maybe Node)
-> Parser () -> ParsecT Text Delimiters Identity [Maybe Node]
forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
manyTill ([ParsecT Text Delimiters Identity (Maybe Node)]
-> ParsecT Text Delimiters Identity (Maybe Node)
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [ParsecT Text Delimiters Identity (Maybe Node)]
alts)
  where
    alts :: [ParsecT Text Delimiters Identity (Maybe Node)]
alts =
      [ Maybe Node
forall a. Maybe a
Nothing Maybe Node
-> Parser () -> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$  Parser () -> Parser ()
forall a. Parser a -> Parser a
withStandalone Parser ()
pComment
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath
-> (Key -> [Node] -> Node) -> ParsecT Text Delimiters Identity Node
pSection FilePath
"#" Key -> [Node] -> Node
Section
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath
-> (Key -> [Node] -> Node) -> ParsecT Text Delimiters Identity Node
pSection FilePath
"^" Key -> [Node] -> Node
InvertedSection
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity Node
forall a. Parser a -> Parser a
pStandalone ((Word -> Maybe Word) -> ParsecT Text Delimiters Identity Node
pPartial Word -> Maybe Word
forall a. a -> Maybe a
Just)
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Word -> Maybe Word) -> ParsecT Text Delimiters Identity Node
pPartial (Maybe Word -> Word -> Maybe Word
forall a b. a -> b -> a
const Maybe Word
forall a. Maybe a
Nothing)
      , Maybe Node
forall a. Maybe a
Nothing Maybe Node
-> Parser () -> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$  Parser () -> Parser ()
forall a. Parser a -> Parser a
withStandalone Parser ()
pSetDelimiters
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Node
pUnescapedVariable
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Node
pUnescapedSpecial
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Node
pEscapedVariable
      , Node -> Maybe Node
forall a. a -> Maybe a
Just    (Node -> Maybe Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity (Maybe Node)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Node
pTextBlock ]
{-# INLINE pMustache #-}

pTextBlock :: Parser Node
pTextBlock :: ParsecT Text Delimiters Identity Node
pTextBlock = do
  FilePath
start <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
openingDel
  (Parser () -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Parser () -> Parser ())
-> (FilePath -> Parser ()) -> FilePath -> Parser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT Text Delimiters Identity FilePath -> Parser ()
forall s (m :: * -> *) t a u.
(Stream s m t, Show a) =>
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy (ParsecT Text Delimiters Identity FilePath -> Parser ())
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> Parser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParsecT Text Delimiters Identity FilePath
string') FilePath
start
  let terminator :: Parser ()
terminator = [Parser ()] -> Parser ()
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice
        [ (ParsecT Text Delimiters Identity FilePath -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text Delimiters Identity FilePath -> Parser ())
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> Parser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT Text Delimiters Identity FilePath
 -> ParsecT Text Delimiters Identity FilePath)
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> ParsecT Text Delimiters Identity FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParsecT Text Delimiters Identity FilePath
string') FilePath
start
        , Parser ()
pBol
        , Parser ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof ]
  Text -> Node
TextBlock (Text -> Node) -> (FilePath -> Text) -> FilePath -> Node
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
T.pack (FilePath -> Node)
-> ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity Node
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Char
-> Parser () -> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
someTill ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar Parser ()
terminator
{-# INLINE pTextBlock #-}

pUnescapedVariable :: Parser Node
pUnescapedVariable :: ParsecT Text Delimiters Identity Node
pUnescapedVariable = Key -> Node
UnescapedVar (Key -> Node)
-> ParsecT Text Delimiters Identity Key
-> ParsecT Text Delimiters Identity Node
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> ParsecT Text Delimiters Identity Key
pTag FilePath
"&"
{-# INLINE pUnescapedVariable #-}

pUnescapedSpecial :: Parser Node
pUnescapedSpecial :: ParsecT Text Delimiters Identity Node
pUnescapedSpecial = do
  FilePath
start <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
openingDel
  FilePath
end   <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
closingDel
  ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity Node
forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
between (FilePath -> ParsecT Text Delimiters Identity FilePath
symbol (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath -> ParsecT Text Delimiters Identity FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
start FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"{") (FilePath -> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m FilePath
string (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath -> ParsecT Text Delimiters Identity FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
"}" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
end) (ParsecT Text Delimiters Identity Node
 -> ParsecT Text Delimiters Identity Node)
-> ParsecT Text Delimiters Identity Node
-> ParsecT Text Delimiters Identity Node
forall a b. (a -> b) -> a -> b
$
    Key -> Node
UnescapedVar (Key -> Node)
-> ParsecT Text Delimiters Identity Key
-> ParsecT Text Delimiters Identity Node
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Key
pKey
{-# INLINE pUnescapedSpecial #-}

pSection :: String -> (Key -> [Node] -> Node) -> Parser Node
pSection :: FilePath
-> (Key -> [Node] -> Node) -> ParsecT Text Delimiters Identity Node
pSection FilePath
suffix Key -> [Node] -> Node
f = do
  Key
key   <- ParsecT Text Delimiters Identity Key
-> ParsecT Text Delimiters Identity Key
forall a. Parser a -> Parser a
withStandalone (FilePath -> ParsecT Text Delimiters Identity Key
pTag FilePath
suffix)
  [Node]
nodes <- (Parser () -> ParsecT Text Delimiters Identity [Node]
pMustache (Parser () -> ParsecT Text Delimiters Identity [Node])
-> (Key -> Parser ())
-> Key
-> ParsecT Text Delimiters Identity [Node]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser () -> Parser ()
forall a. Parser a -> Parser a
withStandalone (Parser () -> Parser ()) -> (Key -> Parser ()) -> Key -> Parser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key -> Parser ()
pClosingTag) Key
key
  Node -> ParsecT Text Delimiters Identity Node
forall (m :: * -> *) a. Monad m => a -> m a
return (Key -> [Node] -> Node
f Key
key [Node]
nodes)
{-# INLINE pSection #-}

pPartial :: (Word -> Maybe Word) -> Parser Node
pPartial :: (Word -> Maybe Word) -> ParsecT Text Delimiters Identity Node
pPartial Word -> Maybe Word
f = do
  Maybe Word
pos <- Word -> Maybe Word
f (Word -> Maybe Word)
-> ParsecT Text Delimiters Identity Word
-> ParsecT Text Delimiters Identity (Maybe Word)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Word
indentLevel
  Key
key <- FilePath -> ParsecT Text Delimiters Identity Key
pTag FilePath
">"
  let pname :: PName
pname = Text -> PName
PName (Text -> PName) -> Text -> PName
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
T.intercalate (FilePath -> Text
T.pack FilePath
".") (Key -> [Text]
unKey Key
key)
  Node -> ParsecT Text Delimiters Identity Node
forall (m :: * -> *) a. Monad m => a -> m a
return (PName -> Maybe Word -> Node
Partial PName
pname Maybe Word
pos)
{-# INLINE pPartial #-}

pComment :: Parser ()
pComment :: Parser ()
pComment = ParsecT Text Delimiters Identity FilePath -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text Delimiters Identity FilePath -> Parser ())
-> ParsecT Text Delimiters Identity FilePath -> Parser ()
forall a b. (a -> b) -> a -> b
$ do
  FilePath
start <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
openingDel
  FilePath
end   <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
closingDel
  (ParsecT Text Delimiters Identity FilePath -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text Delimiters Identity FilePath -> Parser ())
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> Parser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParsecT Text Delimiters Identity FilePath
symbol) (FilePath
start FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"!")
  ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
manyTill ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar (FilePath -> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m FilePath
string FilePath
end)
{-# INLINE pComment #-}

pSetDelimiters :: Parser ()
pSetDelimiters :: Parser ()
pSetDelimiters = Parser () -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Parser () -> Parser ()) -> Parser () -> Parser ()
forall a b. (a -> b) -> a -> b
$ do
  FilePath
start <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
openingDel
  FilePath
end   <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
closingDel
  (ParsecT Text Delimiters Identity FilePath -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text Delimiters Identity FilePath -> Parser ())
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> Parser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParsecT Text Delimiters Identity FilePath
symbol) (FilePath
start FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"=")
  FilePath
start' <- ParsecT Text Delimiters Identity FilePath
pDelimiter ParsecT Text Delimiters Identity FilePath
-> Parser () -> ParsecT Text Delimiters Identity FilePath
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ()
scn
  FilePath
end'   <- ParsecT Text Delimiters Identity FilePath
pDelimiter ParsecT Text Delimiters Identity FilePath
-> Parser () -> ParsecT Text Delimiters Identity FilePath
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ()
scn
  (ParsecT Text Delimiters Identity FilePath -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text Delimiters Identity FilePath -> Parser ())
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> Parser ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m FilePath
string) (FilePath
"=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
end)
  Delimiters -> Parser ()
forall (m :: * -> *) u s. Monad m => u -> ParsecT s u m ()
putState (FilePath -> FilePath -> Delimiters
Delimiters FilePath
start' FilePath
end')
{-# INLINE pSetDelimiters #-}

pEscapedVariable :: Parser Node
pEscapedVariable :: ParsecT Text Delimiters Identity Node
pEscapedVariable = Key -> Node
EscapedVar (Key -> Node)
-> ParsecT Text Delimiters Identity Key
-> ParsecT Text Delimiters Identity Node
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> ParsecT Text Delimiters Identity Key
pTag FilePath
""
{-# INLINE pEscapedVariable #-}

withStandalone :: Parser a -> Parser a
withStandalone :: Parser a -> Parser a
withStandalone Parser a
p = Parser a -> Parser a
forall a. Parser a -> Parser a
pStandalone Parser a
p Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser a
p
{-# INLINE withStandalone #-}

pStandalone :: Parser a -> Parser a
pStandalone :: Parser a -> Parser a
pStandalone Parser a
p = Parser ()
pBol Parser () -> Parser a -> Parser a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser a -> Parser a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (Parser () -> Parser () -> Parser a -> Parser a
forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
between Parser ()
sc (Parser ()
sc Parser () -> Parser () -> Parser ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* (Parser () -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void Parser ()
eol Parser () -> Parser () -> Parser ()
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof)) Parser a
p)
{-# INLINE pStandalone #-}

pTag :: String -> Parser Key
pTag :: FilePath -> ParsecT Text Delimiters Identity Key
pTag FilePath
suffix = do
  FilePath
start <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
openingDel
  FilePath
end   <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
closingDel
  ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity Key
-> ParsecT Text Delimiters Identity Key
forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
between (FilePath -> ParsecT Text Delimiters Identity FilePath
symbol (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath -> ParsecT Text Delimiters Identity FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
start FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
suffix) (FilePath -> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m FilePath
string FilePath
end) ParsecT Text Delimiters Identity Key
pKey
{-# INLINE pTag #-}

pClosingTag :: Key -> Parser ()
pClosingTag :: Key -> Parser ()
pClosingTag Key
key = do
  FilePath
start <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
openingDel
  FilePath
end   <- (Delimiters -> FilePath)
-> ParsecT Text Delimiters Identity FilePath
forall (m :: * -> *) u a s. Monad m => (u -> a) -> ParsecT s u m a
gets Delimiters -> FilePath
closingDel
  let str :: FilePath
str = Key -> FilePath
keyToString Key
key
  ParsecT Text Delimiters Identity FilePath -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text Delimiters Identity FilePath -> Parser ())
-> ParsecT Text Delimiters Identity FilePath -> Parser ()
forall a b. (a -> b) -> a -> b
$ ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
between (FilePath -> ParsecT Text Delimiters Identity FilePath
symbol (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath -> ParsecT Text Delimiters Identity FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
start FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"/") (FilePath -> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m FilePath
string FilePath
end) (FilePath -> ParsecT Text Delimiters Identity FilePath
symbol FilePath
str)
{-# INLINE pClosingTag #-}

pKey :: Parser Key
pKey :: ParsecT Text Delimiters Identity Key
pKey = (([Text] -> Key)
-> ParsecT Text Delimiters Identity [Text]
-> ParsecT Text Delimiters Identity Key
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Text] -> Key
Key (ParsecT Text Delimiters Identity [Text]
 -> ParsecT Text Delimiters Identity Key)
-> (ParsecT Text Delimiters Identity [Text]
    -> ParsecT Text Delimiters Identity [Text])
-> ParsecT Text Delimiters Identity [Text]
-> ParsecT Text Delimiters Identity Key
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT Text Delimiters Identity [Text]
-> ParsecT Text Delimiters Identity [Text]
forall a. Parser a -> Parser a
lexeme (ParsecT Text Delimiters Identity [Text]
 -> ParsecT Text Delimiters Identity [Text])
-> (ParsecT Text Delimiters Identity [Text]
    -> ParsecT Text Delimiters Identity [Text])
-> ParsecT Text Delimiters Identity [Text]
-> ParsecT Text Delimiters Identity [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ParsecT Text Delimiters Identity [Text]
 -> FilePath -> ParsecT Text Delimiters Identity [Text])
-> FilePath
-> ParsecT Text Delimiters Identity [Text]
-> ParsecT Text Delimiters Identity [Text]
forall a b c. (a -> b -> c) -> b -> a -> c
flip ParsecT Text Delimiters Identity [Text]
-> FilePath -> ParsecT Text Delimiters Identity [Text]
forall s u (m :: * -> *) a.
ParsecT s u m a -> FilePath -> ParsecT s u m a
label FilePath
"key") (ParsecT Text Delimiters Identity [Text]
forall u a. ParsecT Text u Identity [a]
implicit ParsecT Text Delimiters Identity [Text]
-> ParsecT Text Delimiters Identity [Text]
-> ParsecT Text Delimiters Identity [Text]
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Text Delimiters Identity [Text]
other)
  where
    implicit :: ParsecT Text u Identity [a]
implicit = [] [a] -> ParsecT Text u Identity Char -> ParsecT Text u Identity [a]
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Char -> ParsecT Text u Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'.'
    other :: ParsecT Text Delimiters Identity [Text]
other    = ParsecT Text Delimiters Identity Text
-> ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity [Text]
forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
sepBy1 (FilePath -> Text
T.pack (FilePath -> Text)
-> ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity FilePath
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some ParsecT Text Delimiters Identity Char
ch) (Char -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'.')
    ch :: ParsecT Text Delimiters Identity Char
ch       = ParsecT Text Delimiters Identity Char
alphaNumChar ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity Char
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> FilePath -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m Char
oneOf FilePath
"-_"
{-# INLINE pKey #-}

pDelimiter :: Parser String
pDelimiter :: ParsecT Text Delimiters Identity FilePath
pDelimiter = ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity FilePath
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some ((Char -> Bool) -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy Char -> Bool
delChar) ParsecT Text Delimiters Identity FilePath
-> FilePath -> ParsecT Text Delimiters Identity FilePath
forall s u (m :: * -> *) a.
ParsecT s u m a -> FilePath -> ParsecT s u m a
<?> FilePath
"delimiter"
  where delChar :: Char -> Bool
delChar Char
x = Bool -> Bool
not (Char -> Bool
isSpace Char
x) Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'='
{-# INLINE pDelimiter #-}

indentLevel :: Parser Word
indentLevel :: ParsecT Text Delimiters Identity Word
indentLevel = (SourcePos -> Word)
-> ParsecT Text Delimiters Identity SourcePos
-> ParsecT Text Delimiters Identity Word
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Column -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Column -> Word) -> (SourcePos -> Column) -> SourcePos -> Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SourcePos -> Column
sourceColumn) ParsecT Text Delimiters Identity SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition

pBol :: Parser ()
pBol :: Parser ()
pBol = do
  Word
level <- ParsecT Text Delimiters Identity Word
indentLevel
  Bool -> Parser () -> Parser ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Word
level Word -> Word -> Bool
forall a. Eq a => a -> a -> Bool
== Word
1) Parser ()
forall (f :: * -> *) a. Alternative f => f a
empty
{-# INLINE pBol #-}

----------------------------------------------------------------------------
-- Auxiliary types

-- | Type of Mustache parser monad stack.

type Parser = ParsecT Text Delimiters Identity

-- | State used in Mustache parser. It includes currently set opening and
-- closing delimiters.

data Delimiters = Delimiters
  { Delimiters -> FilePath
openingDel :: String
  , Delimiters -> FilePath
closingDel :: String }

----------------------------------------------------------------------------
-- Lexer helpers and other

-- TODO: OLEG inline
scn :: Parser ()
scn :: Parser ()
scn = Parser ()
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m ()
spaces
{-# INLINE scn #-}

sc :: Parser ()
sc :: Parser ()
sc = ParsecT Text Delimiters Identity FilePath -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity FilePath
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (FilePath -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m Char
oneOf FilePath
" \t"))
{-# INLINE sc #-}

lexeme :: Parser a -> Parser a
lexeme :: Parser a -> Parser a
lexeme Parser a
p = Parser a
p Parser a -> Parser () -> Parser a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ()
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m ()
spaces
{-# INLINE lexeme #-}

eol :: Parser ()
eol :: Parser ()
eol = ParsecT Text Delimiters Identity Char -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Char -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\n') Parser () -> Parser () -> Parser ()
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Text Delimiters Identity Char -> Parser ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Char -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\r' ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity Char
-> ParsecT Text Delimiters Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\n')

string' :: String -> Parser String
string' :: FilePath -> ParsecT Text Delimiters Identity FilePath
string' = ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT Text Delimiters Identity FilePath
 -> ParsecT Text Delimiters Identity FilePath)
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> ParsecT Text Delimiters Identity FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParsecT Text Delimiters Identity FilePath
forall s (m :: * -> *) u.
Stream s m Char =>
FilePath -> ParsecT s u m FilePath
string

symbol :: String -> Parser String
symbol :: FilePath -> ParsecT Text Delimiters Identity FilePath
symbol = ParsecT Text Delimiters Identity FilePath
-> ParsecT Text Delimiters Identity FilePath
forall a. Parser a -> Parser a
lexeme (ParsecT Text Delimiters Identity FilePath
 -> ParsecT Text Delimiters Identity FilePath)
-> (FilePath -> ParsecT Text Delimiters Identity FilePath)
-> FilePath
-> ParsecT Text Delimiters Identity FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParsecT Text Delimiters Identity FilePath
string'
{-# INLINE symbol #-}

keyToString :: Key -> String
keyToString :: Key -> FilePath
keyToString (Key []) = FilePath
"."
keyToString (Key [Text]
ks) = FilePath -> [FilePath] -> FilePath
forall a. [a] -> [[a]] -> [a]
intercalate FilePath
"." (Text -> FilePath
T.unpack (Text -> FilePath) -> [Text] -> [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text]
ks)
{-# INLINE keyToString #-}

someTill :: Stream s m t => ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
someTill :: ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
someTill ParsecT s u m a
p ParsecT s u m end
end = (:) (a -> [a] -> [a]) -> ParsecT s u m a -> ParsecT s u m ([a] -> [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s u m a
p ParsecT s u m ([a] -> [a])
-> ParsecT s u m [a] -> ParsecT s u m [a]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
manyTill ParsecT s u m a
p ParsecT s u m end
end

gets :: Monad m => (u -> a) -> ParsecT s u m a
gets :: (u -> a) -> ParsecT s u m a
gets u -> a
f = (u -> a) -> ParsecT s u m u -> ParsecT s u m a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap u -> a
f ParsecT s u m u
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState

alphaNumChar :: Parser Char
alphaNumChar :: ParsecT Text Delimiters Identity Char
alphaNumChar = (Char -> Bool) -> ParsecT Text Delimiters Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy Char -> Bool
isAlphaNum