on bd5f6ca help sign in
hakyll/src/Hakyll/Core/Compiler.hs
89 lines 2.6 kB history raw
1-- | A Compiler manages targets and dependencies between targets.
2--
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4module Hakyll.Core.Compiler
5 ( Dependencies
6 , CompilerM
7 , Compiler
8 , runCompiler
9 , require
10 , target
11 , targetFromString
12 ) where
14import Control.Arrow (second)
15import Control.Applicative (Applicative, (<$>))
16import Control.Monad.State (State, modify, runState)
17import Control.Monad.Reader (ReaderT, ask, runReaderT)
18import Data.Set (Set)
19import qualified Data.Set as S
21import Hakyll.Core.Identifier
22import Hakyll.Core.Target
23import Hakyll.Core.Target.Internal
25-- | A set of dependencies
26--
27type Dependencies = Set Identifier
29-- | Add one dependency
30--
31addDependency :: Identifier -> CompilerM a ()
32addDependency dependency = CompilerM $ modify $ addDependency'
33 where
34 addDependency' x = x
35 { compilerDependencies = S.insert dependency $ compilerDependencies x
36 }
38-- | Environment in which a compiler runs
39--
40data CompilerEnvironment a = CompilerEnvironment
41 { compilerIdentifier :: Identifier -- ^ Target identifier
42 }
44-- | State carried along by a compiler
45--
46data CompilerState = CompilerState
47 { compilerDependencies :: Dependencies
48 }
50-- | The compiler monad
51--
52newtype CompilerM a b = CompilerM
53 { unCompilerM :: ReaderT (CompilerEnvironment a) (State CompilerState) b
54 } deriving (Monad, Functor, Applicative)
56-- | Simplified type for a compiler generating a target (which covers most
57-- cases)
58--
59type Compiler a = CompilerM a (TargetM a a)
61-- | Run a compiler, yielding the resulting target and it's dependencies
62--
63runCompiler :: Compiler a -> Identifier -> (TargetM a a, Dependencies)
64runCompiler compiler identifier = second compilerDependencies $
65 runState (runReaderT (unCompilerM compiler) env) state
66 where
67 env = CompilerEnvironment {compilerIdentifier = identifier}
68 state = CompilerState S.empty
70-- | Require another target. Using this function ensures automatic handling of
71-- dependencies
72--
73require :: Identifier
74 -> Compiler a
75require identifier = do
76 addDependency identifier
77 return $ TargetM $ flip targetDependencyLookup identifier <$> ask
79-- | Construct a target inside a compiler
80--
81target :: TargetM a a -> Compiler a
82target = return
84-- | Construct a target from a string, this string being the content of the
85-- resource.
86--
87targetFromString :: (String -> TargetM a a) -- ^ Function to create the target
88 -> Compiler a -- ^ Resulting compiler
89targetFromString = target . (getResourceString >>=)