packages feed

parser-combinators (empty) → 0.1.0

raw patch · 6 files changed

+376/−0 lines, 6 filesdep +basesetup-changed

Dependencies added: base

Files

+ 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++[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)+[![Hackage](https://img.shields.io/hackage/v/parser-combinators.svg?style=flat)](https://hackage.haskell.org/package/parser-combinators)+[![Stackage Nightly](http://stackage.org/package/parser-combinators/badge/nightly)](http://stackage.org/nightly/package/parser-combinators)+[![Stackage LTS](http://stackage.org/package/parser-combinators/badge/lts)](http://stackage.org/lts/package/parser-combinators)+[![Build Status](https://travis-ci.org/mrkkrp/parser-combinators.svg?branch=master)](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