packages feed

JustParse 1.0 → 2.0

raw patch · 8 files changed

+875/−457 lines, 8 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

- Data.JustParse: (<?>) :: Parser s a -> String -> Parser s a
- Data.JustParse: Fail :: [String] -> Maybe s -> Result s a
- Data.JustParse: Match :: String -> [Match] -> Match
- Data.JustParse: alpha :: Stream s Char => Parser s Char
- Data.JustParse: alphaNum :: Stream s Char => Parser s Char
- Data.JustParse: anyChar :: Stream s Char => Parser s Char
- Data.JustParse: anyToken :: Stream s t => Parser s t
- Data.JustParse: ascii :: Stream s Char => Parser s Char
- Data.JustParse: atLeast :: Int -> Parser s a -> Parser s [a]
- Data.JustParse: char :: Stream s Char => Char -> Parser s Char
- Data.JustParse: control :: Stream s Char => Parser s Char
- Data.JustParse: data Match
- Data.JustParse: digit :: Stream s Char => Parser s Char
- Data.JustParse: eof :: (Eq s, Monoid s) => Parser s ()
- Data.JustParse: eol :: Stream s Char => Parser s String
- Data.JustParse: exactly :: Int -> Parser s a -> Parser s [a]
- Data.JustParse: greedy :: Stream s t => Parser s a -> Parser s a
- Data.JustParse: groups :: Match -> [Match]
- Data.JustParse: hexDigit :: Stream s Char => Parser s Char
- Data.JustParse: isDone :: Result s a -> Bool
- Data.JustParse: isFail :: Result s a -> Bool
- Data.JustParse: isPartial :: Result s a -> Bool
- Data.JustParse: justParse :: Stream s t => Parser s a -> s -> Maybe a
- Data.JustParse: latin1 :: Stream s Char => Parser s Char
- Data.JustParse: lookAhead :: Parser s a -> Parser s a
- Data.JustParse: lower :: Stream s Char => Parser s Char
- Data.JustParse: mN :: Int -> Int -> Parser s a -> Parser s [a]
- Data.JustParse: many :: Parser s a -> Parser s [a]
- Data.JustParse: many1 :: Parser s a -> Parser s [a]
- Data.JustParse: manyN :: Int -> Parser s a -> Parser s [a]
- Data.JustParse: matched :: Match -> String
- Data.JustParse: messages :: Result s a -> [String]
- Data.JustParse: noneOf :: (Eq t, Stream s t) => [t] -> Parser s t
- Data.JustParse: octDigit :: Stream s Char => Parser s Char
- Data.JustParse: oneOf :: (Eq t, Stream s t) => [t] -> Parser s t
- Data.JustParse: option :: a -> Parser s a -> Parser s a
- Data.JustParse: print :: Stream s Char => Parser s Char
- Data.JustParse: regex :: Stream s Char => String -> Parser s Match
- Data.JustParse: regex' :: Stream s Char => String -> Parser s String
- Data.JustParse: rename :: String -> Parser s a -> Parser s a
- Data.JustParse: satisfy :: Stream s t => (t -> Bool) -> Parser s t
- Data.JustParse: space :: Stream s Char => Parser s Char
- Data.JustParse: string :: Stream s Char => String -> Parser s String
- Data.JustParse: test :: Parser s a -> Parser s Bool
- Data.JustParse: upper :: Stream s Char => Parser s Char
+ Data.JustParse: parseOnly :: Stream s t => Parser s a -> s -> Maybe a
+ Data.JustParse.Char: alpha :: Stream s Char => Parser s Char
+ Data.JustParse.Char: alphaNum :: Stream s Char => Parser s Char
+ Data.JustParse.Char: anyChar :: Stream s Char => Parser s Char
+ Data.JustParse.Char: ascii :: Stream s Char => Parser s Char
+ Data.JustParse.Char: caseInsensitiveChar :: Stream s Char => Char -> Parser s Char
+ Data.JustParse.Char: caseInsensitiveString :: Stream s Char => String -> Parser s String
+ Data.JustParse.Char: char :: Stream s Char => Char -> Parser s Char
+ Data.JustParse.Char: control :: Stream s Char => Parser s Char
+ Data.JustParse.Char: digit :: Stream s Char => Parser s Char
+ Data.JustParse.Char: eol :: Stream s Char => Parser s String
+ Data.JustParse.Char: hexDigit :: Stream s Char => Parser s Char
+ Data.JustParse.Char: instance [safe] Eq t => Stream [t] t
+ Data.JustParse.Char: latin1 :: Stream s Char => Parser s Char
+ Data.JustParse.Char: lower :: Stream s Char => Parser s Char
+ Data.JustParse.Char: octDigit :: Stream s Char => Parser s Char
+ Data.JustParse.Char: print :: Stream s Char => Parser s Char
+ Data.JustParse.Char: space :: Stream s Char => Parser s Char
+ Data.JustParse.Char: string :: Stream s Char => String -> Parser s String
+ Data.JustParse.Char: upper :: Stream s Char => Parser s Char
+ Data.JustParse.Combinator: (<|>) :: Stream s t => Parser s a -> Parser s a -> Parser s a
+ Data.JustParse.Combinator: (<||>) :: Parser s a -> Parser s a -> Parser s a
+ Data.JustParse.Combinator: anyToken :: Stream s t => Parser s t
+ Data.JustParse.Combinator: assert :: Stream s t => Bool -> Parser s ()
+ Data.JustParse.Combinator: branch :: Parser s a -> Parser s a -> Parser s a
+ Data.JustParse.Combinator: chainl :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a
+ Data.JustParse.Combinator: chainl1 :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a
+ Data.JustParse.Combinator: chainl1_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a
+ Data.JustParse.Combinator: chainl_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a
+ Data.JustParse.Combinator: chainr :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a
+ Data.JustParse.Combinator: chainr1 :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a
+ Data.JustParse.Combinator: chainr1_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a
+ Data.JustParse.Combinator: chainr_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> a -> Parser s a
+ Data.JustParse.Combinator: choice :: Stream s t => [Parser s a] -> Parser s a
+ Data.JustParse.Combinator: choice_ :: Stream s t => [Parser s a] -> Parser s a
+ Data.JustParse.Combinator: count :: Stream s t => Int -> Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: eitherP :: Stream s t => Parser s a -> Parser s b -> Parser s (Either a b)
+ Data.JustParse.Combinator: eitherP_ :: Stream s t => Parser s a -> Parser s b -> Parser s (Either a b)
+ Data.JustParse.Combinator: endBy :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: endBy1 :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: endBy1_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: endBy_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: eof :: Stream s t => Parser s ()
+ Data.JustParse.Combinator: exactly :: Stream s t => Int -> Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: greedy :: Stream s t => Parser s a -> Parser s a
+ Data.JustParse.Combinator: guard :: Stream s t => Bool -> Parser s ()
+ Data.JustParse.Combinator: lookAhead :: Stream s t => Parser s a -> Parser s a
+ Data.JustParse.Combinator: mN :: Stream s t => Int -> Int -> Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: mN_ :: Stream s t => Int -> Int -> Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: many :: Stream s t => Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: many1 :: Stream s t => Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: many1_ :: Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: many_ :: Parser s a -> Parser s [a]
+ Data.JustParse.Combinator: noneOf :: (Eq t, Stream s t) => [t] -> Parser s t
+ Data.JustParse.Combinator: notFollowedBy :: Stream s t => Parser s a -> Parser s ()
+ Data.JustParse.Combinator: oneOf :: (Eq t, Stream s t) => [t] -> Parser s t
+ Data.JustParse.Combinator: option :: Stream s t => a -> Parser s a -> Parser s a
+ Data.JustParse.Combinator: option_ :: Stream s t => a -> Parser s a -> Parser s a
+ Data.JustParse.Combinator: optional :: Stream s t => Parser s a -> Parser s (Maybe a)
+ Data.JustParse.Combinator: optional_ :: Stream s t => Parser s a -> Parser s (Maybe a)
+ Data.JustParse.Combinator: perm :: Stream s t => [Parser s a] -> Parser s [a]
+ Data.JustParse.Combinator: perm_ :: Stream s t => [Parser s a] -> Parser s [a]
+ Data.JustParse.Combinator: satisfy :: Stream s t => (t -> Bool) -> Parser s t
+ Data.JustParse.Combinator: select :: Stream s t => [Parser s a] -> Parser s (Int, a)
+ Data.JustParse.Combinator: select_ :: Stream s t => [Parser s a] -> Parser s (Int, a)
+ Data.JustParse.Combinator: sepBy :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: sepBy1 :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: sepBy1_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: sepBy_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: sepEndBy :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: sepEndBy1 :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: sepEndBy1_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: sepEndBy_ :: Stream s t => Parser s a -> Parser s b -> Parser s [a]
+ Data.JustParse.Combinator: skipMany :: Stream s t => Parser s a -> Parser s ()
+ Data.JustParse.Combinator: skipMany1 :: Stream s t => Parser s a -> Parser s ()
+ Data.JustParse.Combinator: skipMany1_ :: Stream s t => Parser s a -> Parser s ()
+ Data.JustParse.Combinator: skipMany_ :: Stream s t => Parser s a -> Parser s ()
+ Data.JustParse.Combinator: takeWhile :: Stream s t => (t -> Bool) -> Parser s [t]
+ Data.JustParse.Combinator: takeWhile_ :: Stream s t => (t -> Bool) -> Parser s [t]
+ Data.JustParse.Combinator: test :: Stream s t => Parser s a -> Parser s Bool
+ Data.JustParse.Combinator: token :: (Eq t, Stream s t) => t -> Parser s t
+ Data.JustParse.Language: Match :: String -> [Match] -> Match
+ Data.JustParse.Language: data Match
+ Data.JustParse.Language: groups :: Match -> [Match]
+ Data.JustParse.Language: instance [safe] Monoid Match
+ Data.JustParse.Language: instance [safe] Show Match
+ Data.JustParse.Language: matched :: Match -> String
+ Data.JustParse.Language: regex :: Stream s Char => String -> Parser s Match
+ Data.JustParse.Language: regex' :: Stream s Char => String -> Parser s String
+ Data.JustParse.Language: regex_ :: Stream s Char => String -> Parser s Match
+ Data.JustParse.Language: regex_' :: Stream s Char => String -> Parser s String
+ Data.JustParse.Numeric: decFloat :: Stream s Char => Parser s Float
+ Data.JustParse.Numeric: decFloat_ :: Stream s Char => Parser s Float
+ Data.JustParse.Numeric: decInt :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: decInt_ :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: hexInt :: Stream s Char => Parser s Int
+ Data.JustParse.Numeric: hexInt_ :: Stream s Char => Parser s Int

