{-# LANGUAGE OverloadedStrings #-} module Data.Text.Interp.Interpolate where import Control.Monad (foldM) import Control.Monad.Except import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NE import qualified Data.Map.Strict as M import Data.Text (Text, append) import Data.Text.Interp.Get import Data.Text.Interp.Types -- | Record holding intermediary interpolation state data IState = IState { acc :: Text -- ^ interpolated text so far , bm :: BindingMap -- ^ mapping of bound variables } newIState :: IState newIState = IState "" M.empty -- | Build interpolated text out of a `Data.Text.Interp.Types.Subst` mapping and -- a list of segments to interpolate interp :: Subst -- ^ mapping to get substitutions out of -> NonEmpty IText -- ^ lits of segments to interpolate -> I Text -- ^ final interpolation interp s its = acc <$> foldM (interp' s) newIState its -- | Interpolate a single segment interp' :: Subst -- ^ mapping -> IState -- ^ intermediary state -> IText -- ^ segment to interpolate -> I IState -- ^ updated state, after the segment's been interpolated interp' _ (IState a m) (RawText t) = return $ IState (a `append` t) m interp' s (IState a m) (ToInterpolate Nothing p) = do res <- get s p m case res of (SubstM _) -> throwError "too few keys" (SubstL _) -> throwError "too few keys" (SubstV x) -> return $ IState (a `append` x) m interp' s (IState a m) (ToInterpolate (Just (Binding n bp)) p) = do toBind <- get s (NE.toList bp) m res <- get toBind p m case res of (SubstM _) -> throwError "too few keys" (SubstL _) -> throwError "too few keys" (SubstV x) -> return $ IState (a `append` x) $ M.insert n toBind m