parcom-lib 0.1.0.0 → 0.2.0.0
raw patch · 4 files changed
+97/−74 lines, 4 filesdep +mtldep +transformers
Dependencies added: mtl, transformers
Files
- Text/Parcom/Combinators.hs +9/−9
- Text/Parcom/Core.hs +79/−58
- Text/Parcom/Prim.hs +6/−6
- parcom-lib.cabal +3/−1
Text/Parcom/Combinators.hs view
@@ -11,26 +11,26 @@ import Text.Parcom.Internal -- | Walk a list of options, return the first one that succeeds.-choice :: (Stream s t) => [Parcom s t a] -> Parcom s t a+choice :: (Monad m, Stream s t) => [ParcomT s t m a] -> ParcomT s t m a choice xs = foldl (<|>) empty xs <?> "I tried to make a choice, but couldn't" -- | Like @choice@, but each choice tagged with a human-readable name for -- better error reporting.-namedChoice :: (Stream s t) => [(String, Parcom s t a)] -> Parcom s t a+namedChoice :: (Monad m, Stream s t) => [(String, ParcomT s t m a)] -> ParcomT s t m a namedChoice xs = choice (map snd xs) <?> (formatOptionList . map fst) xs -- | Match two consecutive parser, return the first parser's result iff both -- succeed.-before :: (Stream s t) => Parcom s t a -> Parcom s t b -> Parcom s t a+before :: (Monad m, Stream s t) => ParcomT s t m a -> ParcomT s t m b -> ParcomT s t m a before p q = do { v <- p; q; return v } -- | Match three consecutive parsers, return the middle parser's result iff -- all three match. Parsers are given in the order inner, left, right.-between :: (Stream s t) => Parcom s t a -> Parcom s t l -> Parcom s t r -> Parcom s t a+between :: (Monad m, Stream s t) => ParcomT s t m a -> ParcomT s t m l -> ParcomT s t m r -> ParcomT s t m a between p l r = do { l; v <- p; r; return v } -- | Match zero or more occurrences of a parser-many :: (Stream s t) => Parcom s t a -> Parcom s t [a]+many :: (Monad m, Stream s t) => ParcomT s t m a -> ParcomT s t m [a] many p = handle p f m where@@ -40,7 +40,7 @@ return (x:xs) -- | Match one or more occurrences of a parser-many1 :: (Stream s t) => Parcom s t a -> Parcom s t [a]+many1 :: (Monad m, Stream s t) => ParcomT s t m a -> ParcomT s t m [a] many1 p = do xs <- many p if null xs@@ -49,7 +49,7 @@ -- | Given an item parser and a separator parser, keep parsing until the -- separator or the item fails.-manySepBy :: (Stream s t) => Parcom s t a -> Parcom s t b -> Parcom s t [a]+manySepBy :: (Monad m, Stream s t) => ParcomT s t m a -> ParcomT s t m b -> ParcomT s t m [a] manySepBy p s = go where go = do@@ -66,7 +66,7 @@ (\_ -> go >>= \xs -> return (x:xs)) -- | Run the given parser n times, returning all the results as a list.-times :: (Stream s t) => Int -> Parcom s t a -> Parcom s t [a]+times :: (Monad m, Stream s t) => Int -> ParcomT s t m a -> ParcomT s t m [a] times 0 p = return [] times n p = do x <- p@@ -74,5 +74,5 @@ return (x:xs) -- | Ignore the result of a parser.-skip :: Parcom s t a -> Parcom s t ()+skip :: Monad m => ParcomT s t m a -> ParcomT s t m () skip p = p >> return ()
Text/Parcom/Core.hs view
@@ -2,8 +2,8 @@ module Text.Parcom.Core ( ParcomError (..) , SourcePosition (..)-, Parcom-, parse+, ParcomT, parseT+, Parcom, parse , peek, next, atEnd , try, handle , notFollowedBy@@ -16,6 +16,8 @@ import Text.Parcom.Stream (Stream, Token) import Control.Monad (liftM, ap) import Control.Applicative+import Control.Monad.Identity+import Control.Monad.Trans.Class data SourcePosition = SourcePosition@@ -38,92 +40,111 @@ , psStream :: s } -newtype Parcom s t a = Parcom { runParcom :: ParcomState s -> (Either ParcomError a, ParcomState s) }+type Parcom s t a = ParcomT s t Identity a+newtype ParcomT s t m a = ParcomT { runParcomT :: ParcomState s -> m (Either ParcomError a, ParcomState s) } -instance Monad (Parcom s t) where- return x = Parcom (\s -> (Right x, s))- fail err = Parcom (\s -> (Left $ ParcomError err (psSourcePosition s), s))- m >>= f = Parcom $ \s ->- let (a, s') = runParcom m s- in case a of- Left e -> (Left e, s')- Right x -> runParcom (f x) s'+instance (Monad m) => Monad (ParcomT s t m) where+ return x = ParcomT (\s -> return (Right x, s))+ fail err = ParcomT (\s -> return (Left $ ParcomError err (psSourcePosition s), s))+ m >>= f = ParcomT $ \s -> do -- in the m Monad+ (a, s') <- runParcomT m s+ case a of+ Left err -> return (Left err, s')+ Right ma -> do+ runParcomT (f ma) s' -instance Functor (Parcom s t) where+instance MonadTrans (ParcomT s t) where+ lift a = ParcomT $ \s -> do+ v <- a+ return (Right v, s)++instance (Monad m) => Functor (ParcomT s t m) where fmap f xs = xs >>= return . f -instance Applicative (Parcom s t) where+instance (Monad m) => Applicative (ParcomT s t m) where pure = return (<*>) = ap -instance Alternative (Parcom s t) where+instance (Monad m) => Alternative (ParcomT s t m) where (<|>) = alt empty = fail "empty" -runParser :: (Stream s t, Token t) => Parcom s t a -> String -> s -> (Either ParcomError a, ParcomState s)-runParser p fn str =- runParcom p state+runParserT :: (Stream s t, Token t) => ParcomT s t m a -> String -> s -> m (Either ParcomError a, ParcomState s)+runParserT p fn str =+ runParcomT p state where state = ParcomState { psSourcePosition = SourcePosition fn 1 1 , psStream = str } +parseT :: (Stream s t, Token t, Monad m) => ParcomT s t m a -> String -> s -> m (Either ParcomError a)+parseT p fn str = fst `liftM` runParserT p fn str+ parse :: (Stream s t, Token t) => Parcom s t a -> String -> s -> Either ParcomError a-parse p fn str = fst $ runParser p fn str+parse p fn str = runIdentity $ parseT p fn str -getState :: Parcom s t (ParcomState s)-getState = Parcom $ \s -> (Right s, s)+getState :: Monad m => ParcomT s t m (ParcomState s)+getState = ParcomT $ \s -> return (Right s, s) -useState :: (ParcomState s -> a) -> Parcom s t a-useState f = Parcom $ \s -> (Right $ f s, s)+useState :: Monad m => (ParcomState s -> a) -> ParcomT s t m a+useState f = ParcomT $ \s -> return (Right $ f s, s) -setState :: ParcomState s -> Parcom s t ()-setState s = Parcom $ \_ -> (Right (), s)+setState :: Monad m => ParcomState s -> ParcomT s t m ()+setState s = ParcomT $ \_ -> return (Right (), s) -modifyState :: (ParcomState s -> ParcomState s) -> Parcom s t ()-modifyState f = Parcom $ \s -> (Right (), f s)+modifyState :: Monad m => (ParcomState s -> ParcomState s) -> ParcomT s t m ()+modifyState f = ParcomT $ \s -> return (Right (), f s) -handle :: Parcom s t a -> (ParcomError -> Parcom s t b) -> (a -> Parcom s t b) -> Parcom s t b-handle p f t = Parcom $ \s ->- let (r', s') = runParcom p s- in case r' of- -- parse failed: run the error handler- Left e -> runParcom (f e) s'- -- parse succeeded: run the success handler- Right x -> runParcom (t x) s'+-- | Very general error / success handler+-- Each of the error / success branches takes both the old and the new state,+-- so that the branch handler itself can decide whether to backtrack or+-- continue with the new state.+handle' :: Monad m+ => ParcomT s t m a+ -> (ParcomError -> ParcomState s -> ParcomState s -> m (Either ParcomError b, ParcomState s))+ -> (a -> ParcomState s -> ParcomState s -> m (Either ParcomError b, ParcomState s))+ -> ParcomT s t m b+handle' p errorH successH = ParcomT $ \s -> do+ (r, s') <- runParcomT p s+ case r of+ -- parse failed: run error handler+ Left e -> errorH e s s'+ -- parse succeeded: run success handler+ Right x -> successH x s s' +handle :: Monad m+ => ParcomT s t m a+ -> (ParcomError -> ParcomT s t m b)+ -> (a -> ParcomT s t m b)+ -> ParcomT s t m b+handle p f t =+ handle' p (\e _ s' -> runParcomT (f e) s') (\x _ s' -> runParcomT (t x) s') +handleB :: Monad m+ => ParcomT s t m a+ -> (ParcomError -> ParcomT s t m b)+ -> (a -> ParcomT s t m b)+ -> ParcomT s t m b+handleB p f t =+ handle' p (\e s _ -> runParcomT (f e) s) (\x s _ -> runParcomT (t x) s)+ -- | Backtracking modifier; restores the parser state to the previous situation -- if the wrapped parser fails.-try :: Parcom s t a -> Parcom s t a-try p = Parcom $ \s ->- let (r', s') = runParcom p s- in case r' of- -- parse failed: return the error and restore the old state- Left e -> (Left e, s)- -- parse succeeded: return the result and the new state- Right x -> (Right x, s')+try :: Monad m => ParcomT s t m a -> ParcomT s t m a+try p = handle' p (\e s _ -> return (Left e, s)) (\x _ s' -> return (Right x, s')) -- | Return the result of the first parser that succeeds.-alt :: Parcom s t a -> Parcom s t a -> Parcom s t a-alt a b = Parcom $ \s ->- let (r', s') = runParcom a s- in case r' of- Left _ -> runParcom b s- Right x -> (Right x, s')+alt :: Monad m => ParcomT s t m a -> ParcomT s t m a -> ParcomT s t m a+alt a b = handle' a (\e s _ -> runParcomT b s) (\x _ s' -> return (Right x, s')) -- | Succeeds iff the given parser fails-notFollowedBy :: (Stream s t) => Parcom s t a -> Parcom s t ()-notFollowedBy p = Parcom $ \s ->- let (r', s') = runParcom p s- in case r' of- Left _ -> (Right (), s)- Right x -> runParcom (fail "something followed that shouldn't") s+notFollowedBy :: (Monad m, Stream s t) => ParcomT s t m a -> ParcomT s t m ()+notFollowedBy p = handle' p (\_ s _ -> return (Right (), s)) (\x s _ -> runParcomT (fail "something followed that shouldn't") s) -- | Gets the next token from the stream without consuming it. -- Fails at end-of-input.-peek :: (Stream s t) => Parcom s t t+peek :: (Monad m, Stream s t) => ParcomT s t m t peek = do str <- psStream `liftM` getState if Stream.atEnd str@@ -131,7 +152,7 @@ else return (Stream.peek str) -- | Checks whether end-of-input has been reached.-atEnd :: (Stream s t) => Parcom s t Bool+atEnd :: (Monad m, Stream s t) => ParcomT s t m Bool atEnd = useState (Stream.atEnd . psStream) nextLine :: SourcePosition -> SourcePosition@@ -144,7 +165,7 @@ -- | Gets the next token from the stream and consumes it. -- Fails at end-of-input.-next :: (Stream s t, Token t) => Parcom s t t+next :: (Monad m, Stream s t, Token t) => ParcomT s t m t next = do str <- psStream `liftM` getState if Stream.atEnd str@@ -157,5 +178,5 @@ else modifyState $ \s -> s { psSourcePosition = nextColumn (psSourcePosition s) } return t -(<?>) :: (Stream s t) => Parcom s t a -> String -> Parcom s t a+(<?>) :: (Monad m, Stream s t) => ParcomT s t m a -> String -> ParcomT s t m a p <?> expected = p <|> fail ("Expected " ++ expected)
Text/Parcom/Prim.hs view
@@ -9,20 +9,20 @@ import Text.Parcom.Internal -- | Gets the next token from the stream-anyToken :: (Stream s t, Token t) => Parcom s t t+anyToken :: (Monad m, Stream s t, Token t) => ParcomT s t m t anyToken = next -- | Succeeds iff end-of-input has been reached-eof :: (Stream s t, Token t) => Parcom s t ()+eof :: (Monad m, Stream s t, Token t) => ParcomT s t m () eof = notFollowedBy anyToken <?> "end of input" -- | Matches one token against a list of possible tokens; returns the -- matching token.-oneOf :: (Stream s t, Token t, Show t, Eq t) => [t] -> Parcom s t t+oneOf :: (Monad m, Stream s t, Token t, Show t, Eq t) => [t] -> ParcomT s t m t oneOf xs = satisfy (`elem` xs) <?> (formatOptionList . map show) xs -- | Succeeds if the given predicate is met for the next token.-satisfy :: (Stream s t, Token t) => (t -> Bool) -> Parcom s t t+satisfy :: (Monad m, Stream s t, Token t) => (t -> Bool) -> ParcomT s t m t satisfy p = do c <- peek if p c@@ -30,11 +30,11 @@ else fail "Predicate not met" -- | Exactly match one particular token-token :: (Stream s t, Token t, Show t, Eq t) => t -> Parcom s t t+token :: (Monad m, Stream s t, Token t, Show t, Eq t) => t -> ParcomT s t m t token t = satisfy (== t) <?> show t -- | Match a series of tokens exactly-tokens :: (Stream s t, Token t, Eq t, Show t) => [t] -> Parcom s t [t]+tokens :: (Monad m, Stream s t, Token t, Eq t, Show t) => [t] -> ParcomT s t m [t] tokens [] = return [] tokens (x:xs) = do c <- token x
parcom-lib.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: parcom-lib-version: 0.1.0.0+version: 0.2.0.0 synopsis: A simple parser-combinator library, a bit like Parsec but without the frills description: Parcom provides parser combinator functionality in a string-type-agnostic way; it supports strict ByteStrings (with Word8 tokens) and any list type (with@@ -26,3 +26,5 @@ , containers ==0.4.* , bytestring ==0.9.* , word8+ , mtl == 2.1.*+ , transformers == 0.3.*