JustParse 2.0 → 2.1
raw patch · 7 files changed
+246/−52 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.JustParse.Combinator: manyTill :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: takeWhile1 :: Stream s t => (t -> Bool) -> Parser s [t]
+ Data.JustParse.Combinator: takeWhile1_ :: Stream s t => (t -> Bool) -> Parser s [t]
+ Data.JustParse.Combinator: try :: Stream s t => Parser s a -> Parser s a
+ Data.JustParse.Numeric: decDigit :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: hexDigit :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: unsignedDecInt :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: unsignedDecInt_ :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: unsignedHexInt :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: unsignedHexInt_ :: Stream s Char => Parser s Int
Files
- JustParse.cabal +2/−2
- src/Data/JustParse.hs +1/−1
- src/Data/JustParse/Char.hs +19/−1
- src/Data/JustParse/Combinator.hs +84/−3
- src/Data/JustParse/Internal.hs +21/−1
- src/Data/JustParse/Language.hs +19/−0
- src/Data/JustParse/Numeric.hs +100/−44
JustParse.cabal view
@@ -1,5 +1,5 @@ name: JustParse-version: 2.0+version: 2.1 synopsis: A simple and comprehensive Haskell parsing library description: A simple and comprehensive Haskell parsing library homepage: https://github.com/grantslatton/JustParse@@ -25,4 +25,4 @@ base >= 4.2 && < 5 hs-source-dirs: src extensions: MultiParamTypeClasses, Rank2Types, FlexibleInstances, FlexibleContexts, Safe, TupleSections, UndecidableInstances- ghc-options: -O2 -Wall+ ghc-options: -O2
src/Data/JustParse.hs view
@@ -8,7 +8,7 @@ Portability : portable -} ---{-# LANGUAGE Safe #-}+{-# LANGUAGE Safe #-} module Data.JustParse ( -- * Overview -- $overview
src/Data/JustParse/Char.hs view
@@ -10,7 +10,7 @@ Several useful parsers for dealing with 'String's. -} ---{-# LANGUAGE Safe #-}+{-# LANGUAGE Safe #-} module Data.JustParse.Char ( char, anyChar,@@ -40,74 +40,92 @@ -- | Parse a specic char. char :: Stream s Char => Char -> Parser s Char char = token+{-# INLINE char #-} -- | Parse any char. anyChar :: Stream s Char => Parser s Char anyChar = anyToken+{-# INLINE anyChar #-} -- | Parse a specific char, ignoring case. caseInsensitiveChar :: Stream s Char => Char -> Parser s Char caseInsensitiveChar c = char (toUpper c) <|> char (toLower c)+{-# INLINE caseInsensitiveChar #-} -- | Parse any char that is ASCII. ascii :: Stream s Char => Parser s Char ascii = satisfy isAscii+{-# INLINE ascii #-} -- | Parse any char that is Latin-1. latin1 :: Stream s Char => Parser s Char latin1 = satisfy isLatin1+{-# INLINE latin1 #-} -- | Parse a control character. control :: Stream s Char => Parser s Char control = satisfy isControl+{-# INLINE control #-} -- | Parse a space. space :: Stream s Char => Parser s Char space = satisfy isSpace+{-# INLINE space #-} -- | Parse a lowercase character. lower :: Stream s Char => Parser s Char lower = satisfy isLower+{-# INLINE lower #-} -- | Parse an uppercase character. upper :: Stream s Char => Parser s Char upper = satisfy isUpper+{-# INLINE upper #-} -- | Parse an alphabetic character. alpha :: Stream s Char => Parser s Char alpha = satisfy isAlpha+{-# INLINE alpha #-} -- | Parse an alphanumeric character. alphaNum :: Stream s Char => Parser s Char alphaNum = satisfy isAlphaNum+{-# INLINE alphaNum #-} -- | Parse a printable (non-control) character. print :: Stream s Char => Parser s Char print = satisfy isPrint+{-# INLINE print #-} -- | Parse a digit. digit :: Stream s Char => Parser s Char digit = satisfy isDigit+{-# INLINE digit #-} -- | Parse an octal digit. octDigit :: Stream s Char => Parser s Char octDigit = satisfy isOctDigit+{-# INLINE octDigit #-} -- | Parse a hexadeciaml digit. hexDigit :: Stream s Char => Parser s Char hexDigit = satisfy isHexDigit+{-# INLINE hexDigit #-} -- | Parse a specific string. string :: Stream s Char => String -> Parser s String string = mapM char +{-# INLINE string #-} -- | Parse a specfic string, ignoring case. caseInsensitiveString :: Stream s Char => String -> Parser s String caseInsensitiveString = mapM caseInsensitiveChar +{-# INLINE caseInsensitiveString #-} -- | Parses until a newline, carriage return + newline, or newline + carriage return. eol :: Stream s Char => Parser s String eol = choice [string "\r\n", string "\n\r", string "\n"]+{-# INLINE eol #-} -- | Makes common types such as 'String's into a Stream. instance Eq t => Stream [t] t where
src/Data/JustParse/Combinator.hs view
@@ -10,8 +10,7 @@ The bread and butter of combinatory parsing. -} ---{-# LANGUAGE Safe #-}---{-# LANGUAGE TupleSections #-}+{-# LANGUAGE Safe #-} module Data.JustParse.Combinator ( -- * Utility Parsers assert,@@ -24,6 +23,7 @@ option, optional, test,+ try, (<|>), -- * Token Parsers@@ -44,6 +44,7 @@ exactly, many, many1,+ manyTill, mN, sepBy, sepBy1,@@ -52,6 +53,7 @@ sepEndBy, sepEndBy1, takeWhile,+ takeWhile1, -- * Group Parsers choice,@@ -82,7 +84,8 @@ sepEndBy1_, skipMany_, skipMany1_,- takeWhile_+ takeWhile_,+ takeWhile1_ ) where import Prelude hiding ( print, length, takeWhile )@@ -104,58 +107,82 @@ Just s' -> case uncons s' of Nothing -> [Partial $ parse (satisfy f)] Just (x, xs) -> [Done x (Just xs) | f x]+{-# INLINE satisfy #-} -- | A parser that succeeds on 'True' and fails on 'False'. guard :: Stream s t => Bool -> Parser s () guard = M.guard+{-# INLINE guard #-} -- | Synonym of 'guard'. assert :: Stream s t => Bool -> Parser s () assert = guard+{-# INLINE assert #-} -- | Only succeeds when supplied with 'Nothing'. eof :: Stream s t => Parser s () eof = notFollowedBy anyToken+{-# INLINE eof #-} -- | Parse a token that is a member of the list of tokens. oneOf :: (Eq t, Stream s t) => [t] -> Parser s t oneOf ts = satisfy (`elem` ts)+{-# INLINE oneOf #-} -- | Parse a token that is not a member of the list of tokens. noneOf :: (Eq t, Stream s t) => [t] -> Parser s t noneOf ts = satisfy (`notElem` ts)+{-# INLINE noneOf #-} -- | Parse a specific token. token :: (Eq t, Stream s t) => t -> Parser s t token t = satisfy (==t)+{-# INLINE token #-} -- | Parse any token. anyToken :: Stream s t => Parser s t anyToken = satisfy (const True)+{-# INLINE anyToken #-} -- | Parse tokens while a predicate remains true. takeWhile :: Stream s t => (t -> Bool) -> Parser s [t] takeWhile = many . satisfy+{-# INLINE takeWhile #-} +-- | Parse one or more tokens while a predicate remains true.+takeWhile1 :: Stream s t => (t -> Bool) -> Parser s [t]+takeWhile1 = many1 . satisfy+{-# INLINE takeWhile1 #-}+ -- | Branches every iteration where one branch stops and one branch -- continues. takeWhile_ :: Stream s t => (t -> Bool) -> Parser s [t] takeWhile_ = many_ . satisfy+{-# INLINE takeWhile_ #-} +-- | Branches every iteration where one branch stops and one branch +-- continues.+takeWhile1_ :: Stream s t => (t -> Bool) -> Parser s [t]+takeWhile1_ = many1_ . satisfy+{-# INLINE takeWhile1_ #-}+ -- | Splits the current parse branch between the two parsers. branch :: Parser s a -> Parser s a -> Parser s a branch a b = Parser $ \s -> parse a s ++ parse b s+{-# INLINE branch #-} infixr 1 <||> -- | Infix version of 'branch'. (<||>) :: Parser s a -> Parser s a -> Parser s a (<||>) = branch+{-# INLINE (<||>) #-} -- | @mN m n p@ parses between @m@ and @n@ occurences of @p@, inclusive. mN :: Stream s t => Int -> Int -> Parser s a -> Parser s [a] mN _ 0 _ = Parser $ \s -> [Done [] s] mN 0 n p = M.liftM2 (:) p (mN 0 (n-1) p) A.<|> return [] mN m n p = M.liftM2 (:) p (mN (m-1) (n-1) p)+{-# INLINE mN #-} -- | Branches every iteration where one branch stops and one branch -- continues.@@ -163,46 +190,56 @@ mN_ _ 0 _ = Parser $ \s -> [Done [] s] mN_ 0 n p = M.liftM2 (:) p (mN 0 (n-1) p) <||> return [] mN_ m n p = M.liftM2 (:) p (mN (m-1) (n-1) p)+{-# INLINE mN_ #-} -- | Synonym of 'count'. exactly :: Stream s t => Int -> Parser s a -> Parser s [a] exactly n = mN n n+{-# INLINE exactly #-} -- | Applies a parser at least @n@ times. atLeast :: Stream s t => Int -> Parser s a -> Parser s [a] atLeast n = mN n (-1)+{-# INLINE atLeast #-} -- | Branches every iteration where one branch stops and one branch -- continues. atLeast_ :: Stream s t => Int -> Parser s a -> Parser s [a] atLeast_ n = mN_ n (-1)+{-# INLINE atLeast_ #-} -- | Applies a parser at most @n@ times. atMost :: Stream s t => Int -> Parser s a -> Parser s [a] atMost = mN 0+{-# INLINE atMost #-} -- | Branches every iteration where one branch stops and one branch -- continues. atMost_ :: Stream s t => Int -> Parser s a -> Parser s [a] atMost_ = mN 0+{-# INLINE atMost_ #-} -- | Applies a parser zero or more times. many :: Stream s t => Parser s a -> Parser s [a] many = A.many+{-# INLINE many #-} -- | Branches every iteration where one branch stops and one branch -- continues. many_ :: Parser s a -> Parser s [a] many_ p = return [] <||> M.liftM2 (:) p (many_ p)+{-# INLINE many_ #-} -- | Applies a parser one or more times. many1 :: Stream s t => Parser s a -> Parser s [a] many1 p = M.liftM2 (:) p (many p)+{-# INLINE many1 #-} -- | Branches every iteration where one branch stops and one branch -- continues. many1_ :: Parser s a -> Parser s [a] many1_ p = M.liftM2 (:) p (many_ p)+{-# INLINE many1_ #-} -- | Return 'True' if the parser would succeed if one were to apply it, -- otherwise, it returns 'False'. It does not consume input.@@ -213,31 +250,37 @@ case a of Nothing -> return False _ -> return True+{-# INLINE test #-} infixr 1 <|> -- | @a \<|\> b@ is equivalent to @'choice' [a,b]@. That is, first @a@ is -- tried, and if it yields no results, @b@ is tried. (<|>) :: Stream s t => Parser s a -> Parser s a -> Parser s a (<|>) = (A.<|>)+{-# INLINE (<|>) #-} -- | Attempt to apply each parser in the list in order until one succeeds. choice :: Stream s t => [Parser s a] -> Parser s a choice = foldl1' (A.<|>) +{-# INLINE choice #-} -- | Given a list of parsers, split off a branch for each one. choice_ :: Stream s t => [Parser s a] -> Parser s a choice_ = foldl1' (<||>)+{-# INLINE choice_ #-} -- | Like 'choice', but returns the index of the successful parser as well -- as the result. select :: Stream s t => [Parser s a] -> Parser s (Int, a) select [] = M.mzero select (p:ps) = M.liftM (0,) p <|> M.liftM (\(x,y) -> (x+1,y)) (select ps)+{-# INLINE select #-} -- | Like 'choice_', but returns the index of the successful parser. select_ :: Stream s t => [Parser s a] -> Parser s (Int, a) select_ [] = M.mzero select_ (p:ps) = M.liftM (0,) p <||> M.liftM (\(x,y) -> (x+1,y)) (select_ ps)+{-# INLINE select_ #-} -- | Modifies a parser so that it will ony return the most consumptive -- succesful results. @@ -250,6 +293,7 @@ g xs | all isDone xs = [minimumBy (comparing (f . leftover)) xs] | otherwise = [Partial $ \s -> g $ extend s xs] +{-# INLINE greedy #-} -- | Attempts to apply a parser and returns a default value if it fails. option :: Stream s t => a -> Parser s a -> Parser s a@@ -259,39 +303,47 @@ case r of Nothing -> return v Just v' -> return v'+{-# INLINE option #-} -- | Splits off two branches, one where the parse is attempted, and one -- where it is not. option_ :: Stream s t => a -> Parser s a -> Parser s a option_ v p = option v p <||> return v+{-# INLINE option_ #-} -- | Attempts to apply the parser, returning 'Nothing' upon failure, or -- the result wrapped in a 'Just'. optional :: Stream s t => Parser s a -> Parser s (Maybe a) optional = A.optional+{-# INLINE optional #-} -- | Splits off two branches, one where the parse is attempted, and one -- where it is not. optional_ :: Stream s t => Parser s a -> Parser s (Maybe a) optional_ p = M.liftM Just p <||> return Nothing+{-# INLINE optional_ #-} -- | @sepBy1 p s@ parses many occurences of @p@ separated by @s@. sepBy :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepBy p s = sepBy1 p s A.<|> return []+{-# INLINE sepBy #-} -- | Branches every iteration where one branch stops and one branch -- continues. sepBy_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepBy_ p s = sepBy1_ p s <||> return []+{-# INLINE sepBy_ #-} -- | @sepBy1 p s@ parses one or more occurences of @p@ separated by @s@. sepBy1 :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepBy1 p s = M.liftM2 (:) p (many (s >> p))+{-# INLINE sepBy1 #-} -- | Branches every iteration where one branch stops and one branch -- continues. sepBy1_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepBy1_ p s = M.liftM2 (:) p (many_ (s >> p))+{-# INLINE sepBy1_ #-} -- | Applies the parser and returns its result, but resets -- the 'Stream' as if it consumed nothing.@@ -305,79 +357,95 @@ _ -> parse (lookAhead v) (streamAppend s s') in map g (p s)+{-# INLINE lookAhead #-} -- | @count n p@ parses exactly @n@ occurences of @p@. count :: Stream s t => Int -> Parser s a -> Parser s [a] count = exactly+{-# INLINE count #-} -- | Identical to 'many' except the result is discarded. skipMany :: Stream s t => Parser s a -> Parser s () skipMany = M.void . many+{-# INLINE skipMany #-} -- | Branches every iteration where one branch stops and one branch -- continues. skipMany_ :: Stream s t => Parser s a -> Parser s () skipMany_ = M.void . many_+{-# INLINE skipMany_ #-} -- | Identical to 'many1' except the result is discarded. skipMany1 :: Stream s t => Parser s a -> Parser s () skipMany1 = M.void . many1+{-# INLINE skipMany1 #-} -- | Branches every iteration where one branch stops and one branch -- continues. skipMany1_ :: Stream s t => Parser s a -> Parser s () skipMany1_ = M.void . many1_+{-# INLINE skipMany1_ #-} -- | @endBy p s@ parses multiple occurences of @p@ separated and ended by -- @s@. endBy :: Stream s t => Parser s a -> Parser s b -> Parser s [a] endBy p s = many (p A.<* s)+{-# INLINE endBy #-} -- | Branches every iteration where one branch stops and one branch -- continues. endBy_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a] endBy_ p s = many_ (p A.<* s)+{-# INLINE endBy_ #-} -- | @endBy1 p s@ parses one or more occurences of @p@ separated and ended -- by @s@. endBy1 :: Stream s t => Parser s a -> Parser s b -> Parser s [a] endBy1 p s = many1 (p A.<* s)+{-# INLINE endBy1 #-} -- | Branches every iteration where one branch stops and one branch -- continues. endBy1_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a] endBy1_ p s = many1_ (p A.<* s)+{-# INLINE endBy1_ #-} -- | @sepEndBy p s@ parses multiple occurences of @p@ separated and -- optionally ended by @s@. sepEndBy :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepEndBy p s = sepBy p s A.<* optional s+{-# INLINE sepEndBy #-} -- | Branches every iteration where one branch stops and one branch -- continues. sepEndBy_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepEndBy_ p s = sepBy_ p s A.<* optional s+{-# INLINE sepEndBy_ #-} -- | @sepEndBy p s@ parses one or more occurences of @p@ separated and -- optionally ended by @s@. sepEndBy1 :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepEndBy1 p s = sepBy1 p s A.<* optional s+{-# INLINE sepEndBy1 #-} -- | Branches every iteration where one branch stops and one branch -- continues. sepEndBy1_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a] sepEndBy1_ p s = sepBy1_ p s A.<* optional s+{-# INLINE sepEndBy1_ #-} -- | @chainr p o x@ parses zero or more occurences of @p@ separated by @o@. -- The result is the left associative application of the functions to the -- values. If @p@ succeeds zero times, @x@ is returned. chainl :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a chainl p o x = chainl1 p o <|> return x+{-# INLINE chainl #-} -- | Branches every iteration where one branch stops and one branch -- continues. chainl_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a chainl_ p o x = chainl1_ p o <||> return x+{-# INLINE chainl_ #-} -- | Like 'chainl', but a minimum of one occurence of @p@ must be parsed. chainl1 :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a@@ -389,6 +457,7 @@ y <- p f (g x y) <|> return x+{-# INLINE chainl1 #-} -- | Branches every iteration where one branch stops and one branch -- continues.@@ -401,15 +470,18 @@ y <- p f (g x y) <||> return x+{-# INLINE chainl1_ #-} -- | Like 'chainl', but right associative. chainr :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a chainr p o x = chainr1 p o <|> return x+{-# INLINE chainr #-} -- | Branches every iteration where one branch stops and one branch -- continues. chainr_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a chainr_ p o x = chainr1_ p o <||> return x+{-# INLINE chainr_ #-} -- | Like 'chainl1', but right associative. chainr1 :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a@@ -421,6 +493,7 @@ y <- chainr1 p o return (g x y) <|> return x+{-# INLINE chainr1 #-} -- | Branches every iteration where one branch stops and one branch -- continues.@@ -433,10 +506,12 @@ y <- chainr1_ p o return (g x y) <||> return x+{-# INLINE chainr1_ #-} -- | Only succeeds when the given parser fails. Consumes no input. notFollowedBy :: Stream s t => Parser s a -> Parser s () notFollowedBy p = test p >>= assert . not+{-# INLINE notFollowedBy #-} -- | @manyTill a b@ parses multiple occurences of @a@ until @b@ would -- succeed if tried.@@ -447,19 +522,23 @@ if b then return [] else M.liftM2 (:) p (manyTill p e)+{-# INLINE manyTill #-} -- | Does nothing -- only used for @Parsec@ compatability. try :: Stream s t => Parser s a -> Parser s a try = id+{-# INLINE try #-} -- | @eitherP a b@ returns the result wrapped in a 'Left' if @a@ succeeds or -- a 'Right' if @b@ succeeds eitherP :: Stream s t => Parser s a -> Parser s b -> Parser s (Either a b) eitherP a b = M.liftM Left a <|> M.liftM Right b+{-# INLINE eitherP #-} -- | Like 'eitherP', but tries both @a@ and @b@. eitherP_ :: Stream s t => Parser s a -> Parser s b -> Parser s (Either a b) eitherP_ a b = M.liftM Left a <||> M.liftM Right b+{-# INLINE eitherP_ #-} -- | Parses a sequence of parsers in any order. perm :: Stream s t => [Parser s a] -> Parser s [a]@@ -468,6 +547,7 @@ do (i, r) <- select ps M.liftM (r:) (perm (let (a,b) = splitAt i ps in a ++ tail b)) +{-# INLINE perm #-} -- | Parses a sequence of parsers in all possible orders. perm_ :: Stream s t => [Parser s a] -> Parser s [a]@@ -476,3 +556,4 @@ do (i, r) <- select_ ps M.liftM (r:) (perm_ (let (a,b) = splitAt i ps in a ++ tail b)) +{-# INLINE perm_ #-}
src/Data/JustParse/Internal.hs view
@@ -14,7 +14,7 @@ {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FunctionalDependencies #-}---{-# LANGUAGE Safe #-}+{-# LANGUAGE Safe #-} module Data.JustParse.Internal ( Stream (..),@@ -59,28 +59,38 @@ instance Stream s t => Monoid (Parser s a) where mempty = mzero+ {-# INLINE mempty #-} mappend = mplus+ {-# INLINE mappend #-} instance Functor (Parser s) where fmap f (Parser p) = Parser $ map (fmap f) . p + {-# INLINE fmap #-} instance Applicative (Parser s) where pure = return + {-# INLINE pure #-} (<*>) = ap+ {-# INLINE (<*>) #-} instance Stream s t => Alternative (Parser s) where empty = mzero+ {-# INLINE empty #-} (<|>) = mplus+ {-# INLINE (<|>) #-} instance Monad (Parser s) where return v = Parser $ \s -> [Done v s] + {-# INLINE return #-} (Parser p) >>= f = Parser $ p >=> g where g (Done a s) = parse (f a) s g (Partial p) = [Partial $ p >=> g] + {-# INLINE (>>=) #-} instance Stream s t => MonadPlus (Parser s) where mzero = Parser $ const []+ {-# INLINE mzero #-} mplus a b = Parser $ \s -> let g [] = parse b s@@ -101,6 +111,7 @@ in g (parse a s) + {-# INLINE mplus #-} data Result s a -- | A @Partial@ wraps the same function as a Parser. Supply it with @@ -121,28 +132,35 @@ isDone :: Result s a -> Bool isDone (Done _ _) = True isDone _ = False+{-# INLINE isDone #-} isPartial :: Result s a -> Bool isPartial (Partial _) = True isPartial _ = False+{-# INLINE isPartial #-} -- | Lifts a parser into the result space toPartial :: Parser s a -> [Result s a] toPartial (Parser p) = [Partial p]+{-# INLINE toPartial #-} instance Functor (Result s) where fmap f (Partial p) = Partial $ map (fmap f) . p fmap f (Done a s) = Done (f a) s+ {-# INLINE fmap #-} + instance Show a => Show (Result s a) where show (Partial _) = "Partial" show (Done a _) = show a+ {-# INLINE show #-} -- | @finalize@ takes a list of results (presumably returned from a -- 'Parser' or 'Partial', and supplies 'Nothing' to any remaining 'Partial' -- values, so that only 'Done' values remain. finalize :: (Eq s, Monoid s) => [Result s a] -> [Result s a] finalize = extend Nothing+{-# INLINE finalize #-} -- | @extend@ takes a @'Maybe' s@ as input, and supplies the input to all -- values in the 'Result' list. For 'Done' values, it appends @@ -153,8 +171,10 @@ where g (Partial p) = p s g (Done a s') = [Done a (streamAppend s' s)]+{-# INLINE extend #-} streamAppend :: (Eq s, Monoid s) => Maybe s -> Maybe s -> Maybe s streamAppend Nothing _ = Nothing streamAppend (Just s) Nothing = if s == mempty then Nothing else Just s streamAppend s s' = mappend s s'+{-# INLINE streamAppend #-}
src/Data/JustParse/Language.hs view
@@ -36,18 +36,22 @@ -- The returned parser is greedy. regex :: Stream s Char => String -> Parser s Match regex = greedy . fromMaybe mzero . parseOnly regular+{-# INLINE regex #-} -- | Like 'regex', but returns a branching (non-greedy) parser. regex_ :: Stream s Char => String -> Parser s Match regex_ = fromMaybe mzero . parseOnly regular+{-# INLINE regex_ #-} -- | The same as 'regex', but only returns the full matched text. regex' :: Stream s Char => String -> Parser s String regex' = liftM matched . regex +{-# INLINE regex' #-} -- | The same as 'regex_', but only returns the full matched text. regex_' :: Stream s Char => String -> Parser s String regex_' = liftM matched . regex_+{-# INLINE regex_' #-} -- | The result of a 'regex'@@ -76,6 +80,7 @@ regular :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) regular = liftM (liftM mconcat . sequence) (many parser)+{-# INLINE regular #-} parser :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) parser = choice [@@ -90,6 +95,7 @@ negCharClass, period ]+{-# INLINE parser #-} parserNP :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) parserNP = choice [@@ -103,6 +109,7 @@ negCharClass, period ]+{-# INLINE parserNP #-} @@ -114,9 +121,11 @@ group, period ]+{-# INLINE restricted #-} unreserved :: Stream s Char => Parser s Char unreserved = (char '\\' >> anyChar ) <|> noneOf "()[]\\*+{}^?|."+{-# INLINE unreserved #-} character :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) character = @@ -125,6 +134,7 @@ return $ do c' <- char c return $ Match [c] []+{-# INLINE character #-} charClass :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) charClass = @@ -135,6 +145,7 @@ return $ do c' <- oneOf c return $ Match [c'] []+{-# INLINE charClass #-} negCharClass :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) negCharClass = @@ -145,6 +156,7 @@ return $ do c' <- noneOf c return $ Match [c'] []+{-# INLINE negCharClass #-} period :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) period = @@ -153,6 +165,7 @@ return $ do c <- noneOf "\n\r" return $ Match [c] []+{-# INLINE period #-} question :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)@@ -161,6 +174,7 @@ p <- restricted char '?' return $ liftM mconcat (mN_ 0 1 p)+{-# INLINE question #-} group :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) group = @@ -171,6 +185,7 @@ return $ do r <- p return $ r { groups = [r] } +{-# INLINE group #-} asterisk :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) asterisk = @@ -178,6 +193,7 @@ p <- restricted char '*' return $ liftM mconcat (many_ p)+{-# INLINE asterisk #-} plus :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) plus = @@ -185,6 +201,7 @@ p <- restricted char '+' return $ liftM mconcat (many1_ p)+{-# INLINE plus #-} mn :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) mn = @@ -196,6 +213,7 @@ r <- option (-1) decInt char '}' return $ liftM mconcat (mN_ l r p)+{-# INLINE mn #-} pipe :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) pipe = @@ -204,3 +222,4 @@ char '|' p' <- parser return $ p <||> p'+{-# INLINE pipe #-}
src/Data/JustParse/Numeric.hs view
@@ -11,91 +11,147 @@ -} module Data.JustParse.Numeric (- decFloat,- decFloat_,+ decDigit,+ hexDigit,+ unsignedDecInt,+ unsignedDecInt_,+ unsignedHexInt,+ unsignedHexInt_, decInt, decInt_, hexInt,- hexInt_+ hexInt_,+ decFloat,+ decFloat_, ) where ---{-# LANGUAGE Safe #-}+{-# LANGUAGE Safe #-} import Data.JustParse.Combinator import Data.JustParse.Internal-import Data.JustParse.Char+import qualified Data.JustParse.Char as C import Control.Monad ( liftM, liftM2 ) import Data.Char ( ord, digitToInt, toUpper, isDigit, isHexDigit ) --- | Reads many decimal digits and returns them as an @Int@.+-- | Parse a single decimal digit into an 'Int'.+decDigit :: Stream s Char => Parser s Int+decDigit = liftM digitToInt C.digit+{-# INLINE decDigit #-}++-- | Parse a single hexadecimal digit into an 'Int'.+hexDigit :: Stream s Char => Parser s Int+hexDigit = liftM digitToInt C.hexDigit+{-# INLINE hexDigit #-}++-- | Parse a series of decimal digits into an 'Int'.+unsignedDecInt :: Stream s Char => Parser s Int+unsignedDecInt = decDigit >>= g+ where+ g x = + do+ d <- decDigit+ g (x*10+d)+ <|> return x+{-# INLINE unsignedDecInt #-}++-- | Branching version of 'unsignedDecInt'.+unsignedDecInt_ :: Stream s Char => Parser s Int+unsignedDecInt_ = decDigit >>= g+ where+ g x = + do+ d <- decDigit+ g (x*10+d)+ <||> return x+{-# INLINE unsignedDecInt_ #-}++-- | Parse a series of hexadecimal digits into an 'Int'.+unsignedHexInt :: Stream s Char => Parser s Int+unsignedHexInt = hexDigit >>= g+ where+ g x = + do+ d <- hexDigit+ g (x*16+d)+ <|> return x+{-# INLINE unsignedHexInt #-}++-- | Branching version of 'unsignedHexInt'.+unsignedHexInt_ :: Stream s Char => Parser s Int+unsignedHexInt_ = hexDigit >>= g+ where+ g x = + do+ d <- hexDigit+ g (x*16+d)+ <||> return x+{-# INLINE unsignedHexInt_ #-}++-- | Parse a series of decimal digits into an 'Int' with an optional sign. decInt :: Stream s Char => Parser s Int decInt = do sign <- optional (oneOf "-+")- num <- liftM read (many1 digit)+ num <- unsignedDecInt case sign of Just '-' -> return (-num) _ -> return num+{-# INLINE decInt #-} --- | Branching version of decInt.+-- | Branching version of 'decInt'. decInt_ :: Stream s Char => Parser s Int decInt_ = do sign <- optional (oneOf "-+")- num <- liftM read (many1_ digit)+ num <- unsignedDecInt_ case sign of Just '-' -> return (-num) _ -> return num+{-# INLINE decInt_ #-} +-- | Parse a series of hexadecimal digits into an 'Int' with an optional +-- sign.+hexInt :: Stream s Char => Parser s Int+hexInt = + do+ sign <- optional (oneOf "-+")+ num <- unsignedHexInt+ case sign of+ Just '-' -> return (-num)+ _ -> return num+{-# INLINE hexInt #-}++-- | Branching versino of 'hexInt'.+hexInt_ :: Stream s Char => Parser s Int+hexInt_ = + do+ sign <- optional (oneOf "-+")+ num <- unsignedHexInt_+ case sign of+ Just '-' -> return (-num)+ _ -> return num+{-# INLINE hexInt_ #-}+ -- | Parse a float. If a decimal point is present, it must have at -- least one digit before and after the decimal point. decFloat :: Stream s Char => Parser s Float decFloat = do sign <- optional (oneOf "-+")- whole <- many1 digit- fractional <- option ".0" (liftM2 (:) (char '.') (many1 digit))+ whole <- many1 C.digit+ fractional <- option ".0" (liftM2 (:) (C.char '.') (many1 C.digit)) case sign of Just '-' -> return (-(read (whole ++ fractional))) _ -> return (read (whole ++ fractional))+{-# INLINE decFloat #-} -- | Branching version of decFloat. decFloat_ :: Stream s Char => Parser s Float decFloat_ = do sign <- optional (oneOf "-+")- whole <- many1_ digit- fractional <- option_ ".0" (liftM2 (:) (char '.') (many1_ digit))+ whole <- many1_ C.digit+ fractional <- option_ ".0" (liftM2 (:) (C.char '.') (many1_ C.digit)) case sign of Just '-' -> return (-(read (whole ++ fractional))) _ -> return (read (whole ++ fractional))----- | Reads many hexidecimal digits and returns them as an @Int@.-hexInt :: Stream s Char => Parser s Int-hexInt = - do- sign <- optional (oneOf "-+")- num <- liftM (f . reverse) (many1 hexDigit)- case sign of- Just '-' -> return (-num)- _ -> return num- where- f [] = 0- f (x:xs) - | isDigit x = digitToInt x + 16 * f xs - | otherwise = ord (toUpper x) - ord 'A' + 16 * f xs---- | Branching versino of 'hexInt'.-hexInt_ :: Stream s Char => Parser s Int-hexInt_ = - do- sign <- optional (oneOf "-+")- num <- liftM (f . reverse) (many1_ hexDigit)- case sign of- Just '-' -> return (-num)- _ -> return num- where- f [] = 0- f (x:xs) - | isDigit x = digitToInt x + 16 * f xs - | otherwise = ord (toUpper x) - ord 'A' + 16 * f xs+{-# INLINE decFloat_ #-}