-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Typed templates with jinja like syntax -- -- Typed templates with jinja like syntax. Well-typed templates don't go -- wrong. @package zinza @version 0.2 -- | Zinza - a small jinja-syntax-inspired typed-template compiler. -- -- Zinza typechecks and compiles a template. We can compile either to -- Haskell function, or to verbatim Haskell module (planned). -- -- Zinza is very minimalistic. Features are added when needed. -- --

Example usage

-- -- Given a template -- --
--   {% for license in licenses %}
--   licenseName {{license.con}} = {{license.name}}
--   {% endfor %}
--   
-- -- and data definitions like: -- --
--   newtype Licenses = Licenses { licenses :: [License] }
--     deriving (Generic)
--   
--   data License = License
--       { licenseCon  :: String
--       , licenseName :: String
--       }
--     deriving (Generic)
--   
-- -- We can (generically) derive Zinza instances for -- Licenses and License -- --
--   instance Zinza Licenses where
--       toType    = genericToType    id
--       toValue   = genericToValue   id
--       fromValue = genericFromValue id
--   
--   instance Zinza License where
--       toType    = genericToTypeSFP
--       toValue   = genericToValueSFP
--       fromValue = genericFromValueSFP
--   
-- -- Then the example of run-time usage is -- --
--   example :: IO String
--   example = do
--       -- this might fail, type errors!
--       run <- parseAndCompileTemplateIO "fixtures/licenses.zinza"
--       -- this shouldn't fail (run-time errors are due bugs in zinza)
--       run $ Licenses
--           [ License "Foo" (show "foo-1.0")
--           , License "Bar" (show "bar-1.2")
--           ]
--   
-- -- The result of running an example is: -- --
--   licenseName Foo = "foo-1.0"
--   licenseName Bar = "bar-1.2"
--   
-- --

Module generation

-- -- Zinza also supports standalone module generation. -- --
--   parseAndCompileModuleIO (simpleConfig "DemoLicenses" ["Licenses"] :: ModuleConfig Licenses) "fixtures/licenses.zinza" >>= putStr
--   
-- -- prints a Haskell module source code: -- --
--   {--}
--   module DemoLicenses (render) where
--   import Prelude (String, fst, snd, ($), not, return)
--   import Control.Monad (forM_)
--   import Licenses
--   type Writer a = (String, a)
--   tell :: String -> Writer (); tell x = (x, ())
--   execWriter :: Writer a -> String; execWriter = fst
--   render :: Licenses -> String
--   render (z_root) = execWriter $ do
--     forM_ (licenses $ z_root) $ z_var0_license -> do
--       tell "licenseName "
--       tell (licenseCon $ z_var0_license)
--       tell " = "
--       tell (licenseName $ z_var0_license)
--       tell "n"
--   
-- -- which is not dependent on Zinza. You are free to use more efficient -- writer as well. -- --

Expressions

-- --
--   {{ expression }}
--   
-- -- Expression syntax has only few constructions: -- -- -- -- Note: you can provide your own Prelude of functions. See -- Bools.hs and Bools.zinza in tests for an example. -- You cannot define new functions in templates, but you can pass them as -- template arguments. -- --

Control structures

-- -- The for and if statements are supported: -- --
--   {% for value in values %}
--   ...
--   {% endfor %}
--   
-- --
--   {% if boolExpression %}
--   ...
--   {% elif anotherBoolExpression %}
--   ...
--   {% else %}
--   ...
--   {% endif %}
--   
-- -- If a control structure tag starts at the first column, the possible -- trailing new line feed is stripped. This way full-line control tags -- don't introduce new lines in the output. -- --

Blocks

-- -- It's possible to define blocks to be used (possibly multiple times) -- later: -- --
--   {% defblock blockname %}
--   ...
--   {% endblock %}
--   
-- -- And the block can be used later with: -- --
--   {% useblock blockname %}
--   
-- -- Blocks follow scopes of if and for control -- structures -- --

