parser-combinators (empty) → 0.1.0
raw patch · 6 files changed
+376/−0 lines, 6 filesdep +basesetup-changed
Dependencies added: base
Files
- CHANGELOG.md +3/−0
- Control/Applicative/Combinators.hs +281/−0
- LICENSE.md +28/−0
- README.md +24/−0
- Setup.hs +6/−0
- parser-combinators.cabal +34/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## Parser combinators 0.1.0++* Initial release.
+ Control/Applicative/Combinators.hs view
@@ -0,0 +1,281 @@+-- |+-- Module : Control.Applicative.Combinators+-- Copyright : © 2017 Mark Karpov+-- License : BSD 3 clause+--+-- Maintainer : Mark Karpov <markkarpov92@gmail.com>+-- Stability : experimental+-- Portability : portable+--+-- The module provides parser combinators defined for instances of+-- 'Applicative' and 'Alternative'. It also re-exports functions that are+-- commonly used in parsing from "Control.Applicative" with additional+-- parsing-related comments added.+--+-- === A note on backtracking+--+-- Certain parsing libraries, such as Megaparsec, do not backtrack every+-- branch of parsing automatically for the sake of performance and better+-- error messages. They typically backtrack only “atomic” parsers, e.g.+-- those that match a token or several tokens in a row. To backtrack an+-- arbitrary complex parser\/branch, a special combinator should be used,+-- typically called @try@. Combinators in this module are defined in terms+-- 'Applicative' and 'Alternative' operations. Being quite abstract, they+-- cannot know anything about inner workings of any concrete parsing+-- library, and so they cannot use @try@.+--+-- An essential feature of the 'Alternative' type class is the @('<|>')@+-- operator that allows to express choice. In libraries that do not+-- backtrack everything automatically, the choice operator and everything+-- that is build on top of it require the parser of the left hand side to+-- backtrack in order for the other alternative branch of paring to be+-- tried. Thus it is the responsibility of the programmer to wrap more+-- complex, composite parsers in @try@ to achieve correct behavior.++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}++module Control.Applicative.Combinators+ ( -- * Re-exports from "Control.Applicative"+ (<|>)+ -- $assocbo+ , many+ -- $many+ , some+ -- $some+ , optional+ -- $optional++ -- * Original combinators+ , between+ , choice+ , count+ , count'+ , eitherP+ , endBy+ , endBy1+ , manyTill+ , someTill+ , option+ , sepBy+ , sepBy1+ , sepEndBy+ , sepEndBy1+ , skipMany+ , skipSome+ , skipManyTill+ , skipSomeTill )+where++import Control.Applicative+import Data.Foldable++#if !MIN_VERSION_base(4,8,0)+import Data.Traversable (sequenceA)+#endif++----------------------------------------------------------------------------+-- Re-exports from "Control.Applicative"++-- $assocbo+--+-- This combinator implements choice. The parser @p '<|>' q@ first applies+-- @p@. If it succeeds, the value of @p@ is returned. If @p@ fails, parser+-- @q@ is tried.++-- $many+--+-- @'many' p@ applies the parser @p@ /zero/ or more times and returns a list+-- of the returned values of @p@.+--+-- > identifier = (:) <$> letter <*> many (alphaNumChar <|> char '_')++-- $some+--+-- @'some' p@ applies the parser @p@ /one/ or more times and returns a list+-- of the returned values of @p@.+--+-- > word = some letter++-- $optional+--+-- @'optional' p@ tries to apply the parser @p@. It will parse @p@ or+-- 'Nothing'. It only fails if @p@ fails after consuming input. On success+-- result of @p@ is returned inside of 'Just', on failure 'Nothing' is+-- returned.+--+-- See also: 'option'.++----------------------------------------------------------------------------+-- Original combinators++-- | @'between' open close p@ parses @open@, followed by @p@ and @close@.+-- Returns the value returned by @p@.+--+-- > braces = between (symbol "{") (symbol "}")++between :: Applicative m => m open -> m close -> m a -> m a+between open close p = open *> p <* close+{-# INLINE between #-}++-- | @'choice' ps@ tries to apply the parsers in the list @ps@ in order,+-- until one of them succeeds. Returns the value of the succeeding parser.++choice :: (Foldable f, Alternative m) => f (m a) -> m a+choice = asum+{-# INLINE choice #-}++-- | @'count' n p@ parses @n@ occurrences of @p@. If @n@ is smaller or equal+-- to zero, the parser equals to @'pure' []@. Returns a list of @n@ values.+--+-- See also: 'count''.++count :: Applicative m => Int -> m a -> m [a]+count n p = sequenceA (replicate n p)+{-# INLINE count #-}++-- | @'count'' m n p@ parses from @m@ to @n@ occurrences of @p@. If @n@ is+-- not positive or @m > n@, the parser equals to @'pure' []@. Returns a list+-- of parsed values.+--+-- Please note that @m@ /may/ be negative, in this case effect is the same+-- as if it were equal to zero.+--+-- See also: 'count'.++count' :: Alternative m => Int -> Int -> m a -> m [a]+count' m' n' p = go m' n'+ where+ go !m !n+ | n <= 0 || m > n = pure []+ | m > 0 = (:) <$> p <*> go (m - 1) (n - 1)+ | otherwise =+ let f t ts = maybe [] (:ts) t+ in f <$> optional p <*> go 0 (pred n)+{-# INLINE count' #-}++-- | Combine two alternatives.++eitherP :: Alternative m => m a -> m b -> m (Either a b)+eitherP a b = (Left <$> a) <|> (Right <$> b)+{-# INLINE eitherP #-}++-- | @'endBy' p sep@ parses /zero/ or more occurrences of @p@, separated and+-- ended by @sep@. Returns a list of values returned by @p@.+--+-- > cStatements = cStatement `endBy` semicolon++endBy :: Alternative m => m a -> m sep -> m [a]+endBy p sep = many (p <* sep)+{-# INLINE endBy #-}++-- | @'endBy1' p sep@ parses /one/ or more occurrences of @p@, separated and+-- ended by @sep@. Returns a list of values returned by @p@.++endBy1 :: Alternative m => m a -> m sep -> m [a]+endBy1 p sep = some (p <* sep)+{-# INLINE endBy1 #-}++-- | @'manyTill' p end@ applies parser @p@ /zero/ or more times until parser+-- @end@ succeeds. Returns the list of values returned by @p@.+--+-- See also: 'skipMany', 'skipManyTill'.++manyTill :: Alternative m => m a -> m end -> m [a]+manyTill p end = go+ where+ go = ([] <$ end) <|> ((:) <$> p <*> go)+{-# INLINE manyTill #-}++-- | @'someTill' p end@ works similarly to @'manyTill' p end@, but @p@+-- should succeed at least once.+--+-- See also: 'skipSome', 'skipSomeTill'.++someTill :: Alternative m => m a -> m end -> m [a]+someTill p end = (:) <$> p <*> manyTill p end+{-# INLINE someTill #-}++-- | @'option' x p@ tries to apply the parser @p@. If @p@ fails without+-- consuming input, it returns the value @x@, otherwise the value returned+-- by @p@.+--+-- > priority = option 0 (digitToInt <$> digitChar)+--+-- See also: 'optional'.++option :: Alternative m => a -> m a -> m a+option x p = p <|> pure x+{-# INLINE option #-}++-- | @'sepBy' p sep@ parses /zero/ or more occurrences of @p@, separated by+-- @sep@. Returns a list of values returned by @p@.+--+-- > commaSep p = p `sepBy` comma++sepBy :: Alternative m => m a -> m sep -> m [a]+sepBy p sep = sepBy1 p sep <|> pure []+{-# INLINE sepBy #-}++-- | @'sepBy1' p sep@ parses /one/ or more occurrences of @p@, separated by+-- @sep@. Returns a list of values returned by @p@.++sepBy1 :: Alternative m => m a -> m sep -> m [a]+sepBy1 p sep = (:) <$> p <*> many (sep *> p)+{-# INLINE sepBy1 #-}++-- | @'sepEndBy' p sep@ parses /zero/ or more occurrences of @p@, separated+-- and optionally ended by @sep@. Returns a list of values returned by @p@.++sepEndBy :: Alternative m => m a -> m sep -> m [a]+sepEndBy p sep = sepEndBy1 p sep <|> pure []+{-# INLINE sepEndBy #-}++-- | @'sepEndBy1' p sep@ parses /one/ or more occurrences of @p@, separated+-- and optionally ended by @sep@. Returns a list of values returned by @p@.++sepEndBy1 :: Alternative m => m a -> m sep -> m [a]+sepEndBy1 p sep = (:) <$> p <*> ((sep *> sepEndBy p sep) <|> pure [])+{-# INLINEABLE sepEndBy1 #-}++-- | @'skipMany' p@ applies the parser @p@ /zero/ or more times, skipping+-- its result.+--+-- See also: 'manyTill', 'skipManyTill'.++skipMany :: Alternative m => m a -> m ()+skipMany p = go+ where+ go = (p *> go) <|> pure ()+{-# INLINE skipMany #-}++-- | @'skipSome' p@ applies the parser @p@ /one/ or more times, skipping its+-- result.+--+-- See also: 'someTill', 'skipSomeTill'.++skipSome :: Alternative m => m a -> m ()+skipSome p = p *> skipMany p+{-# INLINE skipSome #-}++-- | @'skipManyTill' p end@ applies the parser @p@ /zero/ or more times+-- skipping results until parser @end@ succeeds. Result parsed by @end@ is+-- then returned.+--+-- See also: 'manyTill', 'skipMany'.++skipManyTill :: Alternative m => m a -> m end -> m end+skipManyTill p end = go+ where+ go = end <|> (p *> go)+{-# INLINE skipManyTill #-}++-- | @'skipSomeTill' p end@ applies the parser @p@ /one/ or more times+-- skipping results until parser @end@ succeeds. Result parsed by @end@ is+-- then returned.+--+-- See also: 'someTill', 'skipSome'.++skipSomeTill :: Alternative m => m a -> m end -> m end+skipSomeTill p end = p *> skipManyTill p end+{-# INLINE skipSomeTill #-}
+ LICENSE.md view
@@ -0,0 +1,28 @@+Copyright © 2017 Mark Karpov++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++* Neither the name Mark Karpov nor the names of contributors may be used to+ endorse or promote products derived from this software without specific+ prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS “AS IS” AND ANY EXPRESS+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN+NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,24 @@+# Parser combinators++[](http://opensource.org/licenses/BSD-3-Clause)+[](https://hackage.haskell.org/package/parser-combinators)+[](http://stackage.org/nightly/package/parser-combinators)+[](http://stackage.org/lts/package/parser-combinators)+[](https://travis-ci.org/mrkkrp/parser-combinators)++The package provides common parser combinators defined in terms of+`Applicative` and `Alternative` without any dependencies but `base`. Test+suite and benchmarks can be found in the [Megaparsec repo](https://github.com/mrkkrp/megaparsec).++## Contribution++Issues, bugs, and questions may be reported in [the GitHub issue tracker for+this project](https://github.com/mrkkrp/parser-combinators/issues).++Pull requests are also welcome and will be reviewed quickly.++## License++Copyright © 2017 Mark Karpov++Distributed under BSD 3 clause license.
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMain
+ parser-combinators.cabal view
@@ -0,0 +1,34 @@+name: parser-combinators+version: 0.1.0+cabal-version: >= 1.10+tested-with: GHC==7.4.2, GHC==7.6.3, GHC==7.8.4, GHC==7.10.3, GHC==8.0.2, GHC==8.2.1+license: BSD3+license-file: LICENSE.md+author: Mark Karpov <markkarpov92@gmail.com>+maintainer: Mark Karpov <markkarpov92@gmail.com>+homepage: https://github.com/mrkkrp/parser-combinators+bug-reports: https://github.com/mrkkrp/parser-combinators/issues+category: Parsing+synopsis: Lightweight package providing commonly useful parser combinators+build-type: Simple+description: Lightweight package providing commonly useful parser combinators.+extra-doc-files: CHANGELOG.md+ , README.md++source-repository head+ type: git+ location: https://github.com/mrkkrp/parser-combinators.git++flag dev+ description: Turn on development settings.+ manual: True+ default: False++library+ build-depends: base >= 4.5 && < 5.0+ exposed-modules: Control.Applicative.Combinators+ if flag(dev)+ ghc-options: -Wall -Werror+ else+ ghc-options: -O2 -Wall+ default-language: Haskell2010