mole-0.0.3: src/Data/Mole/Builder/Internal/Template.hs
{-# LANGUAGE OverloadedStrings #-}
module Data.Mole.Builder.Internal.Template where
import Control.Applicative
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Attoparsec.Text as AP
import Data.Monoid
import Data.Mole.Types
type Context = Text -> Either Error Text
data Fragment = Lit Text | Var Text deriving (Show, Eq)
newtype Template = Template [Fragment] deriving (Show, Eq)
template :: String -> Template
template input = case AP.parseOnly (AP.many1 fragmentParser) (T.pack input) of
Left x -> error $ x ++ " on input '" ++ input ++ "'"
Right x -> Template $ mergeLiterals $ concat x
mergeLiterals :: [Fragment] -> [Fragment]
mergeLiterals = reverse . foldl f []
where
f [] frag = [frag]
f ((Lit a):xs) (Lit b) = (Lit $ a <> b) : xs
f acc frag = frag:acc
fragmentParser :: AP.Parser [Fragment]
fragmentParser = var <|> lit
where
var = do
text <- AP.string "<*" *> AP.manyTill AP.anyChar (AP.string "*>")
return $ [Var $ T.strip $ T.pack text]
lit = do
text <- AP.takeTill ('<'==)
( (var <|> (AP.anyChar >>= \c -> return $ [Lit $ T.singleton c]))
>>= \v -> return $ [Lit text] ++ v)
<|> (if T.null text then fail "literal" else return [Lit text])
render :: Template -> Context -> Either Error String
render (Template frags) ctxFunc = do
res <- traverse renderFrag frags
return $ T.unpack $ mconcat res
where
renderFrag (Lit s) = pure s
renderFrag (Var x) = ctxFunc x