polyparse 1.7 → 1.8
raw patch · 4 files changed
+149/−10 lines, 4 files
Files
- polyparse.cabal +3/−2
- src/Text/Parse/ByteString.hs +2/−2
- src/Text/ParserCombinators/Poly/ByteString.hs +7/−6
- src/Text/ParserCombinators/Poly/ByteStringChar.hs +137/−0
polyparse.cabal view
@@ -1,5 +1,5 @@ name: polyparse-version: 1.7+version: 1.8 license: LGPL license-file: COPYRIGHT author: Malcolm Wallace <Malcolm.Wallace@me.com>@@ -39,10 +39,11 @@ build-depends: text exposed-modules: Text.ParserCombinators.Poly.ByteString+ Text.ParserCombinators.Poly.ByteStringChar Text.Parse.ByteString Text.ParserCombinators.Poly.Text Text.ParserCombinators.Poly.StateText -- Text.Parse.Text- cpp-options: -DVERSION="1.7"+ cpp-options: -DVERSION="1.8" nhc98-options: -K6M extensions: CPP
src/Text/Parse/ByteString.hs view
@@ -26,7 +26,7 @@ , parseFloat , parseLitChar -- ** Re-export all the more general combinators from Poly too- , module Text.ParserCombinators.Poly.ByteString+ , module Text.ParserCombinators.Poly.ByteStringChar -- ** ByteStrings and Strings as whole entities , allAsByteString , allAsString@@ -38,7 +38,7 @@ import Data.Ratio import qualified Data.ByteString.Lazy.Char8 as BS import Data.ByteString.Lazy.Char8 (ByteString)-import Text.ParserCombinators.Poly.ByteString+import Text.ParserCombinators.Poly.ByteStringChar ------------------------------------------------------------------------ -- $parser
src/Text/ParserCombinators/Poly/ByteString.hs view
@@ -20,9 +20,10 @@ import Text.ParserCombinators.Poly.Base import Text.ParserCombinators.Poly.Result-import qualified Data.ByteString.Lazy.Char8 as BS-import Data.ByteString.Lazy.Char8 (ByteString)+import qualified Data.ByteString.Lazy as BS+import Data.ByteString.Lazy (ByteString) import Control.Applicative+import Data.Word -- | This @Parser@ datatype is a specialised parsing monad with error -- reporting. Whereas the standard version can be used for arbitrary@@ -83,7 +84,7 @@ ------------------------------------------------------------------------ -- | Simply return the next token in the input tokenstream.-next :: Parser Char+next :: Parser Word8 next = P (\bs-> case BS.uncons bs of Nothing -> Failure bs "Ran out of input (EOF)" Just (h, t) -> Success t h )@@ -95,7 +96,7 @@ else Failure bs "Expected end of input (EOF)" ) -- | Return the next token if it satisfies the given predicate.-satisfy :: (Char -> Bool) -> Parser Char+satisfy :: (Word8 -> Bool) -> Parser Word8 satisfy f = do { x <- next ; if f x then return x else fail "Parse.satisfy: failed" }@@ -115,11 +116,11 @@ ------------------------------------------------------------------------ -- | @manySatisfy p@ is a more efficient fused version of @many (satisfy p)@-manySatisfy :: (Char->Bool) -> Parser ByteString+manySatisfy :: (Word8->Bool) -> Parser ByteString manySatisfy f = P (\bs-> let (pre,suf) = BS.span f bs in Success suf pre) -- | @many1Satisfy p@ is a more efficient fused version of @many1 (satisfy p)@-many1Satisfy :: (Char->Bool) -> Parser ByteString+many1Satisfy :: (Word8->Bool) -> Parser ByteString many1Satisfy f = do x <- manySatisfy f if BS.null x then fail "Parse.many1Satisfy: failed" else return x
+ src/Text/ParserCombinators/Poly/ByteStringChar.hs view
@@ -0,0 +1,137 @@+module Text.ParserCombinators.Poly.ByteStringChar+ ( -- * The Parser datatype+ Parser(P)+ , Result(..)+ , runParser+ -- ** Basic parsers+ , next+ , eof+ , satisfy+ , onFail+ -- ** Derived parsers (but implemented more efficiently)+ , manySatisfy+ , many1Satisfy+ -- ** Re-parsing+ , reparse+ -- * Re-export all more general combinators+ , module Text.ParserCombinators.Poly.Base+ ) where+++import Text.ParserCombinators.Poly.Base+import Text.ParserCombinators.Poly.Result+import qualified Data.ByteString.Lazy.Char8 as BS+import Data.ByteString.Lazy.Char8 (ByteString)+import Control.Applicative++-- | This @Parser@ datatype is a specialised parsing monad with error+-- reporting. Whereas the standard version can be used for arbitrary+-- token types, this version is specialised to ByteString input only.+newtype Parser a = P (ByteString -> Result ByteString a)++-- | Apply a parser to an input token sequence.+runParser :: Parser a -> ByteString -> (Either String a, ByteString)+runParser (P p) = resultToEither . p++instance Functor Parser where+ fmap f (P p) = P (fmap f . p)++instance Monad Parser where+ return x = P (\ts-> Success ts x)+ fail e = P (\ts-> Failure ts e)+ (P f) >>= g = P (continue . f)+ where+ continue (Success ts x) = let (P g') = g x in g' ts+ continue (Committed (Committed r)) = continue (Committed r)+ continue (Committed r) = Committed (continue r)+ continue (Failure ts e) = Failure ts e++instance Commitment Parser where+ commit (P p) = P (Committed . p)+ (P p) `adjustErr` f = P (adjust . p)+ where+ adjust (Failure z e) = Failure z (f e)+ adjust (Committed r) = Committed (adjust r)+ adjust good = good++ oneOf' = accum []+ where accum errs [] =+ fail ("failed to parse any of the possible choices:\n"+ ++indent 2 (concatMap showErr (reverse errs)))+ accum errs ((e,P p):ps) =+ P (\ts-> case p ts of+ Failure _ err ->+ let (P p') = accum ((e,err):errs) ps+ in p' ts+ r@(Success _ _) -> r+ r@(Committed _) -> r )+ showErr (name,err) = name++":\n"++indent 2 err++instance Applicative Parser where+ pure f = return f+ pf <*> px = do { f <- pf; x <- px; return (f x) }+#if defined(GLASGOW_HASKELL) && GLASGOW_HASKELL > 610+ p <* q = p `discard` q+#endif++instance Alternative Parser where+ empty = fail "no parse"+ p <|> q = p `onFail` q++instance PolyParse Parser++------------------------------------------------------------------------++-- | Simply return the next token in the input tokenstream.+next :: Parser Char+next = P (\bs-> case BS.uncons bs of+ Nothing -> Failure bs "Ran out of input (EOF)"+ Just (h, t) -> Success t h )++-- | Succeed if the end of file/input has been reached, fail otherwise.+eof :: Parser ()+eof = P (\bs -> if BS.null bs+ then Success bs ()+ else Failure bs "Expected end of input (EOF)" )++-- | Return the next token if it satisfies the given predicate.+satisfy :: (Char -> Bool) -> Parser Char+satisfy f = do { x <- next+ ; if f x then return x else fail "Parse.satisfy: failed"+ }++-- | @p `onFail` q@ means parse p, unless p fails, in which case+-- parse q instead.+-- Can be chained together to give multiple attempts to parse something.+-- (Note that q could itself be a failing parser, e.g. to change the error+-- message from that defined in p to something different.)+-- However, a severe failure in p cannot be ignored.+onFail :: Parser a -> Parser a -> Parser a+(P p) `onFail` (P q) = P (\ts-> continue ts $ p ts)+ where continue ts (Failure _ _) = q ts+ -- continue _ (Committed r) = r -- no, remain Committed+ continue _ r = r++------------------------------------------------------------------------++-- | @manySatisfy p@ is a more efficient fused version of @many (satisfy p)@+manySatisfy :: (Char->Bool) -> Parser ByteString+manySatisfy f = P (\bs-> let (pre,suf) = BS.span f bs in Success suf pre)++-- | @many1Satisfy p@ is a more efficient fused version of @many1 (satisfy p)@+many1Satisfy :: (Char->Bool) -> Parser ByteString+many1Satisfy f = do x <- manySatisfy f+ if BS.null x then fail "Parse.many1Satisfy: failed"+ else return x++------------------------------------------------------------------------++-- | Push some tokens back onto the front of the input stream and reparse.+-- This is useful e.g. for recursively expanding macros. When the+-- user-parser recognises a macro use, it can lookup the macro+-- expansion from the parse state, lex it, and then stuff the+-- lexed expansion back down into the parser.+reparse :: ByteString -> Parser ()+reparse ts = P (\inp-> Success (ts `BS.append` inp) ())++------------------------------------------------------------------------