prosidyc-0.2.0.0: src/Prosidy/Compile/Run.hs
{-|
Module : Prosidy.Compile.Run
Description : Interpretation of compilation rules.
Copyright : ©2020 James Alexander Feldman-Crough
License : MPL-2.0
Maintainer : alex@fldcr.com
-}
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Prosidy.Compile.Run (run, runM) where
import Lens.Micro
import Prosidy.Compile.Core
import Prosidy.Compile.Error
import Data.Bifunctor ( Bifunctor(..) )
import Data.Functor.Identity ( Identity(..) )
import qualified Prosidy as P
-------------------------------------------------------------------------------
-- | Run a 'Rule' against an input, returning a parse result.
run :: IsError e => RuleT i e Identity a -> i -> Either (ErrorSet e) a
run rule = runIdentity . runM rule
-- | Run a 'RuleT' against an input, returning a contextual parse result.
runM
:: (Applicative context, IsError e)
=> RuleT i e context a
-> i
-> context (Either (ErrorSet e) a)
runM rule = (\(Run x) -> x) . runRun rule
-------------------------------------------------------------------------------
newtype Run error context output = Run
(context (Either (ErrorSet error) output))
deriving Functor
instance (Applicative context, IsError error) => Applicative (Run error context) where
pure = Run . pure . Right
{-# INLINE pure #-}
Run lhsF <*> Run rhsF = Run $ do
lhs <- lhsF
rhs <- rhsF
pure $ either (\es -> Left $ either (es <>) (const es) rhs)
(\fn -> second fn rhs)
lhs
instance (Applicative context, IsError error) => ApError (ErrorSet error) (Run error context) where
liftError = Run . pure . Left
{-# INLINE liftError #-}
mapError f (Run r) = Run $ fmap (first f) r
runRun
:: (Applicative context, IsError e)
=> RuleT i e context a
-> i
-> Run e context a
runRun rule = interpretWith rule interpret
interpret
:: (Applicative context, IsError error)
=> Interpret error context (Run error context)
interpret input = \case
Fail e -> liftError1 e
Lift lifted -> Run . fmap (first singleError) $ lifted input
TestMatch matches ->
groupErrors input $ evalPatterns matches interpret input
Traverse f g rule -> do
fmap g . traverse (runRun rule) $ f input
GetContent rule -> runRun rule $ input ^. P.content
GetProperty k key -> input ^. P.hasProperty key & pure . k
GetSetting k key parse ->
input ^. P.atSetting key & traverse parse & either
(liftError1 . ParseError key)
(pure . k)
GetRequiredSetting key parse -> do
input ^. P.atSetting key & maybe
(liftError1 $ Required key)
(either (liftError1 . ParseError key) pure . parse)
GetSelf k -> pure $ k input