Comments

-- --
--   {# Comments are omitted from the output #}
--   
module Zinza -- | Parse and compile the template into Haskell function. parseAndCompileTemplate :: (Zinza a, ThrowRuntime m) => FilePath -> String -> Either CompileOrParseError (a -> m String) -- | Like parseAndCompileTemplate but reads file and (possibly) -- throws CompileOrParseError. parseAndCompileTemplateIO :: (Zinza a, ThrowRuntime m) => FilePath -> IO (a -> m String) -- | Parse and compile the template into String representing a -- Haskell module. parseAndCompileModule :: Zinza a => ModuleConfig a -> FilePath -> String -> Either CompileOrParseError String -- | Like parseAndCompileModule but reads file and (possibly) throws -- CompileOrParseError. parseAndCompileModuleIO :: Zinza a => ModuleConfig a -> FilePath -> IO String -- | Configuration for module rendering data ModuleConfig a ModuleConfig :: [String] -> String -> ModuleConfig a -- | module header [mcHeader] :: ModuleConfig a -> [String] -- | name of the function [mcRender] :: ModuleConfig a -> String -- | Simple configuration to use with parseAndCompileModule or -- parseAndCompileModuleIO. simpleConfig :: forall a. Typeable a => String -> [String] -> ModuleConfig a -- | Zinza class tells how to convert the type into template -- parameters, and their types. -- -- Class can be auto-derived for product types. -- --
--   >>> data R = R { recFoo :: String, recBar :: Char } deriving Generic
--   
--   >>> instance Zinza R where toType = genericToTypeSFP; toValue = genericToValueSFP; fromValue = genericFromValueSFP
--   
--   >>> displayTy $ toType (Proxy :: Proxy R)
--   "{bar: String, foo: String}"
--   
class Zinza a toType :: Zinza a => Proxy a -> Ty toTypeList :: Zinza a => Proxy a -> Ty toValue :: Zinza a => a -> Value toValueList :: Zinza a => [a] -> Value fromValue :: Zinza a => Loc -> Value -> Either RuntimeError a fromValueList :: Zinza a => Loc -> Value -> Either RuntimeError [a] -- | Generically derive toType function. genericToType :: forall a. (Generic a, GZinzaType (Rep a)) => (String -> String) -> Proxy a -> Ty -- | Generically derive toValue function. genericToValue :: forall a. (Generic a, GZinzaValue (Rep a)) => (String -> String) -> a -> Value genericFromValue :: forall a. (Generic a, GZinzaFrom (Rep a)) => (String -> String) -> Loc -> Value -> Either RuntimeError a -- | genericToType with stripFieldPrefix. genericToTypeSFP :: forall a. (Generic a, GZinzaType (Rep a), GFieldNames (Rep a)) => Proxy a -> Ty -- | genericToValue with stripFieldPrefix. genericToValueSFP :: forall a. (Generic a, GZinzaValue (Rep a), GFieldNames (Rep a)) => a -> Value -- | genericFromValue with stripFieldPrefix. genericFromValueSFP :: forall a. (Generic a, GZinzaFrom (Rep a), GFieldNames (Rep a)) => Loc -> Value -> Either RuntimeError a -- | Field renamer which will automatically strip lowercase prefix from -- field names. -- --
--   >>> data R = R { recFoo :: Int, recBar :: Char } deriving Generic
--   
--   >>> stripFieldPrefix (Proxy :: Proxy R) "recFoo"
--   "foo"
--   
-- -- If whole field is lower case, it's left intact -- --
--   >>> newtype Wrapped = Wrap { unwrap :: String } deriving Generic
--   
--   >>> stripFieldPrefix (Proxy :: Proxy Wrapped) "unwrap"
--   "unwrap"
--   
stripFieldPrefix :: forall a. (Generic a, GFieldNames (Rep a)) => Proxy a -> String -> String class GZinzaType (f :: Type -> Type) class GZinzaValue (f :: Type -> Type) class GZinzaFrom (f :: Type -> Type) class GFieldNames (f :: Type -> Type) -- | Template parts. -- -- We use polymorphic recursion for de Bruijn indices. See materials on -- bound library. data Node a -- | raw text block NRaw :: String -> Node a -- | expression expr : String NExpr :: LExpr a -> Node a -- | conditional block, expr : Bool NIf :: LExpr a -> Nodes a -> Nodes a -> Node a -- | for loop, expr : List a NFor :: Var -> LExpr a -> Nodes (Maybe a) -> Node a -- | define block NDefBlock :: Loc -> Var -> Nodes a -> Node a -- | use block NUseBlock :: Loc -> Var -> Node a -- | comments NComment :: Node a -- | A list of Nodes. type Nodes a = [Node a] -- | Expressions in templates. -- -- Note: there are only eliminators; we cannot construct "bigger" -- expressions. data Expr a -- | variable EVar :: Located a -> Expr a -- | field accessor EField :: LExpr a -> Located Var -> Expr a -- | function application EApp :: LExpr a -> LExpr a -> Expr a -- | Located expression. type LExpr a = Located (Expr a) -- | Zinza types. -- -- The selectors tell how the Haskell value can be converted to -- primitive value. E.g. -- --
--   >>> toType (Proxy :: Proxy Char)
--   TyString (Just "return")
--   
-- -- Here, return converts Char to String. data Ty -- | boolean TyBool :: Ty -- | string TyString :: Maybe Selector -> Ty -- | lists TyList :: Maybe Selector -> Ty -> Ty -- | records TyRecord :: Map Var (Selector, Ty) -> Ty -- | functions TyFun :: Ty -> Ty -> Ty -- | Pretty print Ty. displayTy :: Ty -> String -- | Template values. data Value -- | booleans VBool :: Bool -> Value -- | strings VString :: String -> Value -- | lists VList :: [Value] -> Value -- | records VRecord :: Map Var Value -> Value -- | function VFun :: (Value -> Either RuntimeError Value) -> Value newtype ParseError ParseError :: String -> ParseError data CompileError UnboundTopLevelVar :: Loc -> Var -> CompileError ShadowingBlock :: Loc -> Var -> CompileError UnboundUseBlock :: Loc -> Var -> CompileError ARuntimeError :: RuntimeError -> CompileError data CompileOrParseError ACompileError :: CompileError -> CompileOrParseError AParseError :: ParseError -> CompileOrParseError data RuntimeError NotBool :: Loc -> Ty -> RuntimeError NotString :: Loc -> Ty -> RuntimeError NotRecord :: Loc -> Ty -> RuntimeError NotList :: Loc -> Ty -> RuntimeError FieldNotInRecord :: Loc -> Var -> Ty -> RuntimeError NotFunction :: Loc -> Ty -> RuntimeError FunArgDontMatch :: Loc -> Ty -> Ty -> RuntimeError CustomError :: Loc -> String -> Ty -> RuntimeError -- | Class representing errors containing RuntimeErrors. -- -- Without bugs, compiled template should not throw any -- RuntimeErrors, as they are prevented statically, i.e. reported -- already as CompileErrors. class AsRuntimeError e asRuntimeError :: AsRuntimeError e => RuntimeError -> e class Monad m => ThrowRuntime m throwRuntime :: ThrowRuntime m => RuntimeError -> m a -- | Location, line and column. data Loc Loc :: !Int -> !Int -> Loc -- | Located element. data Located a L :: {-# UNPACK #-} !Loc -> a -> Located a -- | Unknown location. zeroLoc :: Loc -- | Pretty-print location. displayLoc :: Loc -> String -- | Some containers have location for each element. class Traversable t => TraversableWithLoc t traverseWithLoc :: (TraversableWithLoc t, Applicative f) => (Loc -> a -> f b) -> t a -> f (t b) -- | Variable name, possibly a fieldname in the record. type Var = String -- | Haskell selector. type Selector = String