Files

JustParse.cabal view
@@ -1,5 +1,5 @@ name:                JustParse-version:             1.0+version:             2.0 synopsis:            A simple and comprehensive Haskell parsing library description:         A simple and comprehensive Haskell parsing library homepage:            https://github.com/grantslatton/JustParse@@ -13,8 +13,16 @@ cabal-version:       >=1.8  library-   exposed-modules: Data.JustParse-   other-modules: Data.JustParse.Internal, Data.JustParse.Language, Data.JustParse.Common-  build-depends:       base ==4.6.*-  hs-source-dirs: src-  extensions: MultiParamTypeClasses, Rank2Types, FlexibleInstances, FlexibleContexts, Safe+    exposed-modules: +        Data.JustParse,+        Data.JustParse.Combinator,+        Data.JustParse.Numeric,+        Data.JustParse.Language,+        Data.JustParse.Char+    other-modules: +        Data.JustParse.Internal+    build-depends:+        base >= 4.2 && < 5+    hs-source-dirs: src+    extensions: MultiParamTypeClasses, Rank2Types, FlexibleInstances, FlexibleContexts, Safe, TupleSections, UndecidableInstances+    ghc-options: -O2 -Wall
src/Data/JustParse.hs view
@@ -1,16 +1,14 @@ {-| Module      : Data.JustParse-Description : The one-stop import for the library+Description : Parsing functions and types Copyright   : Copyright Waived License     : PublicDomain Maintainer  : grantslatton@gmail.com Stability   : experimental Portability : portable--A simple and comprehensive Haskell parsing library. -}  -{-# LANGUAGE Safe #-}+--{-# LANGUAGE Safe #-} module Data.JustParse (     -- * Overview     -- $overview@@ -24,67 +22,17 @@      -- *** Recursive combinatorial parsing     -- $quickstart3--    -- * General Parsing-    C.Stream(..),-    C.Result(..),-    C.Parser( parse ),-    C.justParse,-    C.runParser,-    C.finalize,-    C.extend,-    C.isDone,-    C.isFail,-    C.isPartial,-    C.rename,-    (C.<?>),--    -- * Generic Parsers-    C.test,-    C.greedy,-    C.option,-    C.satisfy,-    C.mN,-    C.many,-    C.many1,-    C.manyN,-    C.atLeast,-    C.exactly,-    C.eof,-    C.oneOf,-    C.noneOf,-    C.anyToken,-    C.lookAhead,--    -- * Char Parsers-    C.char,-    C.anyChar,-    C.ascii,-    C.latin1,-    C.control,-    C.space,-    C.lower,-    C.upper,-    C.alpha,-    C.alphaNum,-    C.print,-    C.digit,-    C.octDigit,-    C.hexDigit,-    C.eol,--    -- * String Parsers-    C.string,--    -- * Regex Parsers-    L.regex,-    L.regex',-    L.Match(..)-+    runParser,+    parseOnly,+    extend,+    finalize,+    Parser,+    Result(..),+    Stream(..) ) where -import Data.JustParse.Language as L-import Data.JustParse.Common as C+import Data.JustParse.Internal+import Data.JustParse.Combinator  -- $overview -- @@ -92,13 +40,7 @@ --  -- * Makes extensive use of combinators -- --- * Returns relatively verbose 'Fail'ure messages.--- --- * Allows one to 'rename' a 'Parser'. --- --- * Allows for a parser to return a 'Partial' 'Result'--- --- * Non-greedy parsing+-- * Allows for a parser to return a 'Partial' result --  -- * Returns a list of all possible parses -- @@ -112,8 +54,8 @@ --p = do                 --    h \<- char \'h\'                   \-\-Parses the character \'h\' --    rest \<- string \"ello world\"     \-\-Parses the string \"ello world\"---    exp \<- char \'!\'                 \-\-Parses the character \'!\'---    return ([h]++rest++[exp])       \-\-Returns all of the above concatenated together+--    ex \<- char \'!\'                  \-\-Parses the character \'!\'+--    return ([h]++rest++[ex])        \-\-Returns all of the above concatenated together -- @  -- $quickstart2@@ -123,19 +65,37 @@ -- -- @ --p = do---    first \<- string \"hello w\"         \-\-Parses the string \"hello w\"---    os \<- many1 (char \'o\')            \-\-Applies the parser \"char \'o\'\" one or more times---    second \<- string \"rld\"            \-\-Parses the string \"rld\"---    return (length os)                \-\-Return the number of o\'s parsed+--    string \"hello w\"         \-\-Parses the string \"hello w\"+--    os \<- many1 (char \'o\')   \-\-Applies the parser \"char \'o\'\" one or more times+--    string \"rld\"             \-\-Parses the string \"rld\"+--    return (length os)       \-\-Return the number of o\'s parsed -- @  -- $quickstart3 -- --- This parser will turn a string of comma separated values into a list of them+-- This parser will turn a string of comma separated values into a list of +-- them. Note that we could use the 'sepBy' parser, but this demonstrates a +-- recursive parser. -- -- @ --csv = do  ---    v \<- greedy (many (noneOf \",\"))       \-\-Parses as many non-comma characters as possible+--    v \<- many (noneOf \",\")                \-\-Parses as many non-comma characters as possible --    vs \<- option [] (char \',\' >> csv)     \-\-Optionally parses a comma and a csv, returning the empty list upon failure --    return (v:vs)                         \-\-Concatenates and returns the full list -- @++-- | Supplies the input to the 'Parser'. Returns all 'Result' types, +-- including 'Partial' results.+runParser :: Parser s a -> s -> [Result s a]+runParser p = parse p . Just++-- | This runs the 'Parser' greedily over the input, 'finalize's all the +-- results, and returns the first successful result. If there are no +-- successful results, it returns 'Nothing'. This is useful when you are+-- parsing something that you know will have no 'Partial's and you just+-- want an answer.+parseOnly :: Stream s t => Parser s a -> s -> Maybe a+parseOnly p s = +    case finalize (parse (greedy p) (Just s)) of+        [] -> Nothing+        (Done v _:_) -> Just v
+ src/Data/JustParse/Char.hs view
@@ -0,0 +1,115 @@+{-|+Module      : Data.JustParse.Common+Description : Common char parsers+Copyright   : Copyright Waived+License     : PublicDomain+Maintainer  : grantslatton@gmail.com+Stability   : experimental+Portability : portable++Several useful parsers for dealing with 'String's.+-}++--{-# LANGUAGE Safe #-}+module Data.JustParse.Char (+    char,+    anyChar,+    caseInsensitiveChar,+    ascii,+    latin1,+    control,+    space,+    lower,+    upper,+    alpha,+    alphaNum,+    print,+    digit,+    octDigit,+    hexDigit,+    string,+    caseInsensitiveString,+    eol+) where++import Prelude hiding (print)+import Data.Char+import Data.JustParse.Internal+import Data.JustParse.Combinator++-- | Parse a specic char.+char :: Stream s Char => Char -> Parser s Char+char = token++-- | Parse any char.+anyChar :: Stream s Char =>  Parser s Char+anyChar = anyToken++-- | Parse a specific char, ignoring case.+caseInsensitiveChar :: Stream s Char => Char -> Parser s Char+caseInsensitiveChar c = char (toUpper c) <|> char (toLower c)++-- | Parse any char that is ASCII.+ascii :: Stream s Char =>  Parser s Char+ascii = satisfy isAscii++-- | Parse any char that is Latin-1.+latin1 :: Stream s Char =>  Parser s Char+latin1 = satisfy isLatin1++-- | Parse a control character.+control :: Stream s Char =>  Parser s Char+control = satisfy isControl++-- | Parse a space.+space :: Stream s Char =>  Parser s Char+space = satisfy isSpace++-- | Parse a lowercase character.+lower :: Stream s Char =>  Parser s Char+lower = satisfy isLower++-- | Parse an uppercase character.+upper :: Stream s Char =>  Parser s Char+upper = satisfy isUpper++-- | Parse an alphabetic character.+alpha :: Stream s Char =>  Parser s Char+alpha = satisfy isAlpha++-- | Parse an alphanumeric character.+alphaNum :: Stream s Char =>  Parser s Char+alphaNum = satisfy isAlphaNum++-- | Parse a printable (non-control) character.+print :: Stream s Char =>  Parser s Char+print = satisfy isPrint++-- | Parse a digit.+digit :: Stream s Char =>  Parser s Char+digit = satisfy isDigit++-- | Parse an octal digit.+octDigit :: Stream s Char =>  Parser s Char+octDigit = satisfy isOctDigit++-- | Parse a hexadeciaml digit.+hexDigit :: Stream s Char =>  Parser s Char+hexDigit = satisfy isHexDigit++-- | Parse a specific string.+string :: Stream s Char => String -> Parser s String+string = mapM char ++-- | Parse a specfic string, ignoring case.+caseInsensitiveString :: Stream s Char => String -> Parser s String+caseInsensitiveString = mapM caseInsensitiveChar ++-- | 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"]++-- | Makes common types such as 'String's into a Stream.+instance Eq t => Stream [t] t where+    uncons [] = Nothing+    uncons (x:xs) = Just (x, xs)
+ src/Data/JustParse/Combinator.hs view
@@ -0,0 +1,478 @@+{-|+Module      : Data.JustParse.Common+Description : Common parser combinators+Copyright   : Copyright Waived+License     : PublicDomain+Maintainer  : grantslatton@gmail.com+Stability   : experimental+Portability : portable++The bread and butter of combinatory parsing.+-}++--{-# LANGUAGE Safe #-}+--{-# LANGUAGE TupleSections #-}+module Data.JustParse.Combinator (+    -- * Utility Parsers+    assert,+    eof,+    eitherP,+    greedy,+    guard,+    lookAhead,+    notFollowedBy,+    option,+    optional,+    test,+    (<|>),++    -- * Token Parsers+    anyToken,+    noneOf,+    oneOf,+    satisfy,+    token,++    -- * Repetetive Parsers+    chainl,+    chainl1,+    chainr,+    chainr1,+    count,+    endBy,+    endBy1,+    exactly,+    many,+    many1,+    mN,+    sepBy,+    sepBy1,+    skipMany,+    skipMany1,+    sepEndBy,+    sepEndBy1,+    takeWhile,++    -- * Group Parsers+    choice,+    perm,+    select,++    -- * Branching Parsers+    branch,+    (<||>),+    chainl_,+    chainr_,+    chainl1_,+    chainr1_,+    choice_,+    eitherP_,+    endBy_,+    endBy1_,+    many_,+    many1_,+    mN_,+    option_,+    optional_,+    perm_,+    select_,+    sepBy_,+    sepBy1_,+    sepEndBy_,+    sepEndBy1_,+    skipMany_,+    skipMany1_,+    takeWhile_+) where++import Prelude hiding ( print, length, takeWhile )+import Data.JustParse.Internal ( +    Stream(..), Parser(..), Result(..), extend, finalize, isDone, +    isPartial, toPartial, streamAppend )+import Data.Monoid ( mempty, Monoid, mappend )+import Data.Maybe ( fromMaybe )+import Data.List ( minimumBy, foldl1', foldl' )+import Data.Ord ( comparing )+import qualified Control.Monad as M+import qualified Control.Applicative as A++-- | Parse a token that satisfies a predicate.+satisfy :: Stream s t => (t -> Bool) -> Parser s t+satisfy f = Parser $ \s -> +    case s of+        Nothing -> []+        Just s' -> case uncons s' of+            Nothing -> [Partial $ parse (satisfy f)]+            Just (x, xs) -> [Done x (Just xs) | f x]++-- | A parser that succeeds on 'True' and fails on 'False'. +guard :: Stream s t => Bool -> Parser s ()+guard = M.guard++-- | Synonym of 'guard'.+assert :: Stream s t => Bool -> Parser s ()+assert = guard++-- | Only succeeds when supplied with 'Nothing'.+eof :: Stream s t => Parser s ()+eof = notFollowedBy anyToken++-- | 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)++-- | 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)++-- | Parse a specific token.+token :: (Eq t, Stream s t) => t -> Parser s t+token t = satisfy (==t)++-- | Parse any token.+anyToken :: Stream s t => Parser s t+anyToken = satisfy (const True)++-- | Parse tokens while a predicate remains true.+takeWhile :: Stream s t => (t -> Bool) -> Parser s [t]+takeWhile = many . satisfy++-- | Branches every iteration where one branch stops and one branch +-- continues.+takeWhile_ :: Stream s t => (t -> Bool) -> Parser s [t]+takeWhile_ = many_ . satisfy++-- | 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++infixr 1 <||>+-- | Infix version of 'branch'.+(<||>) :: Parser s a -> Parser s a -> Parser s a+(<||>) = branch++-- | @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)++-- | Branches every iteration where one branch stops and one branch +-- continues.+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) <||> return []+mN_ m n p = M.liftM2 (:) p (mN (m-1) (n-1) p)++-- | Synonym of 'count'.+exactly :: Stream s t => Int -> Parser s a -> Parser s [a]+exactly n = mN n n++-- | Applies a parser at least @n@ times.+atLeast :: Stream s t => Int -> Parser s a -> Parser s [a]+atLeast n = mN n (-1)++-- | 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)++-- | Applies a parser at most @n@ times.+atMost :: Stream s t => Int -> Parser s a -> Parser s [a]+atMost  = mN 0++-- | 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++-- | Applies a parser zero or more times.+many :: Stream s t => Parser s a -> Parser s [a]+many = A.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)++-- | Applies a parser one or more times.+many1 :: Stream s t => Parser s a -> Parser s [a]+many1 p = M.liftM2 (:) p (many p)++-- | 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)++-- | Return 'True' if the parser would succeed if one were to apply it,+-- otherwise, it returns 'False'. It does not consume input.+test :: Stream s t => Parser s a -> Parser s Bool+test p = +    do +        a <- optional (lookAhead p)+        case a of+            Nothing -> return False+            _ -> return True++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.<|>)++-- | 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.<|>) ++-- | Given a list of parsers, split off a branch for each one.+choice_ :: Stream s t => [Parser s a] -> Parser s a+choice_ = foldl1' (<||>)++-- | 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)++-- | 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)++-- | Modifies a parser so that it will ony return the most consumptive+-- succesful results. +greedy :: Stream s t => Parser s a -> Parser s a+greedy (Parser p) = Parser $ \s -> g (p s) +    where+        f Nothing = 0+        f (Just s) = length s+        g [] = []+        g xs +            | all isDone xs = [minimumBy (comparing (f . leftover)) xs]+            | otherwise = [Partial $ \s -> g $ extend s xs] ++-- | Attempts to apply a parser and returns a default value if it fails.+option :: Stream s t => a -> Parser s a -> Parser s a+option v p = +    do+        r <- A.optional p+        case r of+            Nothing -> return v+            Just v' -> return v'++-- | 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++-- | 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++-- | 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++-- | @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 []++-- | 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 []++-- | @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))++-- | 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))++-- | Applies the parser and returns its result, but resets+-- the 'Stream' as if it consumed nothing.+lookAhead :: Stream s t => Parser s a -> Parser s a+lookAhead v@(Parser p) = Parser $ \s -> +    let +        g (Done a _) = Done a s+        g (Partial p') = Partial $ \s' -> +            case s' of+                Nothing -> finalize (p' s)+                _ -> parse (lookAhead v) (streamAppend s s')+    in+        map g (p s)++-- | @count n p@ parses exactly @n@ occurences of @p@.+count :: Stream s t => Int -> Parser s a -> Parser s [a]+count = exactly++-- | Identical to 'many' except the result is discarded.+skipMany :: Stream s t => Parser s a -> Parser s ()+skipMany = M.void . many++-- | Branches every iteration where one branch stops and one branch +-- continues.+skipMany_ :: Stream s t => Parser s a -> Parser s ()+skipMany_ = M.void . many_++-- | Identical to 'many1' except the result is discarded.+skipMany1 :: Stream s t => Parser s a -> Parser s ()+skipMany1 = M.void . many1++-- | Branches every iteration where one branch stops and one branch +-- continues.+skipMany1_ :: Stream s t => Parser s a -> Parser s ()+skipMany1_ = M.void . many1_++-- | @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)++-- | 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)++-- | @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)++-- | 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)++-- | @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++-- | 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++-- | @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++-- | 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++-- | @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++-- | 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++-- | 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+chainl1 p o = p >>= f+    where+        f x =+            do+                g <- o+                y <- p+                f (g x y)+            <|> return x++-- | Branches every iteration where one branch stops and one branch +-- continues.+chainl1_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a+chainl1_ p o = p >>= f+    where+        f x =+            do+                g <- o+                y <- p+                f (g x y)+            <||> return x++-- | 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++-- | 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++-- | Like 'chainl1', but right associative.+chainr1 :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a+chainr1 p o = p >>= f+    where+        f x = +            do+                g <- o+                y <- chainr1 p o+                return (g x y)+            <|> return x++-- | Branches every iteration where one branch stops and one branch +-- continues.+chainr1_ :: Stream s t => Parser s a -> Parser s (a -> a -> a) -> Parser s a+chainr1_ p o = p >>= f+    where+        f x = +            do+                g <- o+                y <- chainr1_ p o+                return (g x y)+            <||> return x++-- | 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++-- | @manyTill a b@ parses multiple occurences of @a@ until @b@ would +-- succeed if tried.+manyTill :: Stream s t => Parser s a -> Parser s b -> Parser s [a]+manyTill p e = +    do+        b <- test e+        if b +            then return []+            else M.liftM2 (:) p (manyTill p e)++-- | Does nothing -- only used for @Parsec@ compatability.+try :: Stream s t => Parser s a -> Parser s a+try = id++-- | @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++-- | 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++-- | Parses a sequence of parsers in any order.+perm :: Stream s t => [Parser s a] -> Parser s [a]+perm [] = return []+perm ps = +    do+        (i, r) <- select ps+        M.liftM (r:) (perm (let (a,b) = splitAt i ps in a ++ tail b)) ++-- | Parses a sequence of parsers in all possible orders.+perm_ :: Stream s t => [Parser s a] -> Parser s [a]+perm_ [] = return []+perm_ ps = +    do+        (i, r) <- select_ ps+        M.liftM (r:) (perm_ (let (a,b) = splitAt i ps in a ++ tail b)) 
− src/Data/JustParse/Common.hs
@@ -1,284 +0,0 @@-{-|-Module      : Data.JustParse.Common-Description : Common Parser Combinators-Copyright   : Copyright Waived-License     : PublicDomain-Maintainer  : grantslatton@gmail.com-Stability   : experimental-Portability : portable--Many common parsing needs in one place.--}--{-# LANGUAGE Safe #-}-module Data.JustParse.Common (--- Parsing-    Stream(..),-    Result(..),-    Parser( parse ),-    finalize,-    extend,-    justParse,-    runParser,-    isDone,-    isFail,-    isPartial,-    rename,-    (<?>),---- Primitive parsers-    satisfy,-    mN,---- Derived Parsers---- Generic Parsers-    test,-    greedy,-    option,-    many,-    many1,-    manyN,-    atLeast,-    exactly,-    eof,-    oneOf,-    noneOf,-    anyToken,-    lookAhead,---- Char Parsers-    char,-    anyChar,-    ascii,-    latin1,-    control,-    space,-    lower,-    upper,-    alpha,-    alphaNum,-    print,-    digit,-    octDigit,-    hexDigit,-    eol,---- String Parsers-    string,--) where--import Prelude hiding ( print, length )-import Data.JustParse.Internal ( Stream(..), Parser(..), Result(..), extend, finalize, isDone, isPartial, isFail, rename, (<?>) )-import Data.Monoid ( mempty, Monoid )-import Data.Maybe ( fromMaybe )-import Data.List ( minimumBy )-import Data.Char ( isControl, isSpace, isLower, isUpper, isAlpha, isAlphaNum, isPrint, -                   isDigit, isOctDigit, isHexDigit, isLetter, isMark, isNumber, isPunctuation, -                   isSymbol, isSeparator, isAscii, isLatin1, isAsciiUpper, isAsciiLower )-import Data.Ord ( comparing )-import Control.Monad ( void, (>=>), liftM )-import Control.Applicative ( (<|>), optional, (<*) )---- | Supplies the input to the 'Parser'. Returns all 'Result' types, --- including 'Partial' and 'Fail' types.-runParser :: Parser s a -> s -> [Result s a]-runParser p = parse p . Just---- | This is a \"newbie\" command that one should probably only use out of frustration.--- It runs the 'Parser' greedily over the input, 'finalize's all the results, and returns--- the first successful result. If there are no successful results, it returns Nothing.-justParse :: Stream s t => Parser s a -> s -> Maybe a-justParse p s = -    case finalize (parse (greedy p) (Just s)) of-        [] -> Nothing-        (Done v _:_) -> Just v-        (Fail m _:_) -> Nothing---- | Parse a token that satisfies a predicate.-satisfy :: Stream s t => (t -> Bool) -> Parser s t-satisfy f = Parser $ \s -> -    case s of-        Nothing -> [Fail ["satisfy"] s]-        Just s' -> case uncons s' of-            Nothing -> [Partial $ parse (satisfy f)]-            Just (x, xs) -> -                if f x -                    then [Done x (Just xs)]-                    else [Fail ["satisfy"] s]---- | Parse from @m@ to @n@ occurences of a 'Parser'. Let @n@ be negative--- if one wishes for no upper bound.-mN :: Int -> Int -> Parser s a -> Parser s [a]-mN m n p = mN' m n p <?> "mN"--mN' :: Int -> Int -> Parser s a -> Parser s [a]-mN' _ 0 _ = Parser $ \s -> [Done [] s] -mN' m n p = Parser $ \s -> -    if m == 0 -        then Done [] s : (parse p s >>= g)-        else             parse p s >>= g-    where-        m' = if m == 0 then 0 else m-1-        g (Done a s) = parse (mN' m' (n-1) p) s >>= h a-        g (Partial p') = [Partial $ p' >=> g]-        g (Fail m l) = [Fail m l]-        h a (Done as s) = [Done (a:as) s]-        h a (Partial p') = [Partial $ p' >=> h a]-        h a (Fail m l) = [Fail m l]---- | Return @True@ if the 'Parser' would succeed if one were to apply it,--- otherwise, @False@.-test :: Parser s a -> Parser s Bool-test p = -    do -        a <- optional (lookAhead p)-        case a of-            Nothing -> return False-            _ -> return True---- | Modifies a 'Parser' so that it will ony return the most consumptive--- succesful results. If there are no successful results, it will only--- return the most consumptive failures. One can use @greedy@ to emulate--- parsers from @Parsec@ or @attoparsec@.-greedy :: Stream s t => Parser s a -> Parser s a-greedy (Parser p) = Parser $ \s -> g (p s) -    where-        b (Done _ _) = True-        b (Fail _ _) = True-        b _ = False-        f Nothing = 0-        f (Just s) = length s-        g [] = []-        g xs -            | all b xs = -                let-                    ds = filter isDone xs-                    dm = minimum (map (f . leftover) ds)-                    fs = filter isFail xs-                    fm = minimum (map (f . leftover) fs)-                in-                    if not (null ds)-                        then filter ((dm==) . f . leftover) ds-                        else filter ((fm==) . f . leftover) fs-            | otherwise = [Partial $ \s -> g $ extend s xs] ---- | Attempts to apply a parser and returns a default value if it fails.-option :: a -> Parser s a -> Parser s a-option v p = -    do-        r <- optional p-        case r of-            Nothing -> return v-            Just v' -> return v'---- | Parse any number of occurences of the 'Parser'. Equivalent to @'mN' 0 (-1)@.-many :: Parser s a -> Parser s [a]-many p = rename "many" (mN 0 (-1) p)---- | Parse one or more occurence of the 'Parser'. Equivalent to @'mN' 1 (-1)@.-many1 :: Parser s a -> Parser s [a]-many1 p = rename "many1" (mN 1 (-1) p)---- | Parse at least @n@ occurences of the 'Parser'. Equivalent to @'mN' n (-1)@.-manyN :: Int -> Parser s a -> Parser s [a]-manyN n p = rename "manyN" (mN n (-1) p)---- | Identical to 'manyN', just a more intuitive name.-atLeast :: Int -> Parser s a -> Parser s [a]-atLeast n p = rename "atLeast" (mN n (-1) p)---- | Parse exactly @n@ occurences of the 'Parser'. Equivalent to @'mN' n n@.-exactly :: Int -> Parser s a -> Parser s [a]-exactly n p = rename "exactly" (mN n n p)---- | Only succeeds when supplied with @Nothing@.-eof :: (Eq s, Monoid s) => Parser s ()-eof = Parser $ \s ->-    case s of-        Nothing -> [Done () s]-        Just s' -> -            if s' == mempty-                then [Partial $ parse eof]-                else [Fail ["eof"] (Just s')]--oneOf :: (Eq t, Stream s t) => [t] -> Parser s t-oneOf ts = rename "oneOf" (satisfy (`elem` ts))--noneOf :: (Eq t, Stream s t) => [t] -> Parser s t-noneOf ts = rename "noneOf" (satisfy (not . (`elem` ts)))---- | Parse a specific token.-token :: (Eq t, Stream s t) => t -> Parser s t-token t = rename "token" (satisfy (==t))--anyToken :: Stream s t => Parser s t-anyToken = rename "anyToken" (satisfy (const True))---- | Applies the parser and returns its result, but resets--- the leftovers as if it consumed nothing.-lookAhead :: Parser s a -> Parser s a-lookAhead (Parser p) = rename "lookAhead" $ Parser $ \s -> -    let -        g (Done a _) = [Done a s]-        g (Partial p') = [Partial $ p' >=> g]-        g (Fail m _) = [Fail m s]-    in-        p s >>= g---- | Parse a specic char.-char :: Stream s Char => Char -> Parser s Char-char c = rename ("char "++[c]) (token c)--anyChar :: Stream s Char =>  Parser s Char-anyChar = rename "anyChar" anyToken--ascii :: Stream s Char =>  Parser s Char-ascii = rename "ascii" (satisfy isAscii)--latin1 :: Stream s Char =>  Parser s Char-latin1 = rename "latin1" (satisfy isLatin1)--control :: Stream s Char =>  Parser s Char-control = rename "control" (satisfy isControl)--space :: Stream s Char =>  Parser s Char-space = rename "space" (satisfy isSpace)--lower :: Stream s Char =>  Parser s Char-lower = rename "lower" (satisfy isLower)--upper :: Stream s Char =>  Parser s Char-upper = rename "upper" (satisfy isUpper)--alpha :: Stream s Char =>  Parser s Char-alpha = rename "alpha" (satisfy isAlpha)--alphaNum :: Stream s Char =>  Parser s Char-alphaNum = rename "alphaNum" (satisfy isAlphaNum)--print :: Stream s Char =>  Parser s Char-print = rename "print" (satisfy isPrint)--digit :: Stream s Char =>  Parser s Char-digit = rename "digit" (satisfy isDigit)--octDigit :: Stream s Char =>  Parser s Char-octDigit = rename "octDigit" (satisfy isOctDigit)--hexDigit :: Stream s Char =>  Parser s Char-hexDigit = rename "hexDigit" (satisfy isHexDigit)---- | Parse a specific string.-string :: Stream s Char => String -> Parser s String-string s = rename ("string "++s) (mapM char s)---- | Parses until a newline, carriage return + newline, or newline + carriage return.-eol :: Stream s Char => Parser s String-eol = rename "eol" (string "\r\n" <|> string "\n\r" <|> string "\n")---- | Makes common types such as Strings into a Stream.-instance (Eq t) => Stream [t] t where-    uncons [] = Nothing-    uncons (x:xs) = Just (x, xs)
src/Data/JustParse/Internal.hs view
@@ -11,21 +11,21 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE Safe #-}+--{-# LANGUAGE Safe #-}  module Data.JustParse.Internal (-    finalize,-    extend,     Stream (..),     Parser (..),     Result (..),     isDone,-    isFail,     isPartial,-    rename,-    (<?>)+    toPartial,+    finalize,+    extend,+    streamAppend ) where  import Prelude hiding ( length )@@ -35,15 +35,17 @@ import Data.List ( intercalate )  -- | A @Stream@ instance has a stream of type @s@, made up of tokens of --- type @t@, which must be determinable by the stream.+-- type @t@, which must be determinable by the stream. A minimal complete+-- definition only needs to define @uncons@. class (Eq s, Monoid s) => Stream s t | s -> t where-    -- | @uncons@ returns @Nothing@ if the @Stream@ is empty, otherwise it+    -- | @uncons@ returns 'Nothing' if the @Stream@ is empty, otherwise it     -- returns the first token of the stream, followed by the remainder-    -- of the stream, wrapped in a @Just@.+    -- of the stream, wrapped in a 'Just'.     uncons :: Stream s t => s -> Maybe (t, s)-    -- | The default @length@ implementation is O(n). If your stream provides-    -- a more efficient method for determining the length, it is wise to-    -- override this. The @length@ method is only used by the 'greedy' parser.+    -- | The default @length@ implementation is @O(n)@. If your stream +    -- provides a more efficient method for determining the length, it is +    -- wise to override this. The @length@ method is only used by the +    -- 'greedy' parser.     length :: Stream s t => s -> Int     length s =          case uncons s of@@ -55,18 +57,18 @@         parse :: Maybe s -> [Result s a]     } -instance Monoid (Parser s a) where+instance Stream s t => Monoid (Parser s a) where     mempty = mzero     mappend = mplus  instance Functor (Parser s) where-    fmap f (Parser p) = Parser $ \s -> map (fmap f) (p s)+    fmap f (Parser p) = Parser $ map (fmap f) . p   instance Applicative (Parser s) where     pure = return      (<*>) = ap -instance Alternative (Parser s) where+instance Stream s t => Alternative (Parser s) where     empty = mzero     (<|>) = mplus @@ -74,31 +76,47 @@     return v = Parser $ \s -> [Done v s]      (Parser p) >>= f = Parser $ p >=> g         where-            g (Fail m l) = [Fail m l]             g (Done a s) = parse (f a) s              g (Partial p) = [Partial $ p >=> g]  -instance MonadPlus (Parser s) where+instance Stream s t => MonadPlus (Parser s) where     mzero = Parser $ const []-    mplus (Parser p1) (Parser p2) = Parser (\s -> p1 s ++ p2 s)+    mplus a b = Parser $ \s ->+        let+            g [] = parse b s+            g xs +                | any isDone xs = xs+                | otherwise = [Partial $ \s' -> +                    -- case needed for proper finalization+                    case s' of+                        -- if finalized+                        Nothing -> +                            case finalize (parse a s) of+                                -- if parser a doesn't yield, try b+                                [] -> finalize (parse b s)+                                -- otherwise give what a yielded+                                r -> r+                        -- if not finalized+                        _ -> parse (mplus a b) (streamAppend s s')] +        in+            g (parse a s) + data Result s a -    -- | A @Partial@ wraps the same function as a Parser. Supply it with a @Just@-    -- and it will continue parsing, or with a @Nothing@ and it will terminate.+    -- | A @Partial@ wraps the same function as a Parser. Supply it with +    -- a 'Just'+    -- and it will continue parsing, or with a 'Nothing' and it will +    -- terminate.     =     Partial {         continue    :: Maybe s -> [Result s a]     } |-    -- | A @Done@ contains the resultant @value@, and the @leftover@ stream, if any.+    -- | A @Done@ contains the resultant @value@, and the @leftover@ +    -- stream, if any.     Done {         value       :: a,         leftover    :: Maybe s-    } |-    -- | A @Fail@ contains a stack of error messages, and the @lftover@ stream, if any.-    Fail {-        messages    :: [String],-        leftover    :: Maybe s-    }+    }   isDone :: Result s a -> Bool isDone (Done _ _) = True@@ -108,50 +126,35 @@ isPartial (Partial _) = True isPartial _ = False -isFail :: Result s a -> Bool-isFail (Fail _ _) = True-isFail _ = False+-- | Lifts a parser into the result space+toPartial :: Parser s a -> [Result s a]+toPartial (Parser p) = [Partial p]  instance Functor (Result s) where     fmap f (Partial p) = Partial $ map (fmap f) . p     fmap f (Done a s) = Done (f a) s-    fmap f (Fail m l) = Fail m l  instance Show a => Show (Result s a) where     show (Partial _) = "Partial"     show (Done a _) = show a-    show (Fail m l) = "Fail: \nIn: " ++ intercalate "\nIn: " m --- | @finalize@ takes a list of results (presumably returned from a 'Parser' or 'Partial',--- and supplies @Nothing@ to any remaining @Partial@ values, so that only 'Fail' and 'Done'--- values remain.+-- | @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 --- | @extend@ takes a @Maybe s@ as input, and supplies the input to all values--- in the 'Result' list. For 'Done' and 'Fail' values, it appends the @stream@ --- to the 'leftover' portion, and for 'Partial' values, it runs the continuation,--- adding in any new 'Result' values to the output.+-- | @extend@ takes a @'Maybe' s@ as input, and supplies the input to all +-- values  in the 'Result' list. For 'Done' values, it appends +-- the 'Stream'  to the 'leftover' portion, and for 'Partial' values, it +-- runs the continuation, adding in any new 'Result' values to the output. extend :: (Eq s, Monoid s) => Maybe s -> [Result s a] -> [Result s a]-extend s rs = rs >>= g --`prnt` (show (map i rs, map i (rs >>= g), h s))+extend s rs = rs >>= g      where-        g (Fail m l) = [Fail m (f l s)]         g (Partial p) = p s-        g (Done a s') = [Done a (f s' s)]-        f Nothing _ = Nothing-        f (Just s) Nothing = if s == mempty then Nothing else Just s-        f s s' = mappend s s'---- | @rename@ pushes a new error message onto the stack in case of failure.--- This is particularly useful when debugging a complex 'Parser'.-rename :: String -> Parser s a -> Parser s a-rename s p = Parser (map g . parse p)-    where-        g v@(Fail m l) = Fail (s:m) l-        g v = v-+        g (Done a s') = [Done a (streamAppend s' s)] -infixl 0 <?>--- | The infix version of 'rename'-(<?>) :: Parser s a -> String -> Parser s a-p <?> s = rename s p+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'
src/Data/JustParse/Language.hs view
@@ -1,47 +1,55 @@ {-| Module      : Data.JustParse.Language-Description : Regular Expressions and Grammars in JustParse+Description : Regular expressions Copyright   : Copyright Waived License     : PublicDomain Maintainer  : grantslatton@gmail.com Stability   : experimental Portability : portable -Takes ideas from the field of Formal Languages and imports them into the parsing library.+Allows for conversion from a regular expression and a 'Parser'. -}  {-# LANGUAGE Safe #-} module Data.JustParse.Language (     Match (..),     regex,-    regex'+    regex_,+    regex',+    regex_' ) where -import Data.JustParse.Common ( char, string, many1, digit, Stream, noneOf, oneOf, greedy, many, mN, anyChar, leftover, value, finalize, parse, Result(..), justParse, isFail )-import Data.JustParse.Internal( Parser (..) )-import Control.Applicative ( (<|>), optional )+import Data.JustParse+import Data.JustParse.Internal+import Data.JustParse.Combinator+import Data.JustParse.Numeric+import Data.JustParse.Char+ import Control.Monad ( liftM, mzero ) import Data.Monoid ( Monoid, mconcat, mempty, mappend )-import Data.Maybe ( isJust )+import Data.Maybe ( isJust, fromMaybe ) import Data.List ( intercalate )  -- | @regex@ takes a regular expression in the form of a 'String' and, -- if the regex is valid, returns a 'Parser' that parses that regex.--- If the regex is invalid, it returns a Parser that will only return--- 'Fail' with an \"Invalid Regex\" message.+-- If the regex is invalid, it returns a Parser that will always fail.+-- The returned parser is greedy. regex :: Stream s Char => String -> Parser s Match-regex s -    | null r = Parser $ \s -> [Fail ["Invalid Regex"] s]-    | isFail $ head r = Parser $ \s -> [Fail ["Invalid Regex"] s]-    | isJust $ leftover $ head r = Parser $ \s -> [Fail ["Invalid Regex"] s]-    | otherwise = value $ head r-    where-        r = finalize (parse (greedy regular) (Just s))+regex = greedy . fromMaybe mzero . parseOnly regular +-- | Like 'regex', but returns a branching (non-greedy) parser.+regex_ :: Stream s Char => String -> Parser s Match+regex_ = fromMaybe mzero . parseOnly regular+ -- | The same as 'regex', but only returns the full matched text. regex' :: Stream s Char => String -> Parser s String regex' = liftM matched . regex  +-- | The same as 'regex_', but only returns the full matched text.+regex_' :: Stream s Char => String -> Parser s String+regex_' = liftM matched . regex_++ -- | The result of a 'regex' data Match =      Match {@@ -67,19 +75,48 @@         }  regular :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)-regular = liftM (liftM mconcat . sequence) (greedy $ many parser)+regular = liftM (liftM mconcat . sequence) (many parser)  parser :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)-parser = character <|> charClass <|> negCharClass <|> question <|> group <|> asterisk <|> plus <|> mn <|> period <|> pipe+parser = choice [+    asterisk,+    mn,+    pipe,+    plus,+    question,+    group,+    character,+    charClass,+    negCharClass,+    period+    ]  parserNP :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)-parserNP = character <|> charClass <|> negCharClass <|> question <|> group <|> asterisk <|> plus <|> mn <|> period +parserNP = choice [+    asterisk,+    mn,+    plus,+    question,+    group,+    character,+    charClass,+    negCharClass,+    period+    ] ++ restricted :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)-restricted = character <|> charClass <|> negCharClass <|> group <|> period+restricted = choice [+    character,+    charClass,+    negCharClass,+    group,+    period+    ]  unreserved :: Stream s Char => Parser s Char -unreserved = (char '\\' >> anyChar ) <|> noneOf "()[]\\*+{}^?:<>|."+unreserved = (char '\\' >> anyChar ) <|> noneOf "()[]\\*+{}^?|."  character :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) character = @@ -93,7 +130,7 @@ charClass =      do         char '['-        c <- greedy (many1 unreserved)+        c <- many1 unreserved         char ']'         return $ do             c' <- oneOf c@@ -103,7 +140,7 @@ negCharClass =      do         string "[^"-        c <- greedy (many1 unreserved)+        c <- many1 unreserved         char ']'         return $ do             c' <- noneOf c@@ -123,12 +160,12 @@     do         p <- restricted         char '?'-        return $ liftM mconcat (mN 0 1 p)+        return $ liftM mconcat (mN_ 0 1 p)  group :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) group =      do-        string "("+        char '('         p <- regular         char ')'         return $ do@@ -140,25 +177,25 @@     do         p <- restricted         char '*'-        return $ liftM mconcat (many p)+        return $ liftM mconcat (many_ p)  plus :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) plus =      do         p <- restricted         char '+'-        return $ liftM mconcat (many1 p)+        return $ liftM mconcat (many1_ p)  mn :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) mn =      do         p <- restricted         char '{'-        l <- optional (many1 digit)+        l <- option 0 decInt         char ','-        r <- optional (many1 digit)+        r <- option (-1) decInt         char '}'-        return $ liftM mconcat (mN (maybe 0 read l) (maybe (-1) read r) p)+        return $ liftM mconcat (mN_ l r p)  pipe :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match) pipe = @@ -166,4 +203,4 @@         p <- parserNP         char '|'         p' <- parser-        return $ p <|> p'+        return $ p <||> p'
+ src/Data/JustParse/Numeric.hs view
@@ -0,0 +1,101 @@+{-|+Module      : Data.JustParse.Numeric+Description : Numeric parsing+Copyright   : Copyright Waived+License     : PublicDomain+Maintainer  : grantslatton@gmail.com+Stability   : experimental+Portability : portable++Parsers for dealing with signed and unsigned 'Int's and 'Float's.+-}++module Data.JustParse.Numeric (+    decFloat,+    decFloat_,+    decInt,+    decInt_,+    hexInt,+    hexInt_+) where++--{-# LANGUAGE Safe #-}+import Data.JustParse.Combinator+import Data.JustParse.Internal+import Data.JustParse.Char+import Control.Monad ( liftM, liftM2 )+import Data.Char ( ord, digitToInt, toUpper, isDigit, isHexDigit )++-- | Reads many decimal digits and returns them as an @Int@.+decInt :: Stream s Char => Parser s Int+decInt = +    do+        sign <- optional (oneOf "-+")+        num <- liftM read (many1 digit)+        case sign of+            Just '-' -> return (-num)+            _ -> return num++-- | Branching version of decInt.+decInt_ :: Stream s Char => Parser s Int+decInt_ = +    do+        sign <- optional (oneOf "-+")+        num <- liftM read (many1_ digit)+        case sign of+            Just '-' -> return (-num)+            _ -> return num++-- | 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))+        case sign of+            Just '-' -> return (-(read (whole ++ fractional)))+            _ -> return (read (whole ++ fractional))++-- | 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))+        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