{-#LANGUAGE DeriveFunctor #-}
-- | Implements Ginger's Abstract Syntax Tree.
module Text.Ginger.AST
where

import Data.Text (Text)
import qualified Data.Text as Text
import Text.Ginger.Html
import Data.Scientific (Scientific)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap


-- | A context variable name.
type VarName = Text

-- | Top-level data structure, representing a fully parsed template.
data Template a
    = Template
        { Template a -> Statement a
templateBody :: Statement a
        , Template a -> HashMap VarName (Block a)
templateBlocks :: HashMap VarName (Block a)
        , Template a -> Maybe (Template a)
templateParent :: Maybe (Template a)
        }
        deriving (Int -> Template a -> ShowS
[Template a] -> ShowS
Template a -> String
(Int -> Template a -> ShowS)
-> (Template a -> String)
-> ([Template a] -> ShowS)
-> Show (Template a)
forall a. Show a => Int -> Template a -> ShowS
forall a. Show a => [Template a] -> ShowS
forall a. Show a => Template a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Template a] -> ShowS
$cshowList :: forall a. Show a => [Template a] -> ShowS
show :: Template a -> String
$cshow :: forall a. Show a => Template a -> String
showsPrec :: Int -> Template a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Template a -> ShowS
Show, a -> Template b -> Template a
(a -> b) -> Template a -> Template b
(forall a b. (a -> b) -> Template a -> Template b)
-> (forall a b. a -> Template b -> Template a) -> Functor Template
forall a b. a -> Template b -> Template a
forall a b. (a -> b) -> Template a -> Template b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Template b -> Template a
$c<$ :: forall a b. a -> Template b -> Template a
fmap :: (a -> b) -> Template a -> Template b
$cfmap :: forall a b. (a -> b) -> Template a -> Template b
Functor)

-- | A macro definition ( @{% macro %}@ )
data Macro a
    = Macro { Macro a -> [VarName]
macroArgs :: [VarName], Macro a -> Statement a
macroBody :: Statement a }
    deriving (Int -> Macro a -> ShowS
[Macro a] -> ShowS
Macro a -> String
(Int -> Macro a -> ShowS)
-> (Macro a -> String) -> ([Macro a] -> ShowS) -> Show (Macro a)
forall a. Show a => Int -> Macro a -> ShowS
forall a. Show a => [Macro a] -> ShowS
forall a. Show a => Macro a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Macro a] -> ShowS
$cshowList :: forall a. Show a => [Macro a] -> ShowS
show :: Macro a -> String
$cshow :: forall a. Show a => Macro a -> String
showsPrec :: Int -> Macro a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Macro a -> ShowS
Show, a -> Macro b -> Macro a
(a -> b) -> Macro a -> Macro b
(forall a b. (a -> b) -> Macro a -> Macro b)
-> (forall a b. a -> Macro b -> Macro a) -> Functor Macro
forall a b. a -> Macro b -> Macro a
forall a b. (a -> b) -> Macro a -> Macro b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Macro b -> Macro a
$c<$ :: forall a b. a -> Macro b -> Macro a
fmap :: (a -> b) -> Macro a -> Macro b
$cfmap :: forall a b. (a -> b) -> Macro a -> Macro b
Functor)

-- | A block definition ( @{% block %}@ )
data Block a
    = Block { Block a -> Statement a
blockBody :: Statement a } -- TODO: scoped blocks
    deriving (Int -> Block a -> ShowS
[Block a] -> ShowS
Block a -> String
(Int -> Block a -> ShowS)
-> (Block a -> String) -> ([Block a] -> ShowS) -> Show (Block a)
forall a. Show a => Int -> Block a -> ShowS
forall a. Show a => [Block a] -> ShowS
forall a. Show a => Block a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Block a] -> ShowS
$cshowList :: forall a. Show a => [Block a] -> ShowS
show :: Block a -> String
$cshow :: forall a. Show a => Block a -> String
showsPrec :: Int -> Block a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Block a -> ShowS
Show, a -> Block b -> Block a
(a -> b) -> Block a -> Block b
(forall a b. (a -> b) -> Block a -> Block b)
-> (forall a b. a -> Block b -> Block a) -> Functor Block
forall a b. a -> Block b -> Block a
forall a b. (a -> b) -> Block a -> Block b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Block b -> Block a
$c<$ :: forall a b. a -> Block b -> Block a
fmap :: (a -> b) -> Block a -> Block b
$cfmap :: forall a b. (a -> b) -> Block a -> Block b
Functor)

