-- |
-- 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 (isSpace, isAlphaNum)
import Data.List (intercalate)
import Data.Functor.Identity
import Data.Maybe (catMaybes)
import Data.Text.Lazy (Text)
import Text.Parsec hiding ((<|>))
import Text.Parsec.Char ()
import Data.Word (Word)
import Text.Microstache.Type
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 = Parsec Text Delimiters [Node]
-> Delimiters -> FilePath -> Text -> Either ParseError [Node]
forall s t u a.
Stream s Identity t =>
Parsec s u a -> u -> FilePath -> s -> Either ParseError a
runParser (Parser () -> Parsec Text Delimiters [Node]
pMustache Parser ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof) (FilePath -> FilePath -> Delimiters
Delimiters "{{" "}}")

pMustache :: Parser () -> Parser [Node]
pMustache :: Parser () -> Parsec Text Delimiters [Node]
pMustache = ([Maybe Node] -> [Node])
-> ParsecT Text Delimiters Identity [Maybe Node]
-> Parsec Text Delimiters [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]
 -> Parsec Text Delimiters [Node])
-> (Parser () -> ParsecT Text Delimiters Identity [Maybe Node])
-> Parser ()
-> Parsec Text Delimiters [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 "#" 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 "^" 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 "&"
{-# 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 -> 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
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 suffix :: FilePath
suffix f :: 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 () -> Parsec Text Delimiters [Node]
pMustache (Parser () -> Parsec Text Delimiters [Node])
-> (Key -> Parser ()) -> Key -> Parsec Text Delimiters [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 f :: 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 ">"
  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 ".") (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]
++ "!")
  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
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
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 ""
{-# INLINE pEscapedVariable #-}

withStandalone :: Parser a -> Parser a
withStandalone :: Parser a -> Parser a
withStandalone p :: 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 p :: 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 suffix :: 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
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 -> 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 "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 '.'
    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 '.')
    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 "-_"
{-# 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
<?> "delimiter"
  where delChar :: Char -> Bool
delChar x :: 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
/= '='
{-# 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
== 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 " \t"))
{-# INLINE sc #-}

lexeme :: Parser a -> Parser a
lexeme :: Parser a -> Parser a
lexeme p :: 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 '\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 '\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 '\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 []) = "."
keyToString (Key ks :: [Text]
ks) = FilePath -> [FilePath] -> FilePath
forall a. [a] -> [[a]] -> [a]
intercalate "." (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 p :: ParsecT s u m a
p end :: 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 f :: 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