2008-01-13 20:53:15 +03:00
|
|
|
|
-- |
|
2015-08-01 19:24:45 +03:00
|
|
|
|
-- Module : Text.Megaparsec.Prim
|
|
|
|
|
-- Copyright : © 2015 Megaparsec contributors
|
2015-07-30 19:20:37 +03:00
|
|
|
|
-- © 2007 Paolo Martini
|
|
|
|
|
-- © 1999–2001 Daan Leijen
|
2015-07-28 16:32:19 +03:00
|
|
|
|
-- License : BSD3
|
|
|
|
|
--
|
|
|
|
|
-- Maintainer : Mark Karpov <markkarpov@opmbx.org>
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- Stability : experimental
|
2008-01-13 20:53:15 +03:00
|
|
|
|
-- Portability : portable
|
2015-07-28 16:32:19 +03:00
|
|
|
|
--
|
2008-01-13 20:53:15 +03:00
|
|
|
|
-- The primitive parser combinators.
|
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
{-# OPTIONS_HADDOCK not-home #-}
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-08-01 19:24:45 +03:00
|
|
|
|
module Text.Megaparsec.Prim
|
2015-08-17 18:58:59 +03:00
|
|
|
|
( -- * Used data-types
|
|
|
|
|
State (..)
|
2015-08-12 20:51:06 +03:00
|
|
|
|
, Stream (..)
|
|
|
|
|
, Consumed (..)
|
|
|
|
|
, Reply (..)
|
|
|
|
|
, ParsecT
|
|
|
|
|
, Parsec
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- * Running parser
|
2015-08-12 20:51:06 +03:00
|
|
|
|
, runParser
|
2015-08-17 18:58:59 +03:00
|
|
|
|
, runParserT
|
2015-08-12 20:51:06 +03:00
|
|
|
|
, parse
|
|
|
|
|
, parseMaybe
|
|
|
|
|
, parseTest
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- * Primitive combinators
|
|
|
|
|
, unexpected
|
|
|
|
|
, (<?>)
|
|
|
|
|
, label
|
2015-08-19 22:08:20 +03:00
|
|
|
|
, hidden
|
2015-08-12 20:51:06 +03:00
|
|
|
|
, try
|
|
|
|
|
, lookAhead
|
2015-08-17 18:58:59 +03:00
|
|
|
|
, notFollowedBy
|
|
|
|
|
, eof
|
2015-08-12 20:51:06 +03:00
|
|
|
|
, token
|
|
|
|
|
, tokens
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- * Parser state combinators
|
2015-08-12 20:51:06 +03:00
|
|
|
|
, getPosition
|
|
|
|
|
, getInput
|
|
|
|
|
, setPosition
|
|
|
|
|
, setInput
|
|
|
|
|
, getParserState
|
|
|
|
|
, setParserState
|
|
|
|
|
, updateParserState
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- * User state combinators
|
2015-08-12 20:51:06 +03:00
|
|
|
|
, getState
|
|
|
|
|
, putState
|
|
|
|
|
, modifyState )
|
2015-07-28 16:32:19 +03:00
|
|
|
|
where
|
2014-04-09 23:01:24 +04:00
|
|
|
|
|
2015-08-11 05:54:33 +03:00
|
|
|
|
import Data.Bool (bool)
|
2015-08-17 18:58:59 +03:00
|
|
|
|
import Data.Monoid
|
2014-04-09 23:01:24 +04:00
|
|
|
|
|
2015-07-28 16:32:19 +03:00
|
|
|
|
import Control.Monad
|
2015-08-17 18:58:59 +03:00
|
|
|
|
import Control.Monad.Cont.Class
|
|
|
|
|
import Control.Monad.Error.Class
|
2008-01-13 20:53:15 +03:00
|
|
|
|
import Control.Monad.Identity
|
2008-02-05 08:45:50 +03:00
|
|
|
|
import Control.Monad.Reader.Class
|
2015-07-30 18:45:06 +03:00
|
|
|
|
import Control.Monad.State.Class hiding (state)
|
2015-08-17 18:58:59 +03:00
|
|
|
|
import Control.Monad.Trans
|
2015-08-01 17:39:20 +03:00
|
|
|
|
import qualified Control.Applicative as A
|
2015-07-28 16:32:19 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
import qualified Data.ByteString.Char8 as B
|
|
|
|
|
import qualified Data.ByteString.Lazy.Char8 as BL
|
|
|
|
|
|
|
|
|
|
import qualified Data.Text as T
|
|
|
|
|
import qualified Data.Text.Lazy as TL
|
|
|
|
|
|
2015-08-01 19:24:45 +03:00
|
|
|
|
import Text.Megaparsec.Error
|
2015-08-06 13:37:08 +03:00
|
|
|
|
import Text.Megaparsec.Pos
|
|
|
|
|
import Text.Megaparsec.ShowToken
|
2008-01-20 01:06:33 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- | This is Megaparsec state, this is parametrized over stream type @s@, and
|
2015-07-30 21:36:54 +03:00
|
|
|
|
-- user state @u@.
|
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
data State s u = State
|
2015-08-12 20:51:06 +03:00
|
|
|
|
{ stateInput :: s
|
|
|
|
|
, statePos :: !SourcePos
|
|
|
|
|
, stateUser :: !u }
|
2008-01-20 01:06:33 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- | An instance of @Stream s m t@ has stream type @s@, underlying monad @m@
|
|
|
|
|
-- and token type @t@ determined by the stream.
|
2008-01-22 04:37:52 +03:00
|
|
|
|
--
|
2015-08-12 15:41:22 +03:00
|
|
|
|
-- Some rough guidelines for a “correct” instance of Stream:
|
2015-07-30 18:45:06 +03:00
|
|
|
|
--
|
2015-08-12 15:41:22 +03:00
|
|
|
|
-- * @unfoldM uncons@ gives the @[t]@ corresponding to the stream.
|
|
|
|
|
-- * A @Stream@ instance is responsible for maintaining the “position
|
|
|
|
|
-- within the stream” in the stream state @s@. This is trivial unless
|
|
|
|
|
-- you are using the monad in a non-trivial way.
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-08-06 13:37:08 +03:00
|
|
|
|
class (Monad m, ShowToken t) => Stream s m t | s -> t where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
uncons :: s -> m (Maybe (t, s))
|
2009-03-02 03:20:00 +03:00
|
|
|
|
|
2015-08-06 13:37:08 +03:00
|
|
|
|
instance (Monad m, ShowToken t) => Stream [t] m t where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
uncons [] = return Nothing
|
|
|
|
|
uncons (t:ts) = return $ Just (t, ts)
|
|
|
|
|
{-# INLINE uncons #-}
|
2009-03-02 03:20:00 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
instance Monad m => Stream B.ByteString m Char where
|
|
|
|
|
uncons = return . B.uncons
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
instance Monad m => Stream BL.ByteString m Char where
|
|
|
|
|
uncons = return . BL.uncons
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
instance Monad m => Stream T.Text m Char where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
uncons = return . T.uncons
|
|
|
|
|
{-# INLINE uncons #-}
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
instance Monad m => Stream TL.Text m Char where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
uncons = return . TL.uncons
|
|
|
|
|
{-# INLINE uncons #-}
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 21:36:54 +03:00
|
|
|
|
-- | This data structure represents an aspect of result of parser's
|
|
|
|
|
-- work. The two constructors have the following meaning:
|
|
|
|
|
--
|
|
|
|
|
-- * @Cosumed@ is a wrapper for result when some part of input stream
|
2015-08-12 15:41:22 +03:00
|
|
|
|
-- was consumed.
|
2015-07-30 21:36:54 +03:00
|
|
|
|
-- * @Empty@ is a wrapper for result when input stream is empty.
|
|
|
|
|
--
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- See also: 'Reply'.
|
2015-07-30 21:36:54 +03:00
|
|
|
|
|
2015-08-12 20:51:06 +03:00
|
|
|
|
data Consumed a = Consumed a | Empty !a
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 21:36:54 +03:00
|
|
|
|
-- | This data structure represents an aspect of result of parser's
|
|
|
|
|
-- work. The two constructors have the following meaning:
|
|
|
|
|
--
|
|
|
|
|
-- * @Ok@ for successfully run parser.
|
|
|
|
|
-- * @Error@ for failed parser.
|
|
|
|
|
--
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- See also 'Consumed'.
|
2015-07-30 21:36:54 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
data Reply s u a = Ok a !(State s u) | Error ParseError
|
|
|
|
|
|
|
|
|
|
-- | 'Hints' represent collection of strings to be included into 'ParserError'
|
|
|
|
|
-- as “expected” messages when a parser fails without consuming input right
|
|
|
|
|
-- after successful parser that produced the hints.
|
|
|
|
|
--
|
|
|
|
|
-- For example, without hints you could get:
|
|
|
|
|
--
|
|
|
|
|
-- >>> parseTest (many (char 'r') <* eof) "ra"
|
|
|
|
|
-- parse error at line 1, column 2:
|
|
|
|
|
-- unexpected 'a'
|
|
|
|
|
-- expecting end of input
|
|
|
|
|
--
|
|
|
|
|
-- we're getting better error messages with help of hints:
|
|
|
|
|
--
|
|
|
|
|
-- >>> parseTest (many (char 'r') <* eof) "ra"
|
|
|
|
|
-- parse error at line 1, column 2:
|
|
|
|
|
-- unexpected 'a'
|
|
|
|
|
-- expecting 'r' or end of input
|
|
|
|
|
|
2015-08-19 20:42:02 +03:00
|
|
|
|
newtype Hints = Hints [[String]] deriving Monoid
|
2015-08-17 18:58:59 +03:00
|
|
|
|
|
|
|
|
|
-- | Convert 'ParseError' record into 'Hints'.
|
|
|
|
|
|
|
|
|
|
toHints :: ParseError -> Hints
|
|
|
|
|
toHints err = Hints [messageString <$> msgs]
|
|
|
|
|
where msgs = filter ((== 1) . fromEnum) $ errorMessages err
|
|
|
|
|
|
|
|
|
|
-- | @withHints hs c@ makes “error” continuation @c@ use given hints @hs@.
|
|
|
|
|
|
|
|
|
|
withHints :: Hints -> (ParseError -> m b) -> ParseError -> m b
|
|
|
|
|
withHints (Hints xs) c = c . addHints
|
|
|
|
|
where addHints err = foldr addErrorMessage err (Expected <$> concat xs)
|
|
|
|
|
|
|
|
|
|
-- | @accHints hs c@ results in “OK” continuation that will add given hints
|
|
|
|
|
-- @hs@ to third argument of original continuation @c@.
|
|
|
|
|
|
|
|
|
|
accHints :: Hints -> (a -> State s u -> Hints -> m b) ->
|
|
|
|
|
a -> State s u -> Hints -> m b
|
|
|
|
|
accHints hs1 c x s hs2 = c x s (hs1 <> hs2)
|
|
|
|
|
|
|
|
|
|
-- | Replace most recent group of hints (if any) with given string. Used in
|
|
|
|
|
-- 'label' combinator.
|
|
|
|
|
|
|
|
|
|
refreshLastHint :: Hints -> String -> Hints
|
|
|
|
|
refreshLastHint (Hints []) _ = Hints []
|
|
|
|
|
refreshLastHint (Hints (_:xs)) l = Hints ([l]:xs)
|
|
|
|
|
|
|
|
|
|
-- If you're reading this, you may be interested in how Megaparsec works on
|
|
|
|
|
-- lower level. That's quite simple. 'ParsecT' is a wrapper around function
|
|
|
|
|
-- that takes five arguments:
|
|
|
|
|
--
|
|
|
|
|
-- * State. It includes input stream, position in input stream and
|
|
|
|
|
-- user's backtracking state.
|
|
|
|
|
--
|
|
|
|
|
-- * “Consumed-OK” continuation (cok). This is just a function that
|
|
|
|
|
-- takes three arguments: result of parsing, state after parsing, and
|
|
|
|
|
-- hints (see their description above). This continuation is called when
|
|
|
|
|
-- something has been consumed during parsing and result is OK (no error
|
|
|
|
|
-- occurred).
|
|
|
|
|
--
|
|
|
|
|
-- * “Consumed-error” continuation (cerr). This function is called when
|
|
|
|
|
-- some part of input stream has been consumed and parsing resulted in
|
|
|
|
|
-- an error. When error happens, parsing stops and we're only interested
|
|
|
|
|
-- in error message, so this continuation takes 'ParseError' as its only
|
|
|
|
|
-- argument.
|
|
|
|
|
--
|
|
|
|
|
-- * “Empty-OK” continuation (eok). The function takes the same
|
|
|
|
|
-- arguments as “consumed-OK” continuation. “Empty-OK” is called when no
|
|
|
|
|
-- input has been consumed and no error occurred.
|
|
|
|
|
--
|
|
|
|
|
-- * “Empty-error” continuation (eerr). The function is called when no
|
|
|
|
|
-- input has been consumed, but nonetheless parsing resulted in an
|
|
|
|
|
-- error. Just like “consumed-error”, the continuation take single
|
|
|
|
|
-- argument — 'ParseError' record.
|
|
|
|
|
--
|
|
|
|
|
-- You call specific continuation when you want to proceed in that specific
|
|
|
|
|
-- branch of control flow.
|
|
|
|
|
|
|
|
|
|
-- | @Parsec@ is non-transformer variant of more general @ParsecT@
|
|
|
|
|
-- monad-transformer.
|
|
|
|
|
|
|
|
|
|
type Parsec s u = ParsecT s u Identity
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
|
|
|
|
-- | @ParsecT s u m a@ is a parser with stream type @s@, user state type @u@,
|
|
|
|
|
-- underlying monad @m@ and return type @a@. Parsec is strict in the user
|
|
|
|
|
-- state. If this is undesirable, simply use a data type like @data Box a =
|
|
|
|
|
-- Box a@ and the state type @Box YourStateType@ to add a level of
|
|
|
|
|
-- indirection.
|
|
|
|
|
|
|
|
|
|
newtype ParsecT s u m a = ParsecT
|
2015-08-12 20:51:06 +03:00
|
|
|
|
{ unParser :: forall b . State s u
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-> (a -> State s u -> Hints -> m b) -- consumed-OK
|
|
|
|
|
-> (ParseError -> m b) -- consumed-error
|
|
|
|
|
-> (a -> State s u -> Hints -> m b) -- empty-OK
|
|
|
|
|
-> (ParseError -> m b) -- empty-error
|
|
|
|
|
-> m b }
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
instance Functor (ParsecT s u m) where
|
2015-08-17 18:58:59 +03:00
|
|
|
|
fmap = parsecMap
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
parsecMap :: (a -> b) -> ParsecT s u m a -> ParsecT s u m b
|
2015-07-30 18:45:06 +03:00
|
|
|
|
parsecMap f p = ParsecT $ \s cok cerr eok eerr ->
|
2015-08-12 20:51:06 +03:00
|
|
|
|
unParser p s (cok . f) cerr (eok . f) eerr
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-28 16:32:19 +03:00
|
|
|
|
instance A.Applicative (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
pure = return
|
|
|
|
|
(<*>) = ap
|
|
|
|
|
(*>) = (>>)
|
|
|
|
|
p1 <* p2 = do { x1 <- p1 ; void p2 ; return x1 }
|
2008-01-20 01:06:33 +03:00
|
|
|
|
|
2015-07-28 16:32:19 +03:00
|
|
|
|
instance A.Alternative (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
empty = mzero
|
|
|
|
|
(<|>) = mplus
|
2015-08-17 18:58:59 +03:00
|
|
|
|
many p = reverse <$> manyAccum p
|
|
|
|
|
|
|
|
|
|
manyAccum :: ParsecT s u m a -> ParsecT s u m [a]
|
|
|
|
|
manyAccum p = ParsecT $ \s cok cerr eok _ ->
|
|
|
|
|
let errToHints c err = c (toHints err)
|
|
|
|
|
walk xs x s' _ =
|
|
|
|
|
unParser p s'
|
|
|
|
|
(seq xs $ walk $ x:xs) -- consumed-OK
|
|
|
|
|
cerr -- consumed-error
|
|
|
|
|
manyErr -- empty-OK
|
|
|
|
|
(errToHints $ cok (x:xs) s') -- empty-error
|
|
|
|
|
in unParser p s (walk []) cerr manyErr (errToHints $ eok [] s)
|
|
|
|
|
|
|
|
|
|
manyErr :: a
|
|
|
|
|
manyErr = error
|
|
|
|
|
"Text.Megaparsec.Prim.many: combinator 'many' is applied to a parser \
|
|
|
|
|
\that accepts an empty string."
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
instance Monad (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
return = parserReturn
|
|
|
|
|
(>>=) = parserBind
|
|
|
|
|
fail = parserFail
|
2008-02-05 08:45:50 +03:00
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
parserReturn :: a -> ParsecT s u m a
|
2015-08-17 18:58:59 +03:00
|
|
|
|
parserReturn x = ParsecT $ \s _ _ eok _ -> eok x s mempty
|
2009-03-02 03:20:00 +03:00
|
|
|
|
|
|
|
|
|
parserBind :: ParsecT s u m a -> (a -> ParsecT s u m b) -> ParsecT s u m b
|
|
|
|
|
{-# INLINE parserBind #-}
|
2015-07-30 18:45:06 +03:00
|
|
|
|
parserBind m k = ParsecT $ \s cok cerr eok eerr ->
|
2015-08-19 20:44:28 +03:00
|
|
|
|
let mcok x s' hs = unParser (k x) s' cok cerr
|
|
|
|
|
(accHints hs cok) (withHints hs cerr)
|
2015-08-17 18:58:59 +03:00
|
|
|
|
meok x s' hs = unParser (k x) s' cok cerr
|
|
|
|
|
(accHints hs eok) (withHints hs eerr)
|
|
|
|
|
in unParser m s mcok cerr meok eerr
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
parserFail :: String -> ParsecT s u m a
|
|
|
|
|
parserFail msg = ParsecT $ \s _ _ _ eerr ->
|
2015-08-12 20:51:06 +03:00
|
|
|
|
eerr $ newErrorMessage (Message msg) (statePos s)
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-08-03 21:01:38 +03:00
|
|
|
|
-- | Low-level unpacking of the ParsecT type. To actually run parser see
|
|
|
|
|
-- 'runParserT' and 'runParser'.
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
runParsecT :: Monad m =>
|
|
|
|
|
ParsecT s u m a -> State s u -> m (Consumed (m (Reply s u a)))
|
|
|
|
|
runParsecT p s = unParser p s cok cerr eok eerr
|
2015-08-17 18:58:59 +03:00
|
|
|
|
where cok a s' _ = return . Consumed . return $ Ok a s'
|
|
|
|
|
cerr err = return . Consumed . return $ Error err
|
|
|
|
|
eok a s' _ = return . Empty . return $ Ok a s'
|
|
|
|
|
eerr err = return . Empty . return $ Error err
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
|
|
|
|
-- | Low-level creation of the ParsecT type. You really shouldn't have to do
|
|
|
|
|
-- this.
|
|
|
|
|
|
|
|
|
|
mkPT :: Monad m =>
|
|
|
|
|
(State s u -> m (Consumed (m (Reply s u a)))) -> ParsecT s u m a
|
|
|
|
|
mkPT k = ParsecT $ \s cok cerr eok eerr -> do
|
2015-08-12 20:51:06 +03:00
|
|
|
|
cons <- k s
|
|
|
|
|
case cons of
|
|
|
|
|
Consumed mrep -> do
|
|
|
|
|
rep <- mrep
|
|
|
|
|
case rep of
|
2015-08-17 18:58:59 +03:00
|
|
|
|
Ok x s' -> cok x s' mempty
|
|
|
|
|
Error err -> cerr err
|
2015-08-12 20:51:06 +03:00
|
|
|
|
Empty mrep -> do
|
|
|
|
|
rep <- mrep
|
|
|
|
|
case rep of
|
2015-08-17 18:58:59 +03:00
|
|
|
|
Ok x s' -> eok x s' mempty
|
|
|
|
|
Error err -> eerr err
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
|
|
|
|
instance MonadIO m => MonadIO (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
liftIO = lift . liftIO
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
|
|
|
|
instance MonadReader r m => MonadReader r (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
ask = lift ask
|
|
|
|
|
local f p = mkPT $ \s -> local f (runParsecT p s)
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
|
|
|
|
instance MonadState s m => MonadState s (ParsecT s' u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
get = lift get
|
|
|
|
|
put = lift . put
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
|
|
|
|
instance MonadCont m => MonadCont (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
callCC f = mkPT $ \s ->
|
|
|
|
|
callCC $ \c ->
|
|
|
|
|
runParsecT (f (\a -> mkPT $ \s' -> c (pack s' a))) s
|
2015-08-17 18:58:59 +03:00
|
|
|
|
where pack s a = Empty $ return (Ok a s)
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
|
|
|
|
instance MonadError e m => MonadError e (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
throwError = lift . throwError
|
|
|
|
|
p `catchError` h = mkPT $ \s ->
|
|
|
|
|
runParsecT p s `catchError` \e ->
|
|
|
|
|
runParsecT (h e) s
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
instance MonadPlus (ParsecT s u m) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
mzero = parserZero
|
|
|
|
|
mplus = parserPlus
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
parserZero :: ParsecT s u m a
|
2015-08-17 18:58:59 +03:00
|
|
|
|
parserZero = ParsecT $ \(State _ pos _) _ _ _ eerr ->
|
|
|
|
|
eerr $ newErrorUnknown pos
|
2009-03-02 03:20:00 +03:00
|
|
|
|
|
|
|
|
|
parserPlus :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
|
|
|
|
|
{-# INLINE parserPlus #-}
|
2015-08-12 20:51:06 +03:00
|
|
|
|
parserPlus m n = ParsecT $ \s cok cerr eok eerr ->
|
|
|
|
|
let meerr err =
|
2015-08-17 18:58:59 +03:00
|
|
|
|
let ncerr err' = cerr (mergeError err' err)
|
|
|
|
|
neok x s' hs = eok x s' (hs <> toHints err)
|
|
|
|
|
neerr err' = eerr (mergeError err' err)
|
|
|
|
|
in unParser n s cok ncerr neok neerr
|
2015-08-12 20:51:06 +03:00
|
|
|
|
in unParser m s cok cerr eok meerr
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
|
|
|
|
instance MonadTrans (ParsecT s u) where
|
2015-08-12 20:51:06 +03:00
|
|
|
|
lift amb = ParsecT $ \s _ _ eok _ -> do
|
|
|
|
|
a <- amb
|
2015-08-17 18:58:59 +03:00
|
|
|
|
eok a s mempty
|
2015-07-30 21:36:54 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- Running a parser
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- | The most general way to run a parser over the identity monad.
|
|
|
|
|
-- @runParser p state filePath input@ runs parser @p@ on the input list of
|
|
|
|
|
-- tokens @input@, obtained from source @filePath@ with the initial user
|
|
|
|
|
-- state @st@. The @filePath@ is only used in error messages and may be the
|
|
|
|
|
-- empty string. Returns either a 'ParseError' ('Left') or a value of type
|
|
|
|
|
-- @a@ ('Right').
|
2008-01-22 04:37:52 +03:00
|
|
|
|
--
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- > parseFromFile p fname = runParser p () fname <$> readFile fname
|
2008-03-06 04:17:54 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
runParser :: Stream s Identity t =>
|
|
|
|
|
Parsec s u a -> u -> SourceName -> s -> Either ParseError a
|
|
|
|
|
runParser p u name s = runIdentity $ runParserT p u name s
|
2014-04-09 23:01:24 +04:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- | The most general way to run a parser. @runParserT p state filePath
|
|
|
|
|
-- input@ runs parser @p@ on the input list of tokens @input@, obtained from
|
|
|
|
|
-- source @filePath@ with the initial user state @st@. The @filePath@ is
|
|
|
|
|
-- only used in error messages and may be the empty string. Returns a
|
|
|
|
|
-- computation in the underlying monad @m@ that return either a 'ParseError'
|
|
|
|
|
-- ('Left') or a value of type @a@ ('Right').
|
|
|
|
|
|
|
|
|
|
runParserT :: Stream s m t =>
|
|
|
|
|
ParsecT s u m a -> u -> SourceName -> s -> m (Either ParseError a)
|
2015-08-12 20:51:06 +03:00
|
|
|
|
runParserT p u name s = do
|
|
|
|
|
res <- runParsecT p (State s (initialPos name) u)
|
|
|
|
|
r <- parserReply res
|
|
|
|
|
case r of
|
2015-08-17 18:58:59 +03:00
|
|
|
|
Ok x _ -> return $ Right x
|
|
|
|
|
Error err -> return $ Left err
|
|
|
|
|
where parserReply res =
|
|
|
|
|
case res of
|
|
|
|
|
Consumed r -> r
|
|
|
|
|
Empty r -> r
|
2014-04-09 23:01:24 +04:00
|
|
|
|
|
2015-08-12 15:41:22 +03:00
|
|
|
|
-- | @parse p filePath input@ runs a parser @p@ over identity without user
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- state. The @filePath@ is only used in error messages and may be the empty
|
|
|
|
|
-- string. Returns either a 'ParseError' ('Left') or a value of type @a@
|
|
|
|
|
-- ('Right').
|
|
|
|
|
--
|
|
|
|
|
-- > main = case (parse numbers "" "11, 2, 43") of
|
|
|
|
|
-- > Left err -> print err
|
|
|
|
|
-- > Right xs -> print (sum xs)
|
|
|
|
|
-- >
|
|
|
|
|
-- > numbers = commaSep integer
|
2014-04-09 23:01:24 +04:00
|
|
|
|
|
2015-07-30 21:36:54 +03:00
|
|
|
|
parse :: Stream s Identity t =>
|
2015-07-30 18:45:06 +03:00
|
|
|
|
Parsec s () a -> SourceName -> s -> Either ParseError a
|
|
|
|
|
parse p = runParser p ()
|
2014-04-09 23:01:24 +04:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- | @parseMaybe p input@ runs parser @p@ on @input@ and returns result
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- inside 'Just' on success and 'Nothing' on failure. This function also
|
|
|
|
|
-- parses 'eof', so all input should be consumed by the parser.
|
2009-03-02 03:20:00 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
parseMaybe :: Stream s Identity t => Parsec s () a -> s -> Maybe a
|
|
|
|
|
parseMaybe p s =
|
2015-08-17 18:58:59 +03:00
|
|
|
|
case parse (p <* eof) "" s of
|
2015-08-12 20:51:06 +03:00
|
|
|
|
Left _ -> Nothing
|
|
|
|
|
Right x -> Just x
|
2009-03-02 03:20:00 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- | The expression @parseTest p input@ applies a parser @p@ against
|
|
|
|
|
-- input @input@ and prints the result to stdout. Used for testing.
|
2009-03-02 03:20:00 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
parseTest :: (Stream s Identity t, Show a) => Parsec s () a -> s -> IO ()
|
|
|
|
|
parseTest p input =
|
2015-08-12 20:51:06 +03:00
|
|
|
|
case parse p "" input of
|
|
|
|
|
Left err -> putStr "parse error at " >> print err
|
|
|
|
|
Right x -> print x
|
2015-07-28 16:32:19 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- Primitive combinators
|
|
|
|
|
|
|
|
|
|
-- | The parser @unexpected msg@ always fails with an unexpected error
|
|
|
|
|
-- message @msg@ without consuming any input.
|
|
|
|
|
--
|
|
|
|
|
-- The parsers 'fail', ('<?>') and @unexpected@ are the three parsers used
|
|
|
|
|
-- to generate error messages. Of these, only ('<?>') is commonly used.
|
|
|
|
|
|
|
|
|
|
unexpected :: Stream s m t => String -> ParsecT s u m a
|
|
|
|
|
unexpected msg = ParsecT $ \(State _ pos _) _ _ _ eerr ->
|
|
|
|
|
eerr $ newErrorMessage (Unexpected msg) pos
|
|
|
|
|
|
|
|
|
|
infix 0 <?>
|
|
|
|
|
|
|
|
|
|
-- | The parser @p \<?> msg@ behaves as parser @p@, but whenever the
|
|
|
|
|
-- parser @p@ fails /without consuming any input/, it replaces expect error
|
|
|
|
|
-- messages with the expect error message @msg@.
|
|
|
|
|
--
|
|
|
|
|
-- This is normally used at the end of a set alternatives where we want to
|
|
|
|
|
-- return an error message in terms of a higher level construct rather than
|
|
|
|
|
-- returning all possible characters. For example, if the @expr@ parser from
|
|
|
|
|
-- the “try” example would fail, the error message is: “…: expecting
|
|
|
|
|
-- expression”. Without the @(\<?>)@ combinator, the message would be like
|
|
|
|
|
-- “…: expecting \"let\" or letter”, which is less friendly.
|
|
|
|
|
|
|
|
|
|
(<?>) :: ParsecT s u m a -> String -> ParsecT s u m a
|
|
|
|
|
(<?>) = label
|
|
|
|
|
|
|
|
|
|
-- | A synonym for @(\<?>)@, but as a function instead of an operator.
|
|
|
|
|
|
|
|
|
|
label :: ParsecT s u m a -> String -> ParsecT s u m a
|
|
|
|
|
label p l = ParsecT $ \s cok cerr eok eerr ->
|
|
|
|
|
let cok' x s' hs = cok x s' $ refreshLastHint hs l
|
|
|
|
|
eok' x s' hs = eok x s' $ refreshLastHint hs l
|
|
|
|
|
eerr' err = eerr $ setErrorMessage (Expected l) err
|
|
|
|
|
in unParser p s cok' cerr eok' eerr'
|
|
|
|
|
|
2015-08-19 22:08:20 +03:00
|
|
|
|
-- | @hidden p@ behaves just like parser @p@, but it doesn't show any “expected”
|
|
|
|
|
-- tokens in error message when @p@ fails.
|
|
|
|
|
|
|
|
|
|
hidden :: ParsecT s u m a -> ParsecT s u m a
|
|
|
|
|
hidden p = label p ""
|
|
|
|
|
|
2008-01-22 04:37:52 +03:00
|
|
|
|
-- | The parser @try p@ behaves like parser @p@, except that it
|
|
|
|
|
-- pretends that it hasn't consumed any input when an error occurs.
|
|
|
|
|
--
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- This combinator is used whenever arbitrary look ahead is needed. Since it
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- pretends that it hasn't consumed any input when @p@ fails, the ('A.<|>')
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- combinator will try its second alternative even when the first parser
|
|
|
|
|
-- failed while consuming input.
|
2008-01-22 04:37:52 +03:00
|
|
|
|
--
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- For example, here is a parser that will /try/ (sorry for the pun) to
|
|
|
|
|
-- parse word “let” or “lexical”:
|
2008-01-22 04:37:52 +03:00
|
|
|
|
--
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- >>> parseTest (string "let" <|> string "lexical") "lexical"
|
|
|
|
|
-- parse error at line 1, column 1:
|
|
|
|
|
-- unexpected "lex"
|
|
|
|
|
-- expecting "let"
|
2008-01-22 04:37:52 +03:00
|
|
|
|
--
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- First parser consumed “le” and failed, @string "lexical"@ couldn't
|
|
|
|
|
-- succeed with “xical” as its input! Things get much better with help of
|
|
|
|
|
-- @try@:
|
2008-01-22 04:37:52 +03:00
|
|
|
|
--
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- >>> parseTest (try (string "let") <|> string "lexical") "lexical"
|
|
|
|
|
-- "lexical"
|
|
|
|
|
--
|
|
|
|
|
-- @try@ also improves error messages in case of overlapping alternatives,
|
|
|
|
|
-- because Megparsec's hint system can be used:
|
|
|
|
|
--
|
|
|
|
|
-- >>> parseTest (try (string "let") <|> string "lexical") "le"
|
|
|
|
|
-- parse error at line 1, column 1:
|
|
|
|
|
-- unexpected "le"
|
|
|
|
|
-- expecting "let" or "lexical"
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
try :: ParsecT s u m a -> ParsecT s u m a
|
2015-07-30 18:45:06 +03:00
|
|
|
|
try p = ParsecT $ \s cok _ eok eerr -> unParser p s cok eerr eok eerr
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2011-02-20 19:29:20 +03:00
|
|
|
|
-- | @lookAhead p@ parses @p@ without consuming any input.
|
|
|
|
|
--
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- If @p@ fails and consumes some input, so does @lookAhead@. Combine with
|
|
|
|
|
-- 'try' if this is undesirable.
|
2011-02-20 19:29:20 +03:00
|
|
|
|
|
2015-08-12 15:41:22 +03:00
|
|
|
|
lookAhead :: Stream s m t => ParsecT s u m a -> ParsecT s u m a
|
2015-08-19 20:50:26 +03:00
|
|
|
|
lookAhead p = ParsecT $ \s _ cerr eok eerr ->
|
|
|
|
|
let eok' a _ _ = eok a s mempty
|
|
|
|
|
in unParser p s eok' cerr eok' eerr
|
2011-02-20 19:29:20 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
-- | @notFollowedBy p@ only succeeds when parser @p@ fails. This parser
|
|
|
|
|
-- does not consume any input and can be used to implement the “longest
|
|
|
|
|
-- match” rule.
|
|
|
|
|
|
|
|
|
|
notFollowedBy :: Stream s m t => ParsecT s u m a -> ParsecT s u m ()
|
|
|
|
|
notFollowedBy p = ParsecT $ \s@(State input pos _) _ _ eok eerr -> do
|
|
|
|
|
l <- maybe eoi (showToken . fst) <$> uncons input
|
|
|
|
|
let cok' _ _ _ = eerr $ unexpectedErr l pos
|
|
|
|
|
cerr' _ = eok () s mempty
|
|
|
|
|
eok' _ _ _ = eerr $ unexpectedErr l pos
|
|
|
|
|
eerr' _ = eok () s mempty
|
|
|
|
|
unParser p s cok' cerr' eok' eerr'
|
|
|
|
|
|
|
|
|
|
-- | This parser only succeeds at the end of the input.
|
|
|
|
|
|
|
|
|
|
eof :: Stream s m t => ParsecT s u m ()
|
|
|
|
|
eof = eof' <?> eoi
|
|
|
|
|
|
|
|
|
|
eof' :: Stream s m t => ParsecT s u m ()
|
|
|
|
|
eof' = ParsecT $ \s@(State input pos _) _ _ eok eerr -> do
|
|
|
|
|
r <- uncons input
|
|
|
|
|
case r of
|
|
|
|
|
Nothing -> eok () s mempty
|
|
|
|
|
Just (x,_) -> eerr $ unexpectedErr (showToken x) pos
|
|
|
|
|
|
|
|
|
|
-- | The parser @token nextPos testTok@ accepts a token @t@ with result
|
|
|
|
|
-- @x@ when the function @testTok t@ returns @'Just' x@. The position of the
|
|
|
|
|
-- /next/ token should be returned when @nextPos@ is called with the current
|
|
|
|
|
-- source position @pos@, the current token @t@ and the rest of the tokens
|
|
|
|
|
-- @toks@, @nextPos pos t toks@.
|
|
|
|
|
--
|
|
|
|
|
-- This is the most primitive combinator for accepting tokens. For example,
|
|
|
|
|
-- the 'Text.Megaparsec.Char.char' parser could be implemented as:
|
|
|
|
|
--
|
|
|
|
|
-- > char c = token nextPos testChar
|
|
|
|
|
-- > where testChar x = if x == c then Just x else Nothing
|
|
|
|
|
-- > nextPos pos x xs = updatePosChar pos x
|
|
|
|
|
|
|
|
|
|
token :: Stream s m t =>
|
|
|
|
|
(SourcePos -> t -> s -> SourcePos) -- ^ Next position calculating function.
|
|
|
|
|
-> (t -> Maybe a) -- ^ Matching function for the token to parse.
|
|
|
|
|
-> ParsecT s u m a
|
|
|
|
|
{-# INLINE token #-}
|
|
|
|
|
token nextpos = token' nextpos Nothing
|
|
|
|
|
|
|
|
|
|
token' :: Stream s m t =>
|
|
|
|
|
(SourcePos -> t -> s -> SourcePos)
|
|
|
|
|
-> Maybe (SourcePos -> t -> s -> u -> u)
|
|
|
|
|
-> (t -> Maybe a)
|
|
|
|
|
-> ParsecT s u m a
|
|
|
|
|
{-# INLINE token' #-}
|
|
|
|
|
token' nextpos Nothing test
|
|
|
|
|
= ParsecT $ \(State input pos user) cok _ _ eerr -> do
|
|
|
|
|
r <- uncons input
|
|
|
|
|
case r of
|
|
|
|
|
Nothing -> eerr $ unexpectedErr eoi pos
|
|
|
|
|
Just (c,cs) ->
|
|
|
|
|
case test c of
|
|
|
|
|
Just x -> let newpos = nextpos pos c cs
|
|
|
|
|
newstate = State cs newpos user
|
|
|
|
|
in seq newpos $ seq newstate $ cok x newstate mempty
|
|
|
|
|
Nothing -> eerr $ unexpectedErr (showToken c) pos
|
|
|
|
|
token' nextpos (Just nextState) test
|
|
|
|
|
= ParsecT $ \(State input pos user) cok _ _ eerr -> do
|
|
|
|
|
r <- uncons input
|
|
|
|
|
case r of
|
|
|
|
|
Nothing -> eerr $ unexpectedErr eoi pos
|
|
|
|
|
Just (c,cs) ->
|
|
|
|
|
case test c of
|
|
|
|
|
Just x -> let newpos = nextpos pos c cs
|
|
|
|
|
newUser = nextState pos c cs user
|
|
|
|
|
newstate = State cs newpos newUser
|
|
|
|
|
in seq newpos $ seq newstate $ cok x newstate mempty
|
|
|
|
|
Nothing -> eerr $ unexpectedErr (showToken c) pos
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
2015-08-06 13:37:08 +03:00
|
|
|
|
-- | The parser @tokens posFromTok@ parses list of tokens and returns
|
2015-08-12 15:41:22 +03:00
|
|
|
|
-- it. The resulting parser will use 'showToken' to pretty-print the
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- collection of tokens.
|
|
|
|
|
--
|
2015-08-01 19:24:45 +03:00
|
|
|
|
-- This can be used to example to write 'Text.Megaparsec.Char.string':
|
2015-07-30 18:45:06 +03:00
|
|
|
|
--
|
2015-08-06 13:37:08 +03:00
|
|
|
|
-- > string = tokens updatePosString
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
2015-08-06 13:37:08 +03:00
|
|
|
|
tokens :: (Stream s m t, Eq t, ShowToken [t]) =>
|
|
|
|
|
(SourcePos -> [t] -> SourcePos) -- ^ Computes position of tokens.
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-> [t] -- ^ List of tokens to parse
|
|
|
|
|
-> ParsecT s u m [t]
|
|
|
|
|
{-# INLINE tokens #-}
|
2015-08-17 18:58:59 +03:00
|
|
|
|
tokens _ [] = ParsecT $ \s _ _ eok _ -> eok [] s mempty
|
2015-08-12 20:51:06 +03:00
|
|
|
|
tokens nextposs tts = ParsecT $ \(State input pos u) cok cerr _ eerr ->
|
|
|
|
|
let errExpect x = setErrorMessage (Expected $ showToken tts)
|
|
|
|
|
(newErrorMessage (Unexpected x) pos)
|
2015-08-17 18:58:59 +03:00
|
|
|
|
walk [] _ rs = let pos' = nextposs pos tts
|
|
|
|
|
s' = State rs pos' u
|
|
|
|
|
in cok tts s' mempty
|
2015-08-12 20:51:06 +03:00
|
|
|
|
walk (t:ts) i rs = do
|
|
|
|
|
sr <- uncons rs
|
|
|
|
|
let errorCont = if i == 0 then eerr else cerr
|
|
|
|
|
what = bool (showToken $ take i tts) "end of input" (i == 0)
|
|
|
|
|
case sr of
|
|
|
|
|
Nothing -> errorCont . errExpect $ what
|
|
|
|
|
Just (x,xs)
|
|
|
|
|
| t == x -> walk ts (succ i) xs
|
|
|
|
|
| otherwise -> errorCont . errExpect . showToken $
|
|
|
|
|
take i tts ++ [x]
|
|
|
|
|
in walk tts 0 input
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
unexpectedErr :: String -> SourcePos -> ParseError
|
|
|
|
|
unexpectedErr msg = newErrorMessage (Unexpected msg)
|
2015-07-30 18:45:06 +03:00
|
|
|
|
|
2015-08-17 18:58:59 +03:00
|
|
|
|
eoi :: String
|
|
|
|
|
eoi = "end of input"
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- Parser state combinators
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
|
|
|
|
-- | Returns the current source position. See also 'SourcePos'.
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
getPosition :: Monad m => ParsecT s u m SourcePos
|
|
|
|
|
getPosition = statePos <$> getParserState
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- | Returns the current input.
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
getInput :: Monad m => ParsecT s u m s
|
|
|
|
|
getInput = stateInput <$> getParserState
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-28 16:32:19 +03:00
|
|
|
|
-- | @setPosition pos@ sets the current source position to @pos@.
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
setPosition :: Monad m => SourcePos -> ParsecT s u m ()
|
|
|
|
|
setPosition pos = void $ updateParserState (\(State s _ u) -> State s pos u)
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2008-01-22 04:37:52 +03:00
|
|
|
|
-- | @setInput input@ continues parsing with @input@. The 'getInput' and
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- @setInput@ functions can for example be used to deal with #include files.
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
setInput :: Monad m => s -> ParsecT s u m ()
|
|
|
|
|
setInput s = void $ updateParserState (\(State _ pos u) -> State s pos u)
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2008-01-22 04:37:52 +03:00
|
|
|
|
-- | Returns the full parser state as a 'State' record.
|
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
getParserState :: Monad m => ParsecT s u m (State s u)
|
2008-01-13 20:53:15 +03:00
|
|
|
|
getParserState = updateParserState id
|
|
|
|
|
|
2015-07-28 16:32:19 +03:00
|
|
|
|
-- | @setParserState st@ set the full parser state to @st@.
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
setParserState :: Monad m => State s u -> ParsecT s u m (State s u)
|
2008-01-13 20:53:15 +03:00
|
|
|
|
setParserState st = updateParserState (const st)
|
|
|
|
|
|
2008-01-22 04:37:52 +03:00
|
|
|
|
-- | @updateParserState f@ applies function @f@ to the parser state.
|
|
|
|
|
|
2009-03-02 03:20:00 +03:00
|
|
|
|
updateParserState :: (State s u -> State s u) -> ParsecT s u m (State s u)
|
2015-08-12 20:51:06 +03:00
|
|
|
|
updateParserState f = ParsecT $ \s _ _ eok _ ->
|
2015-08-17 18:58:59 +03:00
|
|
|
|
let s' = f s in eok s' s' mempty
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- User state combinators
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-28 16:32:19 +03:00
|
|
|
|
-- | Returns the current user state.
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
getState :: Monad m => ParsecT s u m u
|
2015-08-12 15:41:22 +03:00
|
|
|
|
getState = stateUser <$> getParserState
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-07-28 16:32:19 +03:00
|
|
|
|
-- | @putState st@ set the user state to @st@.
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
putState :: Monad m => u -> ParsecT s u m ()
|
|
|
|
|
putState u = void $ updateParserState (\s -> s { stateUser = u })
|
2008-01-13 20:53:15 +03:00
|
|
|
|
|
2015-05-17 21:18:05 +03:00
|
|
|
|
-- | @modifyState f@ applies function @f@ to the user state. Suppose
|
2008-01-22 04:37:52 +03:00
|
|
|
|
-- that we want to count identifiers in a source, we could use the user
|
|
|
|
|
-- state as:
|
|
|
|
|
--
|
2015-07-30 18:45:06 +03:00
|
|
|
|
-- > expr = Id <$> identifier <* modifyState (+1)
|
2008-01-22 04:37:52 +03:00
|
|
|
|
|
2015-07-30 18:45:06 +03:00
|
|
|
|
modifyState :: Monad m => (u -> u) -> ParsecT s u m ()
|
|
|
|
|
modifyState f = void $ updateParserState (\s -> s { stateUser = f (stateUser s)})
|