-- | Ginger statements.
data Statement a
    = MultiS a [Statement a] -- ^ A sequence of multiple statements
    | ScopedS a (Statement a) -- ^ Run wrapped statement in a local scope
    | IndentS a (Expression a) (Statement a) -- ^ Establish an indented context around the wrapped statement
    | LiteralS a Html -- ^ Literal output (anything outside of any tag)
    | InterpolationS a (Expression a) -- ^ {{ expression }}
    | ExpressionS a (Expression a) -- ^ Evaluate expression
    | IfS a (Expression a) (Statement a) (Statement a) -- ^ {% if expression %}statement{% else %}statement{% endif %}
    | SwitchS a (Expression a) [((Expression a), (Statement a))] (Statement a) -- ^ {% switch expression %}{% case expression %}statement{% endcase %}...{% default %}statement{% enddefault %}{% endswitch %}
    | ForS a (Maybe VarName) VarName (Expression a) (Statement a) -- ^ {% for index, varname in expression %}statement{% endfor %}
    | SetVarS a VarName (Expression a) -- ^ {% set varname = expr %}
    | DefMacroS a VarName (Macro a) -- ^ {% macro varname %}statements{% endmacro %}
    | BlockRefS a VarName
    | PreprocessedIncludeS a (Template a) -- ^ {% include "template" %}
    | NullS a -- ^ The do-nothing statement (NOP)
    | TryCatchS a (Statement a) [CatchBlock a] (Statement a) -- ^ Try / catch / finally
    deriving (Int -> Statement a -> ShowS
[Statement a] -> ShowS
Statement a -> String
(Int -> Statement a -> ShowS)
-> (Statement a -> String)
-> ([Statement a] -> ShowS)
-> Show (Statement a)
forall a. Show a => Int -> Statement a -> ShowS
forall a. Show a => [Statement a] -> ShowS
forall a. Show a => Statement a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Statement a] -> ShowS
$cshowList :: forall a. Show a => [Statement a] -> ShowS
show :: Statement a -> String
$cshow :: forall a. Show a => Statement a -> String
showsPrec :: Int -> Statement a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Statement a -> ShowS
Show, a -> Statement b -> Statement a
(a -> b) -> Statement a -> Statement b
(forall a b. (a -> b) -> Statement a -> Statement b)
-> (forall a b. a -> Statement b -> Statement a)
-> Functor Statement
forall a b. a -> Statement b -> Statement a
forall a b. (a -> b) -> Statement a -> Statement b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Statement b -> Statement a
$c<$ :: forall a b. a -> Statement b -> Statement a
fmap :: (a -> b) -> Statement a -> Statement b
$cfmap :: forall a b. (a -> b) -> Statement a -> Statement b
Functor)

stmtAnnotation :: Statement p -> p
stmtAnnotation (MultiS p
a [Statement p]
_) = p
a
stmtAnnotation (ScopedS p
a Statement p
_) = p
a
stmtAnnotation (IndentS p
a Expression p
_ Statement p
_) = p
a
stmtAnnotation (LiteralS p
a Html
_) = p
a
stmtAnnotation (InterpolationS p
a Expression p
_) = p
a
stmtAnnotation (ExpressionS p
a Expression p
_) = p
a
stmtAnnotation (IfS p
a Expression p
_ Statement p
_ Statement p
_) = p
a
stmtAnnotation (SwitchS p
a Expression p
_ [(Expression p, Statement p)]
_ Statement p
_) = p
a
stmtAnnotation (ForS p
a Maybe VarName
_ VarName
_ Expression p
_ Statement p
_) = p
a
stmtAnnotation (SetVarS p
a VarName
_ Expression p
_) = p
a
stmtAnnotation (DefMacroS p
a VarName
_ Macro p
_) = p
a
stmtAnnotation (BlockRefS p
a VarName
_) = p
a
stmtAnnotation (PreprocessedIncludeS p
a Template p
_) = p
a
stmtAnnotation (NullS p
a) = p
a
stmtAnnotation (TryCatchS p
a Statement p
_ [CatchBlock p]
_ Statement p
_) = p
a

-- | A @catch@ block
data CatchBlock a =
    Catch
        { CatchBlock a -> Maybe VarName
catchWhat :: Maybe Text
        , CatchBlock a -> Maybe VarName
catchCaptureAs :: Maybe VarName
        , CatchBlock a -> Statement a
catchBody :: Statement a
        }
        deriving (Int -> CatchBlock a -> ShowS
[CatchBlock a] -> ShowS
CatchBlock a -> String
(Int -> CatchBlock a -> ShowS)
-> (CatchBlock a -> String)
-> ([CatchBlock a] -> ShowS)
-> Show (CatchBlock a)
forall a. Show a => Int -> CatchBlock a -> ShowS
forall a. Show a => [CatchBlock a] -> ShowS
forall a. Show a => CatchBlock a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CatchBlock a] -> ShowS
$cshowList :: forall a. Show a => [CatchBlock a] -> ShowS
show :: CatchBlock a -> String
$cshow :: forall a. Show a => CatchBlock a -> String
showsPrec :: Int -> CatchBlock a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> CatchBlock a -> ShowS
Show, a -> CatchBlock b -> CatchBlock a
(a -> b) -> CatchBlock a -> CatchBlock b
(forall a b. (a -> b) -> CatchBlock a -> CatchBlock b)
-> (forall a b. a -> CatchBlock b -> CatchBlock a)
-> Functor CatchBlock
forall a b. a -> CatchBlock b -> CatchBlock a
forall a b. (a -> b) -> CatchBlock a -> CatchBlock b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> CatchBlock b -> CatchBlock a
$c<$ :: forall a b. a -> CatchBlock b -> CatchBlock a
fmap :: (a -> b) -> CatchBlock a -> CatchBlock b
$cfmap :: forall a b. (a -> b) -> CatchBlock a -> CatchBlock b
Functor)

