diff options
-rw-r--r-- | src/Hakyll/Core/Compiler.hs | 80 | ||||
-rw-r--r-- | src/Hakyll/Core/Target/Internal.hs | 1 |
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 |