module Text.Trifecta.Layout.Monad
( Layout(..)
, runLayout
) where
import Control.Applicative
import Control.Category
import Control.Monad
import Control.Monad.State.Class
import Control.Monad.Trans.State.Strict (StateT(..))
import Control.Monad.Writer.Class
import Control.Monad.Reader.Class
import Control.Monad.Cont.Class
import Control.Monad.Trans.Class
import Prelude hiding ((.), id)
import Text.Trifecta.Diagnostic.Class
import Text.Trifecta.Parser.Class
import Text.Trifecta.Parser.Mark
import Text.Trifecta.Parser.Combinators
import Text.Trifecta.Layout.Prim
import Text.Trifecta.Layout.Class
import Text.Trifecta.Layout.Combinators
import Text.Trifecta.Rope.Delta
newtype Layout m a = Layout { unlayout :: StateT LayoutState m a }
deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadTrans, MonadCont)
runLayout :: Monad m => Layout m a -> LayoutState -> m (a, LayoutState)
runLayout = runStateT . unlayout
instance MonadParser m => MonadParser (Layout m) where
satisfy p = try $ layoutEq Other *> lift (satisfy p)
satisfy8 p = try $ layoutEq Other *> lift (satisfy8 p)
line = lift line
unexpected = lift . unexpected
try = Layout . try . unlayout
labels m s = Layout $ labels (unlayout m) s
skipMany = Layout . skipMany . unlayout
highlightInterval h s e = lift $ highlightInterval h s e
someSpace = try $ (layoutEq WhiteSpace <?> "")
nesting (Layout m) = disableLayout $ Layout (nesting m)
semi = getLayout layoutStack >>= \ stk -> case stk of
(DisabledLayout _:_) -> lift semi
_ -> try (';' <$ layoutEq VirtualSemi <?> "virtual semi-colon")
<|> lift semi
skipping = lift . skipping
position = lift position
slicedWith f (Layout m) = Layout $ slicedWith f m
lookAhead (Layout m) = Layout $ lookAhead m
instance MonadMark d m => MonadMark (LayoutMark d) (Layout m) where
mark = LayoutMark <$> getLayout id <*> lift mark
release (LayoutMark s m) = lift (release m) *> setLayout id s
instance MonadDiagnostic e m => MonadDiagnostic e (Layout m) where
throwDiagnostic = lift . throwDiagnostic
logDiagnostic = lift . logDiagnostic
instance MonadParser m => MonadLayout (Layout m) where
layout = buildLayoutParser (lift whiteSpace)
layoutState f = Layout . StateT $ return . f
buildLayoutParser :: MonadLayout m => m () -> m LayoutToken
buildLayoutParser realWhiteSpace = do
bol <- getLayout layoutBol
m <- position
realWhiteSpace
r <- position
if near m r && not bol
then onside m r
else getLayout layoutStack >>= \stk -> case compare (column r) (depth stk) of
GT -> onside m r
EQ -> return VirtualSemi
LT -> case stk of
(IndentedLayout _:xs) -> VirtualRightBrace <$ setLayout layoutStack xs <* setLayout layoutBol True
_ -> unexpected "layout context"
where
onside m r
| r /= m = pure WhiteSpace
| otherwise = setLayout layoutBol False *> option Other (VirtualRightBrace <$ eof <* trailing)
trailing = getLayout layoutStack >>= \ stk -> case stk of
(IndentedLayout _:xs) -> setLayout layoutStack xs
_ -> empty
depth [] = 0
depth (IndentedLayout r:_) = column r
depth (DisabledLayout _:_) = 1
instance MonadState s m => MonadState s (Layout m) where
get = Layout $ lift get
put = Layout . lift . put
instance MonadReader e m => MonadReader e (Layout m) where
ask = Layout $ lift ask
local f (Layout m) = Layout $ local f m
instance MonadWriter w m => MonadWriter w (Layout m) where
tell = Layout . lift . tell
listen (Layout m) = Layout $ listen m
pass (Layout m) = Layout $ pass m