module Text.Bravo.Parser (
template,
templates
)
where
import Control.Monad
import Language.Haskell.Exts.Parser hiding (parse)
import Language.Haskell.Exts.Syntax
import Language.Haskell.Exts.Extension
import Text.Bravo.Syntax
import Text.Bravo.Util
import Text.ParserCombinators.Parsec
keywords :: [String]
keywords = ["if", "elseif", "else", "endif", "tpl", "endtpl"]
parseExts :: [Extension]
parseExts = [TemplateHaskell]
template :: Parser Template
template = tpl
templates :: Parser [Template]
templates = option "" ttext' >> many (tpl << option "" ttext')
tpl :: Parser Template
tpl = liftM2 Template tbegin (many (try tpls) << tend) <?> "tpl"
tpls :: Parser TemplateSplice
tpls = try texpr <|> try tcond <|> try tcomm <|> ttext <?> "tpls"
tcond :: Parser TemplateSplice
tcond = do
i <- tif
ts <- many $ try tpls
eis <- many $ liftM2 (,) (try telsif) (many $ try tpls)
e <- option [] (try telse >> many (try tpls))
tendif
return $ TConditions (((i, ts):eis) ++ [(Con $ UnQual $ Ident "True", e)])
<?> "tcond"
tbegin :: Parser String
tbegin = (string "{{" >> many spc >> string "tpl" >> many1 spc >>
ident << many spc << string "}}") <?> "tbegin"
tend :: Parser ()
tend = (skip $ string "{{" >> many spc >> string "endtpl" >> many spc >> string "}}") <?> "tend"
tif :: Parser Exp
tif = (string "{{" >> many spc >> string "if" >> many1 spc >>
cexpr << many spc << string "}}") <?> "tif"
telsif :: Parser Exp
telsif = (string "{{" >> many spc >> string "elseif" >> many1 spc >>
cexpr << many spc << string "}}") <?> "telseif"
telse :: Parser ()
telse = skip (string "{{" >> many spc >> string "else" >> many spc >> string "}}") <?> "telse"
tendif :: Parser ()
tendif = skip (string "{{" >> many spc >> string "endif" >> many spc >> string "}}") <?> "tendif"
texpr :: Parser TemplateSplice
texpr = liftM TExpr (string "{{:" >> many spc >> expr << many spc << string "}}") <?> "texpr"
tcomm :: Parser TemplateSplice
tcomm = (liftM TComment $ string "{{-" >> manyTill anyChar (try $ string "-}}")) <?> "tcomm"
ttext :: Parser TemplateSplice
ttext = liftM TText ttext' <?> "ttext"
ttext' :: Parser String
ttext' = manyNotMultiple '{'
expr :: Parser Exp
expr = do
s <- manyNotMultiple '}'
case parseExpWithMode defaultParseMode { extensions = parseExts } s of
ParseFailed _ err -> fail $ "expr: " ++ err
ParseOk e -> return e
cexpr :: Parser Exp
cexpr = expr
ident :: Parser String
ident = do
s <- liftM2 (:) lower (many alphaNum)
if elem s keywords then unexpected "keyword" else return s
<?> "ident"
spc :: Parser Char
spc = oneOf " \t\n\r" <?> "spc"
notChar :: Char -> Parser Char
notChar = satisfy . (/=)
manyNotMultiple :: Char -> Parser String
manyNotMultiple c = liftM2 (++) (many1 $ notChar c)
(option [] $ try $ liftM2 (:) (char c) (manyNotMultiple c))