{-# LANGUAGE TemplateHaskell #-}

-- | Contains the main quasiquoters that convert Flamethrower templates into expressions.
module Text.Flamethrower (flamethrower, flamef) where

import Data.Maybe (fromMaybe)
import Language.Haskell.TH
import Language.Haskell.TH.Quote

import qualified Text.Flamethrower.Lexer as L
import qualified Text.Flamethrower.Parser as P
import qualified Text.Flamethrower.Compiler as C
import Text.Flamethrower.Escape

import qualified Data.Text

codeTreeToExpression :: C.CodeTree -> Exp
codeTreeToExpression tree = case tree of
	C.Text s -> ListE [LitE $ StringL s]
	C.Expression escaper exp -> ListE . replicate 1 $
		case escaper of
			None -> exp
			Content -> VarE 'escapeContent `AppE` exp
			Attribute -> VarE 'escapeAttributeValue `AppE` exp
	C.If condition truePart falsePart ->
		let cond = CondE condition (ListE $ map codeTreeToExpression truePart) (ListE $ map codeTreeToExpression falsePart)
		in VarE 'concat `AppE` cond
	C.For bind loop children -> VarE 'concat `AppE` CompE [BindS (VarP bind) loop, NoBindS $ VarE 'concat `AppE` ListE (map codeTreeToExpression children)]

compileTemplate :: String -> [Exp]
compileTemplate = map codeTreeToExpression . C.compile . P.parse . L.lex

-- | Converts strings representing Flamethrower templates into expressions.
flamethrower' :: String -> Q Exp
flamethrower' template = return $ VarE 'Data.Text.concat `AppE` (VarE 'concat `AppE` ListE (compileTemplate template))

-- | A quasiquoter to convert Flamethrower templates into expressions.
--
-- > exampleTemplate :: Text -> Text
-- > exampleTemplate title = [flamethrower|
-- > doctype
-- >
-- > html
-- >     head
-- >         meta charset: "utf-8"
-- >
-- >         title "#{title}"
-- >
-- >     body
-- >         h1 "A page"
-- >
-- >         p "Hello, world!"
-- > |]
flamethrower :: QuasiQuoter
flamethrower = QuasiQuoter {
	quoteExp = flamethrower',
	quotePat = error "Flamethrower templates are expressions, not patterns.",
	quoteDec = error "Flamethrower templates are expressions, not declarations.",
	quoteType = error "Flamethrower templates are expressions, not types."
}

-- | A quasiquoter that reads Flamethrower template files.
--
-- > exampleTemplate :: Text -> Text
-- > exampleTemplate title = [flamef|example-template.flame|]
flamef :: QuasiQuoter
flamef = quoteFile flamethrower