module Text.Megaparsec.Prim
(
State (..)
, Stream (..)
, StorableStream (..)
, Parsec
, ParsecT
, MonadParsec (..)
, (<?>)
, unexpected
, getInput
, setInput
, getPosition
, setPosition
, getTabWidth
, setTabWidth
, setParserState
, runParser
, runParser'
, runParserT
, runParserT'
, parse
, parseMaybe
, parseTest
, parseFromFile )
where
import Control.Monad
import qualified Control.Monad.Fail as Fail
import Control.Monad.Cont.Class
import Control.Monad.Error.Class
import Control.Monad.Identity
import Control.Monad.Reader.Class
import Control.Monad.State.Class hiding (state)
import Control.Monad.Trans
import Control.Monad.Trans.Identity
import Data.Semigroup
import qualified Control.Applicative as A
import qualified Control.Monad.Trans.Reader as L
import qualified Control.Monad.Trans.State.Lazy as L
import qualified Control.Monad.Trans.State.Strict as S
import qualified Control.Monad.Trans.Writer.Lazy as L
import qualified Control.Monad.Trans.Writer.Strict as S
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.IO as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TL
import Text.Megaparsec.Error
import Text.Megaparsec.Pos
import Text.Megaparsec.ShowToken
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>), (<*), pure)
#endif
data State s = State
{ stateInput :: s
, statePos :: !SourcePos
, stateTabWidth :: !Int }
deriving (Show, Eq)
longestMatch :: State s -> State s -> State s
longestMatch s1@(State _ pos1 _) s2@(State _ pos2 _) =
case pos1 `compare` pos2 of
LT -> s2
EQ -> s2
GT -> s1
data Reply s a = Reply !(State s) Consumption (Result a)
data Consumption
= Consumed
| Virgin
data Result a
= OK a
| Error ParseError
newtype Hints = Hints [[String]] deriving (Monoid, Semigroup)
toHints :: ParseError -> Hints
toHints err = Hints hints
where hints = if null msgs then [] else [messageString <$> msgs]
msgs = filter isExpected (errorMessages err)
withHints
:: Hints
-> (ParseError -> State s -> m b)
-> ParseError
-> State s
-> m b
withHints (Hints xs) c e =
if all isMessage (errorMessages e)
then c e
else c (addErrorMessages (Expected <$> concat xs) e)
accHints
:: Hints
-> (a -> State s -> Hints -> m b)
-> a
-> State s
-> Hints
-> m b
accHints hs1 c x s hs2 = c x s (hs1 <> hs2)
refreshLastHint :: Hints -> String -> Hints
refreshLastHint (Hints []) _ = Hints []
refreshLastHint (Hints (_:xs)) "" = Hints xs
refreshLastHint (Hints (_:xs)) l = Hints ([l]:xs)
class (ShowToken t, ShowToken [t]) => Stream s t | s -> t where
uncons :: s -> Maybe (t, s)
instance (ShowToken t, ShowToken [t]) => Stream [t] t where
uncons [] = Nothing
uncons (t:ts) = Just (t, ts)
instance Stream B.ByteString Char where
uncons = B.uncons
instance Stream BL.ByteString Char where
uncons = BL.uncons
instance Stream T.Text Char where
uncons = T.uncons
instance Stream TL.Text Char where
uncons = TL.uncons
class Stream s t => StorableStream s t where
fromFile :: FilePath -> IO s
instance StorableStream String Char where
fromFile = readFile
instance StorableStream B.ByteString Char where
fromFile = B.readFile
instance StorableStream BL.ByteString Char where
fromFile = BL.readFile
instance StorableStream T.Text Char where
fromFile = T.readFile
instance StorableStream TL.Text Char where
fromFile = TL.readFile
type Parsec s = ParsecT s Identity
newtype ParsecT s m a = ParsecT
{ unParser :: forall b. State s
-> (a -> State s -> Hints -> m b)
-> (ParseError -> State s -> m b)
-> (a -> State s -> Hints -> m b)
-> (ParseError -> State s -> m b)
-> m b }
instance Functor (ParsecT s m) where
fmap = pMap
pMap :: (a -> b) -> ParsecT s m a -> ParsecT s m b
pMap f p = ParsecT $ \s cok cerr eok eerr ->
unParser p s (cok . f) cerr (eok . f) eerr
instance A.Applicative (ParsecT s m) where
pure = pPure
(<*>) = ap
p1 *> p2 = p1 `pBind` const p2
p1 <* p2 = do { x1 <- p1 ; void p2 ; return x1 }
instance A.Alternative (ParsecT s m) where
empty = mzero
(<|>) = mplus
many p = reverse <$> manyAcc p
manyAcc :: ParsecT s m a -> ParsecT s m [a]
manyAcc 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)
cerr
manyErr
(errToHints $ cok (x:xs) s')
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."
instance Monad (ParsecT s m) where
return = pure
(>>=) = pBind
fail = Fail.fail
instance Fail.MonadFail (ParsecT s m) where
fail = pFail
pPure :: a -> ParsecT s m a
pPure x = ParsecT $ \s _ _ eok _ -> eok x s mempty
pBind :: ParsecT s m a -> (a -> ParsecT s m b) -> ParsecT s m b
pBind m k = ParsecT $ \s cok cerr eok eerr ->
let mcok x s' hs = unParser (k x) s' cok cerr
(accHints hs cok) (withHints hs cerr)
meok x s' hs = unParser (k x) s' cok cerr
(accHints hs eok) (withHints hs eerr)
in unParser m s mcok cerr meok eerr
pFail :: String -> ParsecT s m a
pFail msg = ParsecT $ \s@(State _ pos _) _ _ _ eerr ->
eerr (newErrorMessage (Message msg) pos) s
mkPT :: Monad m => (State s -> m (Reply s a)) -> ParsecT s m a
mkPT k = ParsecT $ \s cok cerr eok eerr -> do
(Reply s' consumption result) <- k s
case consumption of
Consumed ->
case result of
OK x -> cok x s' mempty
Error e -> cerr e s'
Virgin ->
case result of
OK x -> eok x s' mempty
Error e -> eerr e s'
instance MonadIO m => MonadIO (ParsecT s m) where
liftIO = lift . liftIO
instance MonadReader r m => MonadReader r (ParsecT s m) where
ask = lift ask
local f p = mkPT $ \s -> local f (runParsecT p s)
instance MonadState s m => MonadState s (ParsecT s' m) where
get = lift get
put = lift . put
instance MonadCont m => MonadCont (ParsecT s m) where
callCC f = mkPT $ \s ->
callCC $ \c ->
runParsecT (f (\a -> mkPT $ \s' -> c (pack s' a))) s
where pack s a = Reply s Virgin (OK a)
instance MonadError e m => MonadError e (ParsecT s m) where
throwError = lift . throwError
p `catchError` h = mkPT $ \s ->
runParsecT p s `catchError` \e ->
runParsecT (h e) s
instance MonadPlus (ParsecT s m) where
mzero = pZero
mplus = pPlus
pZero :: ParsecT s m a
pZero = ParsecT $ \s@(State _ pos _) _ _ _ eerr ->
eerr (newErrorUnknown pos) s
pPlus :: ParsecT s m a -> ParsecT s m a -> ParsecT s m a
pPlus m n = ParsecT $ \s cok cerr eok eerr ->
let meerr err ms =
let ncerr err' s' = cerr (err' <> err) (longestMatch ms s')
neok x s' hs = eok x s' (toHints err <> hs)
neerr err' s' = eerr (err' <> err) (longestMatch ms s')
in unParser n s cok ncerr neok neerr
in unParser m s cok cerr eok meerr
instance MonadTrans (ParsecT s) where
lift amb = ParsecT $ \s _ _ eok _ -> amb >>= \a -> eok a s mempty
class (A.Alternative m, MonadPlus m, Stream s t)
=> MonadParsec s m t | m -> s t where
failure :: [Message] -> m a
label :: String -> m a -> m a
hidden :: m a -> m a
hidden = label ""
try :: m a -> m a
lookAhead :: m a -> m a
notFollowedBy :: m a -> m ()
withRecovery
:: (ParseError -> m a)
-> m a
-> m a
eof :: m ()
token
:: (Int -> SourcePos -> t -> SourcePos)
-> (t -> Either [Message] a)
-> m a
tokens :: Eq t
=> (Int -> SourcePos -> [t] -> SourcePos)
-> (t -> t -> Bool)
-> [t]
-> m [t]
getParserState :: m (State s)
updateParserState :: (State s -> State s) -> m ()
instance Stream s t => MonadParsec s (ParsecT s m) t where
failure = pFailure
label = pLabel
try = pTry
lookAhead = pLookAhead
notFollowedBy = pNotFollowedBy
withRecovery = pWithRecovery
eof = pEof
token = pToken
tokens = pTokens
getParserState = pGetParserState
updateParserState = pUpdateParserState
pFailure :: [Message] -> ParsecT s m a
pFailure msgs = ParsecT $ \s@(State _ pos _) _ _ _ eerr ->
eerr (newErrorMessages msgs pos) s
pLabel :: String -> ParsecT s m a -> ParsecT s m a
pLabel l p = ParsecT $ \s cok cerr eok eerr ->
let l' = if null l then l else "rest of " ++ l
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'
pTry :: ParsecT s m a -> ParsecT s m a
pTry p = ParsecT $ \s cok _ eok eerr ->
unParser p s cok eerr eok eerr
pLookAhead :: ParsecT s m a -> ParsecT s m a
pLookAhead p = ParsecT $ \s _ cerr eok eerr ->
let eok' a _ _ = eok a s mempty
in unParser p s eok' cerr eok' eerr
pNotFollowedBy :: Stream s t => ParsecT s m a -> ParsecT s m ()
pNotFollowedBy p = ParsecT $ \s@(State input pos _) _ _ eok eerr ->
let l = maybe eoi (showToken . fst) (uncons input)
cok' _ _ _ = eerr (unexpectedErr l pos) s
cerr' _ _ = eok () s mempty
eok' _ _ _ = eerr (unexpectedErr l pos) s
eerr' _ _ = eok () s mempty
in unParser p s cok' cerr' eok' eerr'
pWithRecovery :: Stream s t
=> (ParseError -> ParsecT s m a)
-> ParsecT s m a
-> ParsecT s m a
pWithRecovery r p = ParsecT $ \s cok cerr eok eerr ->
let mcerr err ms =
let rcok x s' _ = cok x s' mempty
rcerr _ _ = cerr err ms
reok x s' _ = eok x s' (toHints err)
reerr _ _ = cerr err ms
in unParser (r err) ms rcok rcerr reok reerr
meerr err ms =
let rcok x s' _ = cok x s' (toHints err)
rcerr _ _ = eerr err ms
reok x s' _ = eok x s' (toHints err)
reerr _ _ = eerr err ms
in unParser (r err) ms rcok rcerr reok reerr
in unParser p s cok mcerr eok meerr
pEof :: Stream s t => ParsecT s m ()
pEof = label eoi $ ParsecT $ \s@(State input pos _) _ _ eok eerr ->
case uncons input of
Nothing -> eok () s mempty
Just (x,_) -> eerr (unexpectedErr (showToken x) pos) s
pToken :: Stream s t
=> (Int -> SourcePos -> t -> SourcePos)
-> (t -> Either [Message] a)
-> ParsecT s m a
pToken nextpos test = ParsecT $ \s@(State input pos w) cok _ _ eerr ->
case uncons input of
Nothing -> eerr (unexpectedErr eoi pos) s
Just (c,cs) ->
case test c of
Left ms -> eerr (addErrorMessages ms (newErrorUnknown pos)) s
Right x -> let newpos = nextpos w pos c
newstate = State cs newpos w
in seq newpos $ seq newstate $ cok x newstate mempty
pTokens :: Stream s t
=> (Int -> SourcePos -> [t] -> SourcePos)
-> (t -> t -> Bool)
-> [t]
-> ParsecT s m [t]
pTokens _ _ [] = ParsecT $ \s _ _ eok _ -> eok [] s mempty
pTokens nextpos test tts = ParsecT $ \s@(State input pos w) cok _ _ eerr ->
let r = showToken . reverse
errExpect x = setErrorMessage (Expected $ showToken tts)
(newErrorMessage (Unexpected x) pos)
walk [] is rs =
let pos' = nextpos w pos tts
s' = State rs pos' w
in cok (reverse is) s' mempty
walk (t:ts) is rs =
let what = if null is then eoi else r is
in case uncons rs of
Nothing -> eerr (errExpect what) s
Just (x,xs)
| test t x -> walk ts (x:is) xs
| otherwise -> eerr (errExpect $ r (x:is)) s
in walk tts [] input
pGetParserState :: ParsecT s m (State s)
pGetParserState = ParsecT $ \s _ _ eok _ -> eok s s mempty
pUpdateParserState :: (State s -> State s) -> ParsecT s m ()
pUpdateParserState f = ParsecT $ \s _ _ eok _ -> eok () (f s) mempty
infix 0 <?>
(<?>) :: MonadParsec s m t => m a -> String -> m a
(<?>) = flip label
unexpected :: MonadParsec s m t => String -> m a
unexpected = failure . pure . Unexpected
unexpectedErr :: String -> SourcePos -> ParseError
unexpectedErr msg = newErrorMessage (Unexpected msg)
eoi :: String
eoi = "end of input"
getInput :: MonadParsec s m t => m s
getInput = stateInput <$> getParserState
setInput :: MonadParsec s m t => s -> m ()
setInput s = updateParserState (\(State _ pos w) -> State s pos w)
getPosition :: MonadParsec s m t => m SourcePos
getPosition = statePos <$> getParserState
setPosition :: MonadParsec s m t => SourcePos -> m ()
setPosition pos = updateParserState (\(State s _ w) -> State s pos w)
getTabWidth :: MonadParsec s m t => m Int
getTabWidth = stateTabWidth <$> getParserState
setTabWidth :: MonadParsec s m t => Int -> m ()
setTabWidth w = updateParserState (\(State s pos _) -> State s pos w)
setParserState :: MonadParsec s m t => State s -> m ()
setParserState st = updateParserState (const st)
parse :: Stream s t
=> Parsec s a
-> String
-> s
-> Either ParseError a
parse = runParser
parseMaybe :: Stream s t => Parsec s a -> s -> Maybe a
parseMaybe p s =
case parse (p <* eof) "" s of
Left _ -> Nothing
Right x -> Just x
parseTest :: (Stream s t, Show a) => Parsec s a -> s -> IO ()
parseTest p input =
case parse p "" input of
Left e -> print e
Right x -> print x
runParser :: Stream s t
=> Parsec s a
-> String
-> s
-> Either ParseError a
runParser p name s = snd $ runParser' p (initialState name s)
runParser' :: Stream s t
=> Parsec s a
-> State s
-> (State s, Either ParseError a)
runParser' p = runIdentity . runParserT' p
runParserT :: (Monad m, Stream s t)
=> ParsecT s m a
-> String
-> s
-> m (Either ParseError a)
runParserT p name s = snd `liftM` runParserT' p (initialState name s)
runParserT' :: (Monad m, Stream s t)
=> ParsecT s m a
-> State s
-> m (State s, Either ParseError a)
runParserT' p s = do
(Reply s' _ result) <- runParsecT p s
case result of
OK x -> return (s', Right x)
Error e -> return (s', Left e)
initialState :: Stream s t => String -> s -> State s
initialState name s = State s (initialPos name) defaultTabWidth
runParsecT :: Monad m
=> ParsecT s m a
-> State s
-> m (Reply s a)
runParsecT p s = unParser p s cok cerr eok eerr
where cok a s' _ = return $ Reply s' Consumed (OK a)
cerr err s' = return $ Reply s' Consumed (Error err)
eok a s' _ = return $ Reply s' Virgin (OK a)
eerr err s' = return $ Reply s' Virgin (Error err)
parseFromFile :: StorableStream s t
=> Parsec s a
-> FilePath
-> IO (Either ParseError a)
parseFromFile p filename = runParser p filename <$> fromFile filename
instance MonadParsec s m t => MonadParsec s (L.StateT e m) t where
failure = lift . failure
label n (L.StateT m) = L.StateT $ label n . m
try (L.StateT m) = L.StateT $ try . m
lookAhead (L.StateT m) = L.StateT $ \s ->
(,s) . fst <$> lookAhead (m s)
notFollowedBy (L.StateT m) = L.StateT $ \s ->
notFollowedBy (fst <$> m s) >> return ((),s)
withRecovery r (L.StateT m) = L.StateT $ \s ->
withRecovery (\e -> L.runStateT (r e) s) (m s)
eof = lift eof
token f e = lift $ token f e
tokens f e ts = lift $ tokens f e ts
getParserState = lift getParserState
updateParserState f = lift $ updateParserState f
instance MonadParsec s m t => MonadParsec s (S.StateT e m) t where
failure = lift . failure
label n (S.StateT m) = S.StateT $ label n . m
try (S.StateT m) = S.StateT $ try . m
lookAhead (S.StateT m) = S.StateT $ \s ->
(,s) . fst <$> lookAhead (m s)
notFollowedBy (S.StateT m) = S.StateT $ \s ->
notFollowedBy (fst <$> m s) >> return ((),s)
withRecovery r (S.StateT m) = S.StateT $ \s ->
withRecovery (\e -> S.runStateT (r e) s) (m s)
eof = lift eof
token f e = lift $ token f e
tokens f e ts = lift $ tokens f e ts
getParserState = lift getParserState
updateParserState f = lift $ updateParserState f
instance MonadParsec s m t => MonadParsec s (L.ReaderT e m) t where
failure = lift . failure
label n (L.ReaderT m) = L.ReaderT $ label n . m
try (L.ReaderT m) = L.ReaderT $ try . m
lookAhead (L.ReaderT m) = L.ReaderT $ lookAhead . m
notFollowedBy (L.ReaderT m) = L.ReaderT $ notFollowedBy . m
withRecovery r (L.ReaderT m) = L.ReaderT $ \s ->
withRecovery (\e -> L.runReaderT (r e) s) (m s)
eof = lift eof
token f e = lift $ token f e
tokens f e ts = lift $ tokens f e ts
getParserState = lift getParserState
updateParserState f = lift $ updateParserState f
instance (Monoid w, MonadParsec s m t) => MonadParsec s (L.WriterT w m) t where
failure = lift . failure
label n (L.WriterT m) = L.WriterT $ label n m
try (L.WriterT m) = L.WriterT $ try m
lookAhead (L.WriterT m) = L.WriterT $
(,mempty) . fst <$> lookAhead m
notFollowedBy (L.WriterT m) = L.WriterT $
(,mempty) <$> notFollowedBy (fst <$> m)
withRecovery r (L.WriterT m) = L.WriterT $
withRecovery (L.runWriterT . r) m
eof = lift eof
token f e = lift $ token f e
tokens f e ts = lift $ tokens f e ts
getParserState = lift getParserState
updateParserState f = lift $ updateParserState f
instance (Monoid w, MonadParsec s m t) => MonadParsec s (S.WriterT w m) t where
failure = lift . failure
label n (S.WriterT m) = S.WriterT $ label n m
try (S.WriterT m) = S.WriterT $ try m
lookAhead (S.WriterT m) = S.WriterT $
(,mempty) . fst <$> lookAhead m
notFollowedBy (S.WriterT m) = S.WriterT $
(,mempty) <$> notFollowedBy (fst <$> m)
withRecovery r (S.WriterT m) = S.WriterT $
withRecovery (S.runWriterT . r) m
eof = lift eof
token f e = lift $ token f e
tokens f e ts = lift $ tokens f e ts
getParserState = lift getParserState
updateParserState f = lift $ updateParserState f
instance MonadParsec s m t => MonadParsec s (IdentityT m) t where
failure = lift . failure
label n (IdentityT m) = IdentityT $ label n m
try = IdentityT . try . runIdentityT
lookAhead (IdentityT m) = IdentityT $ lookAhead m
notFollowedBy (IdentityT m) = IdentityT $ notFollowedBy m
withRecovery r (IdentityT m) = IdentityT $
withRecovery (runIdentityT . r) m
eof = lift eof
token f e = lift $ token f e
tokens f e ts = lift $ tokens f e ts
getParserState = lift getParserState
updateParserState f = lift $ updateParserState f