{-| This module contains the primitve indentation parsers. In most of the case one would not want to use the functions of this module. -} module Text.ParserCombinators.Parsec.IndentParser.Prim ( -- * Types IndentParser, IndentCharParser, IndentMode(..), IndentState, -- * Geting indentation modes and position. getIndentMode, setIndentMode, getIndentPos, setIndentPos, -- * User state manipulation. getState, setState, -- * Runing and testing runParser, parseTest ) where import Text.ParserCombinators.Parsec hiding (getState, setState, parseTest, runParser) import qualified Text.ParserCombinators.Parsec.Prim as PP import Control.Monad(fmap) import Text.ParserCombinators.Parsec.Pos(initialPos) -- | The mode of the indentation parser. data IndentMode = NoIndent -- ^ Ignore indentation | Block -- ^ In block mode | LineFold -- ^ In line fold mode deriving Eq {-| Indentation awareness is built into indentation parser by using these parser states. To distinguish it from the actual user defined state we call the former the indentation state and the later the user state. -} data IndentState = IndentState { indentMode :: IndentMode, -- the indentation mode. indentPos :: SourcePos -- The position where the current -- indentation started. } {-| An indentation aware parser. -} type IndentParser tok st a = GenParser tok (st, IndentState) a type IndentCharParser st a = IndentParser Char st a -- | Gets the current user state. getState :: IndentParser tok st st -- | Gets the current indentation state. getIndentState :: IndentParser tok st IndentState -- | Gets the current identation mode. getIndentMode :: IndentParser tok st IndentMode -- | Gets the position where the last indentation started. getIndentPos :: IndentParser tok st SourcePos getState = fmap fst getStatePrim getIndentState = fmap snd getStatePrim getIndentMode = fmap indentMode getIndentState getIndentPos = fmap indentPos getIndentState -- | Sets the user state. setState :: st -> IndentParser tok st () -- | Sets the current indentation. setIndentPos :: SourcePos -> IndentParser tok st () -- | Sets the current indentation mode. setIndentMode :: IndentMode -> IndentParser tok st () -- | Sets the indentation state of the parser. setIndentState :: IndentState -> IndentParser tok st () setState st = do indst <- getIndentState setStatePrim (st,indst) setIndentState indst = do st <- getState setStatePrim (st, indst) setIndentPos sp = do indst <- getIndentState setIndentState $ indst {indentPos = sp} setIndentMode indm = do indst <- getIndentState setIndentState $ indst {indentMode = indm} {- $run The most generic way to run an IndentParser. Use @parseTest@ for testing your parser instead. -} runParser :: IndentParser tok st a -- ^ the parser to be run -> st -- ^ the initial state -> IndentMode -- ^ the indentation mode -> SourceName -- ^ the source file name -> [tok] -- ^ the list of tokens -> Either ParseError a -- ^ the result of parsing runParser p st imode sname = runParserPrim p (st, istate) sname where istate = IndentState { indentPos = initialPos sname, indentMode = imode } {-| This is the function analogues to parseTest of the Parsec module. Given an indent parser @p :: IndentParser tok () a@ and a list of tokens it runs the parser and prints the result. -} parseTest :: Show a => IndentParser tok () a -> [tok] -> IO () parseTest p input = case result of Left err -> do putStr "Error"; print err Right a -> do print a where result = runParser p () NoIndent "" input getStatePrim = PP.getState setStatePrim = PP.setState runParserPrim = PP.runParser