{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
module Language.Ginger
(
ginger
, GingerT
, Eval (..)
, RuntimeError (..)
, Context (..)
, defContext
, Env (..)
, emptyEnv
, defEnv
, defVars
, defVarsCompat
, Statement (..)
, Expr (..)
, Template (..)
, Block (..)
, Value (..)
, Scalar (..)
, Encoded (..)
, prettyRuntimeError
, Identifier (..)
, Encoder
, htmlEncoder
, JinjaDialect (..)
, POptions (..)
, defPOptions
, BlockTrimming (..)
, BlockStripping (..)
, TemplateLoader
, fileLoader
)
where
import Language.Ginger.AST
import Language.Ginger.BuiltinsAutodoc
import Language.Ginger.FileLoader
( fileLoader
)
import Language.Ginger.Interpret
import Language.Ginger.Interpret.DefEnv
( htmlEncoder
, defVars
, defVarsCompat
)
import Language.Ginger.Parse
( POptions (..)
, defPOptions
, BlockTrimming (..)
, BlockStripping (..)
)
import qualified Language.Ginger.Parse as P
import Language.Ginger.RuntimeError (prettyRuntimeError)
import Language.Ginger.Value
import Control.Monad.Except (runExceptT, throwError)
import Control.Monad.Random (evalRandT, RandT)
import Control.Monad.Trans (MonadTrans (..))
import Data.Map.Strict (Map)
import Data.Text (Text)
import qualified Data.Text as Text
import System.Random (SplitGen)
data JinjaDialect
= DialectGinger2
| DialectJinja2
deriving (Int -> JinjaDialect -> ShowS
[JinjaDialect] -> ShowS
JinjaDialect -> String
(Int -> JinjaDialect -> ShowS)
-> (JinjaDialect -> String)
-> ([JinjaDialect] -> ShowS)
-> Show JinjaDialect
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JinjaDialect -> ShowS
showsPrec :: Int -> JinjaDialect -> ShowS
$cshow :: JinjaDialect -> String
show :: JinjaDialect -> String
$cshowList :: [JinjaDialect] -> ShowS
showList :: [JinjaDialect] -> ShowS
Show, JinjaDialect -> JinjaDialect -> Bool
(JinjaDialect -> JinjaDialect -> Bool)
-> (JinjaDialect -> JinjaDialect -> Bool) -> Eq JinjaDialect
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JinjaDialect -> JinjaDialect -> Bool
== :: JinjaDialect -> JinjaDialect -> Bool
$c/= :: JinjaDialect -> JinjaDialect -> Bool
/= :: JinjaDialect -> JinjaDialect -> Bool
Eq, Eq JinjaDialect
Eq JinjaDialect =>
(JinjaDialect -> JinjaDialect -> Ordering)
-> (JinjaDialect -> JinjaDialect -> Bool)
-> (JinjaDialect -> JinjaDialect -> Bool)
-> (JinjaDialect -> JinjaDialect -> Bool)
-> (JinjaDialect -> JinjaDialect -> Bool)
-> (JinjaDialect -> JinjaDialect -> JinjaDialect)
-> (JinjaDialect -> JinjaDialect -> JinjaDialect)
-> Ord JinjaDialect
JinjaDialect -> JinjaDialect -> Bool
JinjaDialect -> JinjaDialect -> Ordering
JinjaDialect -> JinjaDialect -> JinjaDialect
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: JinjaDialect -> JinjaDialect -> Ordering
compare :: JinjaDialect -> JinjaDialect -> Ordering
$c< :: JinjaDialect -> JinjaDialect -> Bool
< :: JinjaDialect -> JinjaDialect -> Bool
$c<= :: JinjaDialect -> JinjaDialect -> Bool
<= :: JinjaDialect -> JinjaDialect -> Bool
$c> :: JinjaDialect -> JinjaDialect -> Bool
> :: JinjaDialect -> JinjaDialect -> Bool
$c>= :: JinjaDialect -> JinjaDialect -> Bool
>= :: JinjaDialect -> JinjaDialect -> Bool
$cmax :: JinjaDialect -> JinjaDialect -> JinjaDialect
max :: JinjaDialect -> JinjaDialect -> JinjaDialect
$cmin :: JinjaDialect -> JinjaDialect -> JinjaDialect
min :: JinjaDialect -> JinjaDialect -> JinjaDialect
Ord, Int -> JinjaDialect
JinjaDialect -> Int
JinjaDialect -> [JinjaDialect]
JinjaDialect -> JinjaDialect
JinjaDialect -> JinjaDialect -> [JinjaDialect]
JinjaDialect -> JinjaDialect -> JinjaDialect -> [JinjaDialect]
(JinjaDialect -> JinjaDialect)
-> (JinjaDialect -> JinjaDialect)
-> (Int -> JinjaDialect)
-> (JinjaDialect -> Int)
-> (JinjaDialect -> [JinjaDialect])
-> (JinjaDialect -> JinjaDialect -> [JinjaDialect])
-> (JinjaDialect -> JinjaDialect -> [JinjaDialect])
-> (JinjaDialect -> JinjaDialect -> JinjaDialect -> [JinjaDialect])
-> Enum JinjaDialect
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: JinjaDialect -> JinjaDialect
succ :: JinjaDialect -> JinjaDialect
$cpred :: JinjaDialect -> JinjaDialect
pred :: JinjaDialect -> JinjaDialect
$ctoEnum :: Int -> JinjaDialect
toEnum :: Int -> JinjaDialect
$cfromEnum :: JinjaDialect -> Int
fromEnum :: JinjaDialect -> Int
$cenumFrom :: JinjaDialect -> [JinjaDialect]
enumFrom :: JinjaDialect -> [JinjaDialect]
$cenumFromThen :: JinjaDialect -> JinjaDialect -> [JinjaDialect]
enumFromThen :: JinjaDialect -> JinjaDialect -> [JinjaDialect]
$cenumFromTo :: JinjaDialect -> JinjaDialect -> [JinjaDialect]
enumFromTo :: JinjaDialect -> JinjaDialect -> [JinjaDialect]
$cenumFromThenTo :: JinjaDialect -> JinjaDialect -> JinjaDialect -> [JinjaDialect]
enumFromThenTo :: JinjaDialect -> JinjaDialect -> JinjaDialect -> [JinjaDialect]
Enum, JinjaDialect
JinjaDialect -> JinjaDialect -> Bounded JinjaDialect
forall a. a -> a -> Bounded a
$cminBound :: JinjaDialect
minBound :: JinjaDialect
$cmaxBound :: JinjaDialect
maxBound :: JinjaDialect
Bounded)
ginger :: forall m g. (Monad m, SplitGen g)
=> TemplateLoader m
-> POptions
-> JinjaDialect
-> g
-> Encoder m
-> Text
-> Map Identifier (Value (RandT g m))
-> m (Either RuntimeError Encoded)
ginger :: forall (m :: * -> *) g.
(Monad m, SplitGen g) =>
TemplateLoader m
-> POptions
-> JinjaDialect
-> g
-> Encoder m
-> Text
-> Map Identifier (Value (RandT g m))
-> m (Either RuntimeError Encoded)
ginger TemplateLoader m
loader POptions
parserOptions JinjaDialect
dialect g
rng Encoder m
encoder Text
templateName Map Identifier (Value (RandT g m))
vars =
(RandT g m (Either RuntimeError Encoded)
-> g -> m (Either RuntimeError Encoded))
-> g
-> RandT g m (Either RuntimeError Encoded)
-> m (Either RuntimeError Encoded)
forall a b c. (a -> b -> c) -> b -> a -> c
flip RandT g m (Either RuntimeError Encoded)
-> g -> m (Either RuntimeError Encoded)
forall (m :: * -> *) g a. Monad m => RandT g m a -> g -> m a
evalRandT g
rng (RandT g m (Either RuntimeError Encoded)
-> m (Either RuntimeError Encoded))
-> RandT g m (Either RuntimeError Encoded)
-> m (Either RuntimeError Encoded)
forall a b. (a -> b) -> a -> b
$
ExceptT RuntimeError (RandT g m) Encoded
-> RandT g m (Either RuntimeError Encoded)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT RuntimeError (RandT g m) Encoded
-> RandT g m (Either RuntimeError Encoded))
-> ExceptT RuntimeError (RandT g m) Encoded
-> RandT g m (Either RuntimeError Encoded)
forall a b. (a -> b) -> a -> b
$ do
templateSrc <- ExceptT RuntimeError (RandT g m) Text
-> (Text -> ExceptT RuntimeError (RandT g m) Text)
-> Maybe Text
-> ExceptT RuntimeError (RandT g m) Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
(RuntimeError -> ExceptT RuntimeError (RandT g m) Text
forall a. RuntimeError -> ExceptT RuntimeError (RandT g m) a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (RuntimeError -> ExceptT RuntimeError (RandT g m) Text)
-> RuntimeError -> ExceptT RuntimeError (RandT g m) Text
forall a b. (a -> b) -> a -> b
$ Text -> RuntimeError
TemplateFileNotFoundError Text
templateName)
Text -> ExceptT RuntimeError (RandT g m) Text
forall a. a -> ExceptT RuntimeError (RandT g m) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
(Maybe Text -> ExceptT RuntimeError (RandT g m) Text)
-> ExceptT RuntimeError (RandT g m) (Maybe Text)
-> ExceptT RuntimeError (RandT g m) Text
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (RandT g m (Maybe Text)
-> ExceptT RuntimeError (RandT g m) (Maybe Text)
forall (m :: * -> *) a. Monad m => m a -> ExceptT RuntimeError m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (RandT g m (Maybe Text)
-> ExceptT RuntimeError (RandT g m) (Maybe Text))
-> (m (Maybe Text) -> RandT g m (Maybe Text))
-> m (Maybe Text)
-> ExceptT RuntimeError (RandT g m) (Maybe Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m (Maybe Text) -> RandT g m (Maybe Text)
forall (m :: * -> *) a. Monad m => m a -> RandT g m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift) (TemplateLoader m
loader Text
templateName)
let parseResult = POptions -> P Template -> String -> Text -> Either String Template
forall a. POptions -> P a -> String -> Text -> Either String a
P.parseGingerWith
POptions
parserOptions
P Template
P.template
(Text -> String
Text.unpack Text
templateName)
Text
templateSrc
template <- either
(throwError . TemplateParseError templateName . Text.pack)
pure
parseResult
let ctx = Context (RandT g m)
forall (m :: * -> *). MonadRandom m => Context m
defContext
{ contextEncode = (lift . encoder)
, contextLoadTemplateFile = (lift . loader)
}
defVars' = case JinjaDialect
dialect of
JinjaDialect
DialectGinger2 -> Map Identifier (Value (RandT g m))
forall (m :: * -> *). MonadRandom m => Map Identifier (Value m)
defVars
JinjaDialect
DialectJinja2 -> Map Identifier (Value (RandT g m))
forall (m :: * -> *). MonadRandom m => Map Identifier (Value m)
defVarsCompat
env = Env (RandT g m)
forall (m :: * -> *). Monad m => Env m
defEnv
{ envVars = defVars' <> vars
}
eitherExceptM $
(runGingerT
(evalT template >>= encode)
ctx
env
)
$(addHaddockFromFile "src/Language/Ginger.haddock")
$(builtinsAutodoc)