polyparse 1.5 → 1.6
raw patch · 5 files changed
+304/−9 lines, 5 filesdep +text
Dependencies added: text
Files
- COPYRIGHT +1/−1
- polyparse.cabal +6/−5
- src/Text/ParserCombinators/Poly/Base.hs +0/−3
- src/Text/ParserCombinators/Poly/StateText.hs +159/−0
- src/Text/ParserCombinators/Poly/Text.hs +138/−0
COPYRIGHT view
@@ -6,7 +6,7 @@ (c) copyright 1998-2000 Malcolm Wallace The modules Text.ParserCombinators.Poly* and Text.Parse and Text.Parse.* are- (c) copyright 2006-2010 Malcolm Wallace+ (c) copyright 2006-2011 Malcolm Wallace These modules are licensed under the terms of the GNU Lesser General Public Licence (LGPL), which can be found in the file called
polyparse.cabal view
@@ -1,5 +1,5 @@ name: polyparse-version: 1.5+version: 1.6 license: LGPL license-file: COPYRIGHT author: Malcolm Wallace <Malcolm.Wallace@me.com>@@ -36,12 +36,13 @@ Text.Parse if impl(ghc) build-depends: bytestring--- build-depends: text+ build-depends: text exposed-modules:- Text.ParserCombinators.Poly.ByteString,+ Text.ParserCombinators.Poly.ByteString Text.Parse.ByteString--- Text.ParserCombinators.Poly.Text,+ Text.ParserCombinators.Poly.Text+ Text.ParserCombinators.Poly.StateText -- Text.Parse.Text- cpp-options: -DVERSION="1.5"+ cpp-options: -DVERSION="1.6" nhc98-options: -K6M extensions: CPP
src/Text/ParserCombinators/Poly/Base.hs view
@@ -13,13 +13,10 @@ , indent -- :: Int -> String -> String -- ** Choices , oneOf -- :: PolyParse p => [p a] -> p a- , optional -- :: PolyParse p => p a -> p (Maybe a) -- ** Sequences , exactly -- :: PolyParse p => Int -> p a -> p [a] , upto -- :: PolyParse p => Int -> p a -> p [a]- , many -- :: PolyParse p => p a -> p [a] , many1 -- :: PolyParse p => p a -> p [a]- , some -- :: PolyParse p => p a -> p [a] , sepBy -- :: PolyParse p => p a -> p sep -> p [a] , sepBy1 -- :: PolyParse p => p a -> p sep -> p [a] , bracketSep -- :: PolyParse p => p bra -> p sep -> p ket -> p a -> p [a]
+ src/Text/ParserCombinators/Poly/StateText.hs view
@@ -0,0 +1,159 @@+module Text.ParserCombinators.Poly.StateText+ ( -- * The Parser datatype+ Parser(P)+ , Result(..)+ , runParser+ -- ** Basic parsers+ , next+ , eof+ , satisfy+ , onFail+ -- ** Derived parsers (but implemented more efficiently)+ , manySatisfy+ , many1Satisfy+ -- ** State-handling+ , stUpdate -- :: (s->s) -> Parser s t ()+ , stQuery -- :: (s->a) -> Parser s t a+ , stGet -- :: Parser s t s+ -- ** Re-parsing+ , reparse+ -- * Re-export all more general combinators+ , module Text.ParserCombinators.Poly.Base+ , module Control.Applicative+ ) where+++import Text.ParserCombinators.Poly.Base+import Text.ParserCombinators.Poly.Result+import qualified Data.Text.Lazy as T+import Data.Text.Lazy (Text)+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 Text input only.+newtype Parser s a = P (s -> Text -> Result (Text,s) a)++-- | Apply a parser to an input token sequence.+runParser :: Parser s a -> s -> Text -> (Either String a, s, Text)+runParser (P p) = \s -> reTuple . resultToEither . p s+ where+ reTuple (either, (z,s)) = (either, s, z)++instance Functor (Parser s) where+ fmap f (P p) = P (\s-> fmap f . p s)++instance Monad (Parser s) where+ return x = P (\s ts-> Success (ts,s) x)+ fail e = P (\s ts-> Failure (ts,s) e)+ (P f) >>= g = P (\s-> continue . f s)+ where+ continue (Success (ts,s) x) = let (P g') = g x in g' s ts+ continue (Committed (Committed r)) = continue (Committed r)+ continue (Committed r) = Committed (continue r)+ continue (Failure ts e) = Failure ts e++instance Commitment (Parser s) where+ commit (P p) = P (\s-> Committed . p s)+ (P p) `adjustErr` f = P (\s-> adjust . p s)+ 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 (\s ts-> case p s ts of+ Failure _ err ->+ let (P p') = accum ((e,err):errs) ps+ in p' s ts+ r@(Success _ _) -> r+ r@(Committed _) -> r )+ showErr (name,err) = name++":\n"++indent 2 err++instance Applicative (Parser s) 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 s) where+ empty = fail "no parse"+ p <|> q = p `onFail` q++instance PolyParse (Parser s)++------------------------------------------------------------------------++-- | Simply return the next token in the input tokenstream.+next :: Parser s Char+next = P (\s bs-> case T.uncons bs of+ Nothing -> Failure (bs,s) "Ran out of input (EOF)"+ Just (c, bs') -> Success (bs',s) c )++-- | Succeed if the end of file/input has been reached, fail otherwise.+eof :: Parser s ()+eof = P (\s bs -> if T.null bs+ then Success (bs,s) ()+ else Failure (bs,s) "Expected end of input (EOF)" )++-- | Return the next token if it satisfies the given predicate.+satisfy :: (Char -> Bool) -> Parser s 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 s a -> Parser s a -> Parser s a+(P p) `onFail` (P q) = P (\s ts-> continue s ts $ p s ts)+ where continue s ts (Failure _ _) = q s 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 s Text+manySatisfy f = P (\s bs-> let (pre,suf) = T.span f bs in Success (suf,s) pre)++-- | @many1Satisfy p@ is a more efficient fused version of @many1 (satisfy p)@+many1Satisfy :: (Char->Bool) -> Parser s Text+many1Satisfy f = do x <- manySatisfy f+ if T.null x then fail "Parse.many1Satisfy: failed"+ else return x++------------------------------------------------------------------------+-- State handling++-- | Update the internal state.+stUpdate :: (s->s) -> Parser s ()+stUpdate f = P (\s bs-> Success (bs, f s) ())++-- | Query the internal state.+stQuery :: (s->a) -> Parser s a+stQuery f = P (\s bs-> Success (bs,s) (f s))++-- | Deliver the entire internal state.+stGet :: Parser s s+stGet = P (\s bs-> Success (bs,s) s)++------------------------------------------------------------------------++-- | 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 :: Text -> Parser s ()+reparse ts = P (\s inp-> Success (ts `T.append` inp,s) ())++------------------------------------------------------------------------
+ src/Text/ParserCombinators/Poly/Text.hs view
@@ -0,0 +1,138 @@+module Text.ParserCombinators.Poly.Text+ ( -- * 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+ , module Control.Applicative+ ) where+++import Text.ParserCombinators.Poly.Base+import Text.ParserCombinators.Poly.Result+import qualified Data.Text.Lazy as T+import Data.Text.Lazy (Text)+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 Text input only.+newtype Parser a = P (Text -> Result Text a)++-- | Apply a parser to an input token sequence.+runParser :: Parser a -> Text -> (Either String a, Text)+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 T.uncons bs of+ Nothing -> Failure bs "Ran out of input (EOF)"+ Just (c, bs') -> Success bs' c )++-- | Succeed if the end of file/input has been reached, fail otherwise.+eof :: Parser ()+eof = P (\bs -> if T.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 Text+manySatisfy f = P (\bs-> let (pre,suf) = T.span f bs in Success suf pre)++-- | @many1Satisfy p@ is a more efficient fused version of @many1 (satisfy p)@+many1Satisfy :: (Char->Bool) -> Parser Text+many1Satisfy f = do x <- manySatisfy f+ if T.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 :: Text -> Parser ()+reparse ts = P (\inp-> Success (ts `T.append` inp) ())++------------------------------------------------------------------------