mirror of
https://github.com/mrkkrp/megaparsec.git
synced 2024-11-27 15:32:14 +03:00
added new parser ‘string'’
This is like ‘string’, but is case-insensitive.
This commit is contained in:
parent
183c996e6a
commit
6ac08b0956
@ -120,6 +120,9 @@
|
|||||||
* `sepEndBy`
|
* `sepEndBy`
|
||||||
* `sepEndBy1`
|
* `sepEndBy1`
|
||||||
|
|
||||||
|
* Added combinator `string'` which is the same as `string`, but
|
||||||
|
case-insensitive.
|
||||||
|
|
||||||
* Added comprehensive QuickCheck test suite.
|
* Added comprehensive QuickCheck test suite.
|
||||||
|
|
||||||
* Added benchmarks.
|
* Added benchmarks.
|
||||||
|
@ -121,6 +121,7 @@ module Text.Megaparsec
|
|||||||
, noneOf
|
, noneOf
|
||||||
, satisfy
|
, satisfy
|
||||||
, string
|
, string
|
||||||
|
, string'
|
||||||
-- * Error messages
|
-- * Error messages
|
||||||
, Message (..)
|
, Message (..)
|
||||||
, messageString
|
, messageString
|
||||||
|
@ -41,7 +41,8 @@ module Text.Megaparsec.Char
|
|||||||
, oneOf
|
, oneOf
|
||||||
, noneOf
|
, noneOf
|
||||||
, satisfy
|
, satisfy
|
||||||
, string )
|
, string
|
||||||
|
, string' )
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
@ -276,4 +277,14 @@ satisfy f = token nextPos testChar
|
|||||||
-- > divOrMod = string "div" <|> string "mod"
|
-- > divOrMod = string "div" <|> string "mod"
|
||||||
|
|
||||||
string :: Stream s m Char => String -> ParsecT s u m String
|
string :: Stream s m Char => String -> ParsecT s u m String
|
||||||
string = tokens updatePosString
|
string = tokens updatePosString (==)
|
||||||
|
|
||||||
|
-- | The same as 'string', but case-insensitive. On success returns string
|
||||||
|
-- cased as argument of the function.
|
||||||
|
--
|
||||||
|
-- >>> parseTest (string' "foobar") "foObAr"
|
||||||
|
-- "foobar"
|
||||||
|
|
||||||
|
string' :: Stream s m Char => String -> ParsecT s u m String
|
||||||
|
string' = tokens updatePosString test
|
||||||
|
where test x y = toLower x == toLower y
|
||||||
|
@ -582,37 +582,38 @@ token nextpos test = ParsecT $ \(State input pos u) cok _ _ eerr -> do
|
|||||||
in seq newpos $ seq newstate $ cok x newstate mempty
|
in seq newpos $ seq newstate $ cok x newstate mempty
|
||||||
Nothing -> eerr $ unexpectedErr (showToken c) pos
|
Nothing -> eerr $ unexpectedErr (showToken c) pos
|
||||||
|
|
||||||
-- | The parser @tokens posFromTok@ parses list of tokens and returns
|
-- | The parser @tokens posFromTok test@ parses list of tokens and returns
|
||||||
-- it. The resulting parser will use 'showToken' to pretty-print the
|
-- it. The resulting parser will use 'showToken' to pretty-print the
|
||||||
-- collection of tokens.
|
-- collection of tokens. Supplied predicate @test@ is used to check equality
|
||||||
|
-- of given and parsed tokens.
|
||||||
--
|
--
|
||||||
-- This can be used to example to write 'Text.Megaparsec.Char.string':
|
-- This can be used to example to write 'Text.Megaparsec.Char.string':
|
||||||
--
|
--
|
||||||
-- > string = tokens updatePosString
|
-- > string = tokens updatePosString (==)
|
||||||
|
|
||||||
tokens :: (Stream s m t, Eq t, ShowToken [t]) =>
|
tokens :: (Stream s m t, Eq t, ShowToken [t]) =>
|
||||||
(SourcePos -> [t] -> SourcePos) -- ^ Computes position of tokens.
|
(SourcePos -> [t] -> SourcePos) -- ^ Computes position of tokens.
|
||||||
-> [t] -- ^ List of tokens to parse
|
-> (t -> t -> Bool) -- ^ Predicate to check equality of tokens.
|
||||||
|
-> [t] -- ^ List of tokens to parse
|
||||||
-> ParsecT s u m [t]
|
-> ParsecT s u m [t]
|
||||||
{-# INLINE tokens #-}
|
{-# INLINE tokens #-}
|
||||||
tokens _ [] = ParsecT $ \s _ _ eok _ -> eok [] s mempty
|
tokens _ _ [] = ParsecT $ \s _ _ eok _ -> eok [] s mempty
|
||||||
tokens nextposs tts = ParsecT $ \(State input pos u) cok cerr _ eerr ->
|
tokens nextpos test tts = ParsecT $ \(State input pos u) cok cerr _ eerr ->
|
||||||
let errExpect x = setErrorMessage (Expected $ showToken tts)
|
let errExpect x = setErrorMessage (Expected $ showToken tts)
|
||||||
(newErrorMessage (Unexpected x) pos)
|
(newErrorMessage (Unexpected x) pos)
|
||||||
walk [] _ rs = let pos' = nextposs pos tts
|
walk [] _ rs = let pos' = nextpos pos tts
|
||||||
s' = State rs pos' u
|
s' = State rs pos' u
|
||||||
in cok tts s' mempty
|
in cok tts s' mempty
|
||||||
walk (t:ts) i rs = do
|
walk (t:ts) is rs = do
|
||||||
sr <- uncons rs
|
sr <- uncons rs
|
||||||
let errorCont = if i == 0 then eerr else cerr
|
let errorCont = if null is then eerr else cerr
|
||||||
what = bool (showToken $ take i tts) "end of input" (i == 0)
|
what = bool (showToken $ reverse is) "end of input" (null is)
|
||||||
case sr of
|
case sr of
|
||||||
Nothing -> errorCont . errExpect $ what
|
Nothing -> errorCont . errExpect $ what
|
||||||
Just (x,xs)
|
Just (x,xs)
|
||||||
| t == x -> walk ts (succ i) xs
|
| test t x -> walk ts (x:is) xs
|
||||||
| otherwise -> errorCont . errExpect . showToken $
|
| otherwise -> errorCont . errExpect . showToken $ reverse (x:is)
|
||||||
take i tts ++ [x]
|
in walk tts [] input
|
||||||
in walk tts 0 input
|
|
||||||
|
|
||||||
unexpectedErr :: String -> SourcePos -> ParseError
|
unexpectedErr :: String -> SourcePos -> ParseError
|
||||||
unexpectedErr msg = newErrorMessage (Unexpected msg)
|
unexpectedErr msg = newErrorMessage (Unexpected msg)
|
||||||
|
@ -71,7 +71,8 @@ tests = testGroup "Character parsers"
|
|||||||
, testProperty "anyChar" prop_anyChar
|
, testProperty "anyChar" prop_anyChar
|
||||||
, testProperty "oneOf" prop_oneOf
|
, testProperty "oneOf" prop_oneOf
|
||||||
, testProperty "noneOf" prop_noneOf
|
, testProperty "noneOf" prop_noneOf
|
||||||
, testProperty "string" prop_string ]
|
, testProperty "string" prop_string
|
||||||
|
, testProperty "string'" prop_string' ]
|
||||||
|
|
||||||
instance Arbitrary GeneralCategory where
|
instance Arbitrary GeneralCategory where
|
||||||
arbitrary = elements
|
arbitrary = elements
|
||||||
@ -110,7 +111,7 @@ prop_newline :: String -> Property
|
|||||||
prop_newline = checkChar newline (== '\n') (Just "newline")
|
prop_newline = checkChar newline (== '\n') (Just "newline")
|
||||||
|
|
||||||
prop_crlf :: String -> Property
|
prop_crlf :: String -> Property
|
||||||
prop_crlf = checkString crlf "\r\n" "crlf newline"
|
prop_crlf = checkString crlf "\r\n" (==) "crlf newline"
|
||||||
|
|
||||||
prop_eol :: String -> Property
|
prop_eol :: String -> Property
|
||||||
prop_eol s = checkParser eol r s
|
prop_eol s = checkParser eol r s
|
||||||
@ -211,4 +212,8 @@ prop_noneOf :: String -> String -> Property
|
|||||||
prop_noneOf a = checkChar (noneOf a) (`notElem` a) Nothing
|
prop_noneOf a = checkChar (noneOf a) (`notElem` a) Nothing
|
||||||
|
|
||||||
prop_string :: String -> String -> Property
|
prop_string :: String -> String -> Property
|
||||||
prop_string a = checkString (string a) a (showToken a)
|
prop_string a = checkString (string a) a (==) (showToken a)
|
||||||
|
|
||||||
|
prop_string' :: String -> String -> Property
|
||||||
|
prop_string' a = checkString (string' a) a test (showToken a)
|
||||||
|
where test x y = toLower x == toLower y
|
||||||
|
@ -325,8 +325,8 @@ prop_token s = checkParser p r s
|
|||||||
| otherwise = posErr 0 s [uneCh h]
|
| otherwise = posErr 0 s [uneCh h]
|
||||||
|
|
||||||
prop_tokens :: String -> String -> Property
|
prop_tokens :: String -> String -> Property
|
||||||
prop_tokens a = checkString p a (showToken a)
|
prop_tokens a = checkString p a (==) (showToken a)
|
||||||
where p = tokens updatePosString a
|
where p = tokens updatePosString (==) a
|
||||||
|
|
||||||
-- Parser state combinators
|
-- Parser state combinators
|
||||||
|
|
||||||
|
@ -89,18 +89,20 @@ checkChar p f l' s = checkParser p r s
|
|||||||
| not (f h) = posErr 0 s (uneCh h : l)
|
| not (f h) = posErr 0 s (uneCh h : l)
|
||||||
| otherwise = posErr 1 s [uneCh (s !! 1), exEof]
|
| otherwise = posErr 1 s [uneCh (s !! 1), exEof]
|
||||||
|
|
||||||
-- | @checkString p a label s@ runs parser @p@ on input @s@ and checks if
|
-- | @checkString p a test label s@ runs parser @p@ on input @s@ and checks if
|
||||||
-- the result is equal to @a@ and also quality of error messages. @label@ is
|
-- the result is equal to @a@ and also quality of error messages. @test@ is
|
||||||
-- used as expected representation of parser's result in error messages.
|
-- used to compare tokens. @label@ is used as expected representation of
|
||||||
|
-- parser's result in error messages.
|
||||||
|
|
||||||
checkString :: Parser String -> String -> String -> String -> Property
|
checkString :: Parser String -> String -> (Char -> Char -> Bool) ->
|
||||||
checkString p a' l s' = checkParser p (w a' 0 s') s'
|
String -> String -> Property
|
||||||
|
checkString p a' test l s' = checkParser p (w a' 0 s') s'
|
||||||
where w [] _ [] = Right a'
|
where w [] _ [] = Right a'
|
||||||
w [] i (s:_) = posErr i s' [uneCh s, exEof]
|
w [] i (s:_) = posErr i s' [uneCh s, exEof]
|
||||||
w _ 0 [] = posErr 0 s' [uneEof, exSpec l]
|
w _ 0 [] = posErr 0 s' [uneEof, exSpec l]
|
||||||
w _ i [] = posErr 0 s' [uneStr (take i s'), exSpec l]
|
w _ i [] = posErr 0 s' [uneStr (take i s'), exSpec l]
|
||||||
w (a:as) i (s:ss)
|
w (a:as) i (s:ss)
|
||||||
| a == s = w as i' ss
|
| test a s = w as i' ss
|
||||||
| otherwise = posErr 0 s' [uneStr (take i' s'), exSpec l]
|
| otherwise = posErr 0 s' [uneStr (take i' s'), exSpec l]
|
||||||
where i' = succ i
|
where i' = succ i
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user