From c372fc47da1d29d6613b782d7c8974a2de5b13ff Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Sat, 25 Dec 2010 18:15:44 +0100 Subject: Add Compiler module --- src/Hakyll/Core/Compiler.hs | 80 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/Hakyll/Core/Compiler.hs (limited to 'src/Hakyll/Core/Compiler.hs') 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 -- cgit v1.2.3