-- 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. -- --
-- {% 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" ---- --
-- 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.
--
--
-- {{ expression }}
--
--
-- Expression syntax has only few constructions:
--
--
-- {% 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.
--
--
-- {% defblock blockname %}
-- ...
-- {% endblock %}
--
--
-- And the block can be used later with:
--
--
-- {% useblock blockname %}
--
--
-- Blocks follow scopes of if and for control
-- structures
--
--
-- {# 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