summaryrefslogtreecommitdiff
path: root/src/Hakyll/Core/Compiler/Internal.hs
diff options
context:
space:
mode:
authorJasper Van der Jeugt <jaspervdj@gmail.com>2011-03-01 14:50:41 +0100
committerJasper Van der Jeugt <jaspervdj@gmail.com>2011-03-01 14:50:41 +0100
commit90b25105830d6e4b0943ab55f9317bd142533acf (patch)
tree6eefb80a8a84724e70539dd8fa449530f7b17fe0 /src/Hakyll/Core/Compiler/Internal.hs
parent8ef5a3ed0307be5d34a9564d02af3ed494f8e228 (diff)
parent8b727b994d482d593046f9b01a5c40b97c166d62 (diff)
downloadhakyll-90b25105830d6e4b0943ab55f9317bd142533acf.tar.gz
Merge branch 'hakyll3'
Conflicts: hakyll.cabal src/Text/Hakyll/Tags.hs
Diffstat (limited to 'src/Hakyll/Core/Compiler/Internal.hs')
-rw-r--r--src/Hakyll/Core/Compiler/Internal.hs146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/Hakyll/Core/Compiler/Internal.hs b/src/Hakyll/Core/Compiler/Internal.hs
new file mode 100644
index 0000000..53df044
--- /dev/null
+++ b/src/Hakyll/Core/Compiler/Internal.hs
@@ -0,0 +1,146 @@
+-- | Internally used compiler module
+--
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Hakyll.Core.Compiler.Internal
+ ( Dependencies
+ , DependencyEnvironment (..)
+ , CompilerEnvironment (..)
+ , CompilerM (..)
+ , Compiler (..)
+ , runCompilerJob
+ , runCompilerDependencies
+ , fromJob
+ , fromDependencies
+ , fromDependency
+ ) where
+
+import Prelude hiding ((.), id)
+import Control.Applicative (Applicative, pure, (<*>), (<$>))
+import Control.Monad.Reader (ReaderT, Reader, ask, runReaderT, runReader)
+import Control.Monad ((<=<), liftM2)
+import Data.Set (Set)
+import qualified Data.Set as S
+import Control.Category (Category, (.), id)
+import Control.Arrow (Arrow, ArrowChoice, arr, first, left)
+
+import Hakyll.Core.Identifier
+import Hakyll.Core.ResourceProvider
+import Hakyll.Core.Store
+import Hakyll.Core.Routes
+import Hakyll.Core.Logger
+
+-- | A set of dependencies
+--
+type Dependencies = Set Identifier
+
+-- | Environment in which the dependency analyzer runs
+--
+data DependencyEnvironment = DependencyEnvironment
+ { -- | Target identifier
+ dependencyIdentifier :: Identifier
+ , -- | Resource provider
+ dependencyResourceProvider :: ResourceProvider
+ }
+
+-- | Environment in which a compiler runs
+--
+data CompilerEnvironment = CompilerEnvironment
+ { -- | Target identifier
+ compilerIdentifier :: Identifier
+ , -- | Resource provider
+ compilerResourceProvider :: ResourceProvider
+ , -- | Site routes
+ compilerRoutes :: Routes
+ , -- | Compiler store
+ compilerStore :: Store
+ , -- | Flag indicating if the underlying resource was modified
+ compilerResourceModified :: Bool
+ , -- | Logger
+ compilerLogger :: Logger
+ }
+
+-- | The compiler monad
+--
+newtype CompilerM a = CompilerM
+ { unCompilerM :: ReaderT CompilerEnvironment IO a
+ } deriving (Monad, Functor, Applicative)
+
+-- | The compiler arrow
+--
+data Compiler a b = Compiler
+ { compilerDependencies :: Reader DependencyEnvironment Dependencies
+ , compilerJob :: a -> CompilerM b
+ }
+
+instance Functor (Compiler a) where
+ fmap f ~(Compiler d j) = Compiler d $ fmap f . j
+
+instance Applicative (Compiler a) where
+ pure = Compiler (return S.empty) . const . return
+ ~(Compiler d1 f) <*> ~(Compiler d2 j) =
+ Compiler (liftM2 S.union d1 d2) $ \x -> f x <*> j x
+
+instance Category Compiler where
+ id = Compiler (return S.empty) return
+ ~(Compiler d1 j1) . ~(Compiler d2 j2) =
+ Compiler (liftM2 S.union d1 d2) (j1 <=< j2)
+
+instance Arrow Compiler where
+ arr f = Compiler (return S.empty) (return . f)
+ first ~(Compiler d j) = Compiler d $ \(x, y) -> do
+ x' <- j x
+ return (x', y)
+
+instance ArrowChoice Compiler where
+ left ~(Compiler d j) = Compiler d $ \e -> case e of
+ Left l -> Left <$> j l
+ Right r -> Right <$> return r
+
+-- | Run a compiler, yielding the resulting target and it's dependencies
+--
+runCompilerJob :: Compiler () a -- ^ Compiler to run
+ -> Identifier -- ^ Target identifier
+ -> ResourceProvider -- ^ Resource provider
+ -> Routes -- ^ Route
+ -> Store -- ^ Store
+ -> Bool -- ^ Was the resource modified?
+ -> Logger -- ^ Logger
+ -> IO a
+runCompilerJob compiler identifier provider route store modified logger =
+ runReaderT (unCompilerM $ compilerJob compiler ()) env
+ where
+ env = CompilerEnvironment
+ { compilerIdentifier = identifier
+ , compilerResourceProvider = provider
+ , compilerRoutes = route
+ , compilerStore = store
+ , compilerResourceModified = modified
+ , compilerLogger = logger
+ }
+
+runCompilerDependencies :: Compiler () a
+ -> Identifier
+ -> ResourceProvider
+ -> Dependencies
+runCompilerDependencies compiler identifier provider =
+ runReader (compilerDependencies compiler) env
+ where
+ env = DependencyEnvironment
+ { dependencyIdentifier = identifier
+ , dependencyResourceProvider = provider
+ }
+
+fromJob :: (a -> CompilerM b)
+ -> Compiler a b
+fromJob = Compiler (return S.empty)
+
+fromDependencies :: (Identifier -> ResourceProvider -> [Identifier])
+ -> Compiler b b
+fromDependencies collectDeps = flip Compiler return $ do
+ DependencyEnvironment identifier provider <- ask
+ return $ S.fromList $ collectDeps identifier provider
+
+-- | Wait until another compiler has finished before running this compiler
+--
+fromDependency :: Identifier -> Compiler a a
+fromDependency = fromDependencies . const . const . return