ginger-0.7.0.0: src/Text/Ginger/AST.hs
{-#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
{ templateBody :: Statement a
, templateBlocks :: HashMap VarName (Block a)
, templateParent :: Maybe (Template a)
}
deriving (Show, Functor)
-- | A macro definition ( @{% macro %}@ )
data Macro a
= Macro { macroArgs :: [VarName], macroBody :: Statement a }
deriving (Show, Functor)
-- | A block definition ( @{% block %}@ )
data Block a
= Block { blockBody :: Statement a } -- TODO: scoped blocks
deriving (Show, 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 (Show, Functor)
stmtAnnotation (MultiS a _) = a
stmtAnnotation (ScopedS a _) = a
stmtAnnotation (IndentS a _ _) = a
stmtAnnotation (LiteralS a _) = a
stmtAnnotation (InterpolationS a _) = a
stmtAnnotation (ExpressionS a _) = a
stmtAnnotation (IfS a _ _ _) = a
stmtAnnotation (SwitchS a _ _ _) = a
stmtAnnotation (ForS a _ _ _ _) = a
stmtAnnotation (SetVarS a _ _) = a
stmtAnnotation (DefMacroS a _ _) = a
stmtAnnotation (BlockRefS a _) = a
stmtAnnotation (PreprocessedIncludeS a _) = a
stmtAnnotation (NullS a) = a
stmtAnnotation (TryCatchS a _ _ _) = a
-- | A @catch@ block
data CatchBlock a =
Catch
{ catchWhat :: Maybe Text
, catchCaptureAs :: Maybe VarName
, catchBody :: Statement a
}
deriving (Show, 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 (Show, Functor)
exprAnnotation (StringLiteralE a _) = a
exprAnnotation (NumberLiteralE a _) = a
exprAnnotation (BoolLiteralE a _) = a
exprAnnotation (NullLiteralE a) = a
exprAnnotation (VarE a _) = a
exprAnnotation (ListE a _) = a
exprAnnotation (ObjectE a _) = a
exprAnnotation (MemberLookupE a _ _) = a
exprAnnotation (CallE a _ _) = a
exprAnnotation (LambdaE a _ _) = a
exprAnnotation (TernaryE a _ _ _) = a
exprAnnotation (DoE a _) = a
class Annotated f where
annotation :: f p -> p
instance Annotated Expression where
annotation = exprAnnotation
instance Annotated Statement where
annotation = stmtAnnotation
instance Annotated Block where
annotation = annotation . blockBody
instance Annotated Macro where
annotation = annotation . macroBody
instance Annotated Template where
annotation = annotation . templateBody