module Text.Parsec.Indent (
IndentParserT, block, lineFold,
manyLine, runIndent
) where
import Text.Parsec
import Text.Parsec.Pos
import Control.Monad.State
import Control.Concatenative
type IndentParserT s u m a = ParsecT s u (StateT SourcePos m) a
block :: (Stream s (StateT SourcePos m) Char, Monad m) => IndentParserT s u m a -> IndentParserT s u m [a]
block p = do
a <- setStart
r <- many (checkIndent >> p)
put a
return r
lineFold :: (Stream s (StateT SourcePos m) Char, Monad m) => IndentParserT s u m a -> IndentParserT s u m [a]
lineFold p = do
a <- setStart
r <- blockOrNewLine p
put a
return r
blockOrNewLine :: (Stream s (StateT SourcePos m) Char, Monad m) => IndentParserT s u m a -> IndentParserT s u m [a]
blockOrNewLine p = do
a <- p
s <- get
pos <- getPosition
liftM (a:) $ if biAp sourceLine (==) pos s then blockOrNewLine p else liftM concat (block (manyLine p))
manyLine :: (Stream s (StateT SourcePos m) Char, Monad m) => IndentParserT s u m a -> IndentParserT s u m [a]
manyLine p = setStart >> f where
f = do
s <- get
pos <- getPosition
if biAp sourceLine (==) pos s then liftM2 (:) p f else many (char ' ') >> return []
setStart :: (Stream s (StateT SourcePos m) Char, Monad m) => IndentParserT s u m SourcePos
setStart = do
a <- get
p <- getPosition
(put p)
return a
checkIndent :: (Stream s (StateT SourcePos m) Char, Monad m) => IndentParserT s u m ()
checkIndent = do
s <- get
p <- getPosition
if biAp sourceColumn (==) p s then return () else mzero
runIndent :: Monad m => SourceName -> StateT SourcePos m a -> m a
runIndent s = flip evalStateT (initialPos s)