module Language.Egison.Pretty.Pattern.Print
( Print
, askMode
, askContext
, operatorOf
, withContext
, runPrint
)
where
import qualified Data.Map as Map
( Map
, empty
, lookup
, insert
)
import Control.Monad.Except ( MonadError(..) )
import Control.Monad.Reader ( ReaderT
, MonadReader(..)
, runReaderT
)
import Language.Egison.Pretty.Pattern.Error
( Error(UnknownInfixOperator) )
import Language.Egison.Pretty.Pattern.Context
( Context(World) )
import Language.Egison.Pretty.Pattern.PrintMode
( PrintMode(..)
, PrintFixity(..)
, Fixity(..)
)
import Language.Egison.Pretty.Pattern.Operator
( Operator(..) )
type OperatorTable n = Map.Map n Operator
data Env n v e
= Env { mode :: PrintMode n v e
, table :: OperatorTable n
, context :: Context
}
buildOperatorTable :: Ord n => [PrintFixity n] -> OperatorTable n
buildOperatorTable = foldr go Map.empty
where
go fixity@PrintFixity { fixity = Fixity { symbol } } =
Map.insert symbol (toOperator fixity)
toOperator PrintFixity { fixity = Fixity { precedence, associativity }, printed }
= InfixOp { precedence, associativity, symbol = printed }
initialEnv :: Ord n => PrintMode n v e -> Env n v e
initialEnv mode@PrintMode { fixities } =
Env { mode, table = buildOperatorTable fixities, context = World }
newtype Print n v e a = Print { unParse :: ReaderT (Env n v e) (Either (Error n)) a }
deriving newtype (Functor, Applicative, Monad)
deriving newtype (MonadReader (Env n v e))
deriving newtype (MonadError (Error n))
askMode :: Print n v e (PrintMode n v e)
askMode = do
Env { mode } <- ask
pure mode
askContext :: Print n v e Context
askContext = do
Env { context } <- ask
pure context
withContext :: Context -> Print n v e a -> Print n v e a
withContext = local . updateContext
where updateContext context env = env { context }
runPrint
:: (Ord n, MonadError (Error n) m) => Print n v e a -> PrintMode n v e -> m a
runPrint p mode = case runReaderT (unParse p) (initialEnv mode) of
Left err -> throwError err
Right x -> pure x
operatorOf :: Ord n => n -> Print n v e Operator
operatorOf n = do
Env { table } <- ask
case Map.lookup n table of
Just op -> pure op
Nothing -> throwError $ UnknownInfixOperator n