module Text.Parsec.Indent (block, lineFold, 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 <- many1 (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
s <- get
pos <- getPosition
liftM2 (:) p $ 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 = do
s <- liftM ((+1) . sourceLine) get
pos <- liftM sourceLine getPosition
if pos == s then many (char ' ') >> return [] else liftM2 (:) p (manyLine p)
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)