@@ -0,0 +1,80 @@
1+-- | A Compiler manages targets and dependencies between targets.
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+module Hakyll.Core.Compiler
13+import Control.Arrow (second)
14+import Control.Applicative (Applicative, (<$>))
15+import Control.Monad.State (State, modify, runState)
16+import Control.Monad.Reader (ReaderT, ask, runReaderT)
18+import qualified Data.Set as S
20+import Hakyll.Core.Identifier
21+import Hakyll.Core.Target.Internal
23+-- | A set of dependencies
25+type Dependencies = Set Identifier
27+-- | Add one dependency
29+addDependency :: Identifier -> CompilerM a ()
30+addDependency dependency = CompilerM $ modify $ addDependency'
33+ { compilerDependencies = S.insert dependency $ compilerDependencies x
36+-- | Environment in which a compiler runs
38+data CompilerEnvironment a = CompilerEnvironment
39+ { compilerIdentifier :: Identifier -- ^ Target identifier
42+-- | State carried along by a compiler
44+data CompilerState = CompilerState
45+ { compilerDependencies :: Dependencies
48+-- | The compiler monad
50+newtype CompilerM a b = CompilerM
51+ { unCompilerM :: ReaderT (CompilerEnvironment a) (State CompilerState) b
52+ } deriving (Monad, Functor, Applicative)
54+-- | Simplified type for a compiler generating a target (which covers most
57+type Compiler a = CompilerM a (TargetM a a)
59+-- | Run a compiler, yielding the resulting target and it's dependencies
61+runCompiler :: Compiler a -> Identifier -> (TargetM a a, Dependencies)
62+runCompiler compiler identifier = second compilerDependencies $
63+ runState (runReaderT (unCompilerM compiler) env) state
65+ env = CompilerEnvironment {compilerIdentifier = identifier}
66+ state = CompilerState S.empty
68+-- | Require another target. Using this function ensures automatic handling of
73+require identifier = do
74+ addDependency identifier
75+ return $ TargetM $ flip targetDependencyLookup identifier <$> ask
77+-- | Construct a target inside a compiler
79+target :: TargetM a a -> Compiler a