-- | Expressions, building blocks for the expression minilanguage.
data Expression a
    = StringLiteralE a Text -- ^ String literal expression: "foobar"
    | NumberLiteralE a Scientific -- ^ Numeric literal expression: 123.4
    | BoolLiteralE a Bool -- ^ Boolean literal expression: true
    | NullLiteralE a -- ^ Literal null
    | VarE a VarName -- ^ Variable reference: foobar
    | ListE a [(Expression a)] -- ^ List construct: [ expr, expr, expr ]
    | ObjectE a [((Expression a), (Expression a))] -- ^ Object construct: { expr: expr, expr: expr, ... }
    | MemberLookupE a (Expression a) (Expression a) -- ^ foo[bar] (also dot access)
    | CallE a (Expression a) [(Maybe Text, (Expression a))] -- ^ foo(bar=baz, quux)
    | LambdaE a [Text] (Expression a) -- ^ (foo, bar) -> expr
    | TernaryE a (Expression a) (Expression a) (Expression a) -- ^ expr ? expr : expr
    | DoE a (Statement a) -- ^ do { statement; }
    deriving (Int -> Expression a -> ShowS
[Expression a] -> ShowS
Expression a -> String
(Int -> Expression a -> ShowS)
-> (Expression a -> String)
-> ([Expression a] -> ShowS)
-> Show (Expression a)
forall a. Show a => Int -> Expression a -> ShowS
forall a. Show a => [Expression a] -> ShowS
forall a. Show a => Expression a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Expression a] -> ShowS
$cshowList :: forall a. Show a => [Expression a] -> ShowS
show :: Expression a -> String
$cshow :: forall a. Show a => Expression a -> String
showsPrec :: Int -> Expression a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Expression a -> ShowS
Show, a -> Expression b -> Expression a
(a -> b) -> Expression a -> Expression b
(forall a b. (a -> b) -> Expression a -> Expression b)
-> (forall a b. a -> Expression b -> Expression a)
-> Functor Expression
forall a b. a -> Expression b -> Expression a
forall a b. (a -> b) -> Expression a -> Expression b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Expression b -> Expression a
$c<$ :: forall a b. a -> Expression b -> Expression a
fmap :: (a -> b) -> Expression a -> Expression b
$cfmap :: forall a b. (a -> b) -> Expression a -> Expression b
Functor)

exprAnnotation :: Expression p -> p
exprAnnotation (StringLiteralE p
a VarName
_) = p
a
exprAnnotation (NumberLiteralE p
a Scientific
_) = p
a
exprAnnotation (BoolLiteralE p
a Bool
_) = p
a
exprAnnotation (NullLiteralE p
a) = p
a
exprAnnotation (VarE p
a VarName
_) = p
a
exprAnnotation (ListE p
a [Expression p]
_) = p
a
exprAnnotation (ObjectE p
a [(Expression p, Expression p)]
_) = p
a
exprAnnotation (MemberLookupE p
a Expression p
_ Expression p
_) = p
a
exprAnnotation (CallE p
a Expression p
_ [(Maybe VarName, Expression p)]
_) = p
a
exprAnnotation (LambdaE p
a [VarName]
_ Expression p
_) = p
a
exprAnnotation (TernaryE p
a Expression p
_ Expression p
_ Expression p
_) = p
a
exprAnnotation (DoE p
a Statement p
_) = p
a

class Annotated f where
    annotation :: f p -> p

instance Annotated Expression where
    annotation :: Expression p -> p
annotation = Expression p -> p
forall p. Expression p -> p
exprAnnotation

instance Annotated Statement where
    annotation :: Statement p -> p
annotation = Statement p -> p
forall p. Statement p -> p
stmtAnnotation

instance Annotated Block where
    annotation :: Block p -> p
annotation = Statement p -> p
forall (f :: * -> *) p. Annotated f => f p -> p
annotation (Statement p -> p) -> (Block p -> Statement p) -> Block p -> p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Block p -> Statement p
forall a. Block a -> Statement a
blockBody

instance Annotated Macro where
    annotation :: Macro p -> p
annotation = Statement p -> p
forall (f :: * -> *) p. Annotated f => f p -> p
annotation (Statement p -> p) -> (Macro p -> Statement p) -> Macro p -> p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Macro p -> Statement p
forall a. Macro a -> Statement a
macroBody

instance Annotated Template where
    annotation :: Template p -> p
annotation = Statement p -> p
forall (f :: * -> *) p. Annotated f => f p -> p
annotation (Statement p -> p)
-> (Template p -> Statement p) -> Template p -> p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Template p -> Statement p
forall a. Template a -> Statement a
templateBody