summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Hakyll/Core/Compiler.hs80
-rw-r--r--src/Hakyll/Core/Target/Internal.hs1
2 files changed, 81 insertions, 0 deletions
diff --git a/src/Hakyll/Core/Compiler.hs b/src/Hakyll/Core/Compiler.hs
new file mode 100644
index 0000000..42598f6
--- /dev/null
+++ b/src/Hakyll/Core/Compiler.hs
@@ -0,0 +1,80 @@
+-- | A Compiler manages targets and dependencies between targets.
+--
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Hakyll.Core.Compiler
+ ( Dependencies
+ , CompilerM
+ , Compiler
+ , runCompiler
+ , require
+ , target
+ ) where
+
+import Control.Arrow (second)
+import Control.Applicative (Applicative, (<$>))
+import Control.Monad.State (State, modify, runState)
+import Control.Monad.Reader (ReaderT, ask, runReaderT)
+import Data.Set (Set)
+import qualified Data.Set as S
+
+import Hakyll.Core.Identifier
+import Hakyll.Core.Target.Internal
+
+-- | A set of dependencies
+--
+type Dependencies = Set Identifier
+
+-- | Add one dependency
+--
+addDependency :: Identifier -> CompilerM a ()
+addDependency dependency = CompilerM $ modify $ addDependency'
+ where
+ addDependency' x = x
+ { compilerDependencies = S.insert dependency $ compilerDependencies x
+ }
+
+-- | Environment in which a compiler runs
+--
+data CompilerEnvironment a = CompilerEnvironment
+ { compilerIdentifier :: Identifier -- ^ Target identifier
+ }
+
+-- | State carried along by a compiler
+--
+data CompilerState = CompilerState
+ { compilerDependencies :: Dependencies
+ }
+
+-- | The compiler monad
+--
+newtype CompilerM a b = CompilerM
+ { unCompilerM :: ReaderT (CompilerEnvironment a) (State CompilerState) b
+ } deriving (Monad, Functor, Applicative)
+
+-- | Simplified type for a compiler generating a target (which covers most
+-- cases)
+--
+type Compiler a = CompilerM a (TargetM a a)
+
+-- | Run a compiler, yielding the resulting target and it's dependencies
+--
+runCompiler :: Compiler a -> Identifier -> (TargetM a a, Dependencies)
+runCompiler compiler identifier = second compilerDependencies $
+ runState (runReaderT (unCompilerM compiler) env) state
+ where
+ env = CompilerEnvironment {compilerIdentifier = identifier}
+ state = CompilerState S.empty
+
+-- | Require another target. Using this function ensures automatic handling of
+-- dependencies
+--
+require :: Identifier
+ -> Compiler a
+require identifier = do
+ addDependency identifier
+ return $ TargetM $ flip targetDependencyLookup identifier <$> ask
+
+-- | Construct a target inside a compiler
+--
+target :: TargetM a a -> Compiler a
+target = return
diff --git a/src/Hakyll/Core/Target/Internal.hs b/src/Hakyll/Core/Target/Internal.hs
index a58f736..96e3087 100644
--- a/src/Hakyll/Core/Target/Internal.hs
+++ b/src/Hakyll/Core/Target/Internal.hs
@@ -3,6 +3,7 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Hakyll.Core.Target.Internal
( DependencyLookup
+ , TargetEnvironment (..)
, TargetM (..)
, Target
, runTarget