on 9939708 help sign in
hakyll/src/Hakyll/Core/Compiler.hs
83 lines 2.5 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 , compileFromString
11 ) where
13import Control.Arrow (second)
14import Control.Applicative (Applicative, (<$>))
15import Control.Monad.State (State, modify, runState)
16import Control.Monad.Reader (ReaderT, ask, runReaderT)
17import Data.Set (Set)
18import qualified Data.Set as S
20import Hakyll.Core.Identifier
21import Hakyll.Core.Target
22import Hakyll.Core.Target.Internal
24-- | A set of dependencies
25--
26type Dependencies = Set Identifier
28-- | Add one dependency
29--
30addDependency :: Identifier -> CompilerM a ()
31addDependency dependency = CompilerM $ modify $ addDependency'
32 where
33 addDependency' x = x
34 { compilerDependencies = S.insert dependency $ compilerDependencies x
35 }
37-- | Environment in which a compiler runs
38--
39data CompilerEnvironment a = CompilerEnvironment
40 { compilerIdentifier :: Identifier -- ^ Target identifier
41 }
43-- | State carried along by a compiler
44--
45data CompilerState = CompilerState
46 { compilerDependencies :: Dependencies
47 }
49-- | The compiler monad
50--
51newtype CompilerM a b = CompilerM
52 { unCompilerM :: ReaderT (CompilerEnvironment a) (State CompilerState) b
53 } deriving (Monad, Functor, Applicative)
55-- | Simplified type for a compiler generating a target (which covers most
56-- cases)
57--
58type Compiler a = CompilerM a (TargetM a a)
60-- | Run a compiler, yielding the resulting target and it's dependencies
61--
62runCompiler :: Compiler a -> Identifier -> (TargetM a a, Dependencies)
63runCompiler compiler identifier = second compilerDependencies $
64 runState (runReaderT (unCompilerM compiler) env) state
65 where
66 env = CompilerEnvironment {compilerIdentifier = identifier}
67 state = CompilerState S.empty
69-- | Require another target. Using this function ensures automatic handling of
70-- dependencies
71--
72require :: Identifier
73 -> Compiler a
74require identifier = do
75 addDependency identifier
76 return $ TargetM $ flip targetDependencyLookup identifier <$> ask
78-- | Construct a target from a string, this string being the content of the
79-- resource.
80--
81compileFromString :: (String -> TargetM a a) -- ^ Function to create the target
82 -> Compiler a -- ^ Resulting compiler
83compileFromString = return . (getResourceString >>=)