@@ -0,0 +1,80 @@
1+-- | A Compiler manages targets and dependencies between targets.
2+--
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+module Hakyll.Core.Compiler
5+ ( Dependencies
6+ , CompilerM
7+ , Compiler
8+ , runCompiler
9+ , require
10+ , target
11+ ) where
12+
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)
17+import Data.Set (Set)
18+import qualified Data.Set as S
19+
20+import Hakyll.Core.Identifier
21+import Hakyll.Core.Target.Internal
22+
23+-- | A set of dependencies
24+--
25+type Dependencies = Set Identifier
26+
27+-- | Add one dependency
28+--
29+addDependency :: Identifier -> CompilerM a ()
30+addDependency dependency = CompilerM $ modify $ addDependency'
31+ where
32+ addDependency' x = x
33+ { compilerDependencies = S.insert dependency $ compilerDependencies x
34+ }
35+
36+-- | Environment in which a compiler runs
37+--
38+data CompilerEnvironment a = CompilerEnvironment
39+ { compilerIdentifier :: Identifier -- ^ Target identifier
40+ }
41+
42+-- | State carried along by a compiler
43+--
44+data CompilerState = CompilerState
45+ { compilerDependencies :: Dependencies
46+ }
47+
48+-- | The compiler monad
49+--
50+newtype CompilerM a b = CompilerM
51+ { unCompilerM :: ReaderT (CompilerEnvironment a) (State CompilerState) b
52+ } deriving (Monad, Functor, Applicative)
53+
54+-- | Simplified type for a compiler generating a target (which covers most
55+-- cases)
56+--
57+type Compiler a = CompilerM a (TargetM a a)
58+
59+-- | Run a compiler, yielding the resulting target and it's dependencies
60+--
61+runCompiler :: Compiler a -> Identifier -> (TargetM a a, Dependencies)
62+runCompiler compiler identifier = second compilerDependencies $
63+ runState (runReaderT (unCompilerM compiler) env) state
64+ where
65+ env = CompilerEnvironment {compilerIdentifier = identifier}
66+ state = CompilerState S.empty
67+
68+-- | Require another target. Using this function ensures automatic handling of
69+-- dependencies
70+--
71+require :: Identifier
72+ -> Compiler a
73+require identifier = do
74+ addDependency identifier
75+ return $ TargetM $ flip targetDependencyLookup identifier <$> ask
76+
77+-- | Construct a target inside a compiler
78+--
79+target :: TargetM a a -> Compiler a
80+target = return