hakyll/src/Hakyll/Core/Compiler.hs

145 lines
4.3 KiB
Haskell
Raw Normal View History

2010-12-25 17:15:44 +00:00
-- | A Compiler manages targets and dependencies between targets.
--
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Hakyll.Core.Compiler
( Dependencies
, CompilerM
2010-12-29 21:59:38 +00:00
, Compiler (..)
2010-12-25 17:15:44 +00:00
, runCompiler
2010-12-29 21:59:38 +00:00
, getIdentifier
, getResourceString
2010-12-25 17:15:44 +00:00
, require
2010-12-29 21:59:38 +00:00
-- , requireAll
-- , compileFromString
2010-12-25 17:15:44 +00:00
) where
2010-12-29 21:59:38 +00:00
import Prelude hiding ((.), id)
import Control.Arrow (second, (>>>))
2010-12-25 17:15:44 +00:00
import Control.Applicative (Applicative, (<$>))
import Control.Monad.State (State, modify, runState)
import Control.Monad.Reader (ReaderT, ask, runReaderT)
2010-12-29 21:59:38 +00:00
import Control.Monad.Trans (liftIO)
import Control.Monad ((<=<))
2010-12-25 17:15:44 +00:00
import Data.Set (Set)
import qualified Data.Set as S
2010-12-29 21:59:38 +00:00
import Control.Category (Category, (.), id)
import Control.Arrow (Arrow, arr, first)
2010-12-28 10:12:45 +00:00
import Data.Binary (Binary)
2010-12-29 21:59:38 +00:00
import Data.Typeable (Typeable)
2010-12-25 17:15:44 +00:00
import Hakyll.Core.Identifier
2010-12-29 14:33:22 +00:00
import Hakyll.Core.Identifier.Pattern
2010-12-28 10:12:45 +00:00
import Hakyll.Core.CompiledItem
import Hakyll.Core.Writable
2010-12-29 14:33:22 +00:00
import Hakyll.Core.ResourceProvider
2010-12-25 17:15:44 +00:00
-- | A set of dependencies
--
type Dependencies = Set Identifier
2010-12-29 21:59:38 +00:00
-- | A lookup with which we can get dependencies
2010-12-25 17:15:44 +00:00
--
2010-12-29 21:59:38 +00:00
type DependencyLookup = Identifier -> CompiledItem
2010-12-25 17:15:44 +00:00
-- | Environment in which a compiler runs
--
2010-12-28 10:12:45 +00:00
data CompilerEnvironment = CompilerEnvironment
2010-12-29 14:33:22 +00:00
{ compilerIdentifier :: Identifier -- ^ Target identifier
, compilerResourceProvider :: ResourceProvider -- ^ Resource provider
2010-12-29 21:59:38 +00:00
, compilerDependencyLookup :: DependencyLookup -- ^ Dependency lookup
2010-12-25 17:15:44 +00:00
}
-- | The compiler monad
--
2010-12-28 10:12:45 +00:00
newtype CompilerM a = CompilerM
2010-12-29 21:59:38 +00:00
{ unCompilerM :: ReaderT CompilerEnvironment IO a
2010-12-25 17:15:44 +00:00
} deriving (Monad, Functor, Applicative)
2010-12-29 21:59:38 +00:00
-- | The compiler arrow
2010-12-25 17:15:44 +00:00
--
2010-12-29 21:59:38 +00:00
data Compiler a b = Compiler
{ -- TODO: Reader ResourceProvider Dependencies
compilerDependencies :: Dependencies
, compilerJob :: a -> CompilerM b
}
instance Category Compiler where
id = Compiler S.empty return
(Compiler d1 j1) . (Compiler d2 j2) =
Compiler (d1 `S.union` d2) (j1 <=< j2)
instance Arrow Compiler where
arr f = Compiler S.empty (return . f)
first (Compiler d j) = Compiler d $ \(x, y) -> do
x' <- j x
return (x', y)
2010-12-25 17:15:44 +00:00
-- | Run a compiler, yielding the resulting target and it's dependencies
--
2010-12-29 21:59:38 +00:00
runCompiler :: Compiler () a
-> Identifier
-> ResourceProvider
-> DependencyLookup
-> IO a
runCompiler compiler identifier provider lookup' =
runReaderT (unCompilerM $ compilerJob compiler ()) env
2010-12-25 17:15:44 +00:00
where
2010-12-29 14:33:22 +00:00
env = CompilerEnvironment
{ compilerIdentifier = identifier
, compilerResourceProvider = provider
2010-12-29 21:59:38 +00:00
, compilerDependencyLookup = lookup'
2010-12-29 14:33:22 +00:00
}
2010-12-29 21:59:38 +00:00
addDependency :: Identifier
-> Compiler b b
addDependency id' = Compiler (S.singleton id') return
fromCompilerM :: (a -> CompilerM b)
-> Compiler a b
fromCompilerM = Compiler S.empty
getIdentifier :: Compiler () Identifier
getIdentifier = fromCompilerM $ const $ CompilerM $
compilerIdentifier <$> ask
getResourceString :: Compiler () String
getResourceString = getIdentifier >>> getResourceString'
where
getResourceString' = fromCompilerM $ \id' -> CompilerM $ do
provider <- compilerResourceProvider <$> ask
liftIO $ resourceString provider id'
2010-12-25 17:15:44 +00:00
-- | Require another target. Using this function ensures automatic handling of
-- dependencies
--
2010-12-28 10:12:45 +00:00
require :: (Binary a, Typeable a, Writable a)
=> Identifier
2010-12-29 21:59:38 +00:00
-> (a -> b -> c)
-> Compiler b c
require identifier f = addDependency identifier >>> fromCompilerM require'
where
require' x = CompilerM $ do
lookup' <- compilerDependencyLookup <$> ask
return $ f (unCompiledItem $ lookup' identifier) x
2010-12-25 17:15:44 +00:00
2010-12-29 21:59:38 +00:00
{-
2010-12-29 14:33:22 +00:00
-- | Require a number of targets. Using this function ensures automatic handling
-- of dependencies
--
requireAll :: (Binary a, Typeable a, Writable a)
=> Pattern
-> Compiler [a]
requireAll pattern = CompilerM $ do
provider <- compilerResourceProvider <$> ask
r <- unCompilerM $ mapM require $ matches pattern $ resourceList provider
return $ sequence r
2010-12-26 10:57:42 +00:00
-- | Construct a target from a string, this string being the content of the
-- resource.
--
2010-12-28 10:12:45 +00:00
compileFromString :: (String -> TargetM a) -- ^ Function to create the target
-> Compiler a -- ^ Resulting compiler
2010-12-26 12:21:27 +00:00
compileFromString = return . (getResourceString >>=)
2010-12-29 21:59:38 +00:00
-}