{-# language OverloadedStrings #-} module Tempered.Parser ( templateFromFile , parseTemplate , handleTemplateError ) where import Tempered.Template import System.Exit import Control.Applicative (liftA2) import Text.Parsec import Text.Parsec.String infix 0 ?> (?>) :: String -> ParsecT s u m a -> ParsecT s u m a (?>) = flip () -- | Parse a template from a file. templateFromFile :: FilePath -> IO (Either ParseError (Template Command)) templateFromFile fname = do file <- readFile fname return $ parseTemplate fname file -- | Parse a template from a string with a given filename for errors. parseTemplate :: FilePath -> String -> Either ParseError (Template Command) parseTemplate = runP templateP () -- | Fail if parsing errors occurred, otherwise return the template. handleTemplateError :: Either ParseError (Template a) -> IO (Template a) handleTemplateError (Left err) = print err >> exitFailure handleTemplateError (Right temp) = return temp -- | Template Parser templateP :: Parser (Template Command) templateP = "template" ?> do optional (try shebangP) contents <- many (cmd <|> txt) eof return $ Template contents where cmd = Right <$> commandP txt = Left <$> many1 (notFollowedBy (string "{{") *> anyChar) -- | Shebang Parser shebangP :: Parser String shebangP = "shebang" ?> liftA2 (++) (lookAhead (string "#!") *> string "#!") (manyTill anyChar (char '\n')) -- | Command Parser commandP :: Parser Command commandP = "command" ?> do _ <- string "{{" cmdString <- manyTill anyChar (string "}}") optional newline return $ Command cmdString