Hello community,
here is the log from the commit of package ghc-regex-applicative for
openSUSE:Factory checked in at 2020-09-07 21:22:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-regex-applicative (Old)
and /work/SRC/openSUSE:Factory/.ghc-regex-applicative.new.3399 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-regex-applicative"
Mon Sep 7 21:22:12 2020 rev:9 rq:831222 version:0.3.4
Changes:
--------
---
/work/SRC/openSUSE:Factory/ghc-regex-applicative/ghc-regex-applicative.changes
2019-12-27 13:56:28.488748362 +0100
+++
/work/SRC/openSUSE:Factory/.ghc-regex-applicative.new.3399/ghc-regex-applicative.changes
2020-09-07 21:22:16.205020254 +0200
@@ -1,0 +2,11 @@
+Tue Sep 1 14:41:27 UTC 2020 - [email protected]
+
+- Update regex-applicative to version 0.3.4.
+ 0.3.4
+ -----
+
+ * Let the user provide a custom `uncons` function (add
+ `find{First,Longest,Shortest}PrefixWithUncons`)
+ * Add `Filtrable` and `Monoid` instances for `RE`
+
+-------------------------------------------------------------------
Old:
----
regex-applicative-0.3.3.1.tar.gz
New:
----
regex-applicative-0.3.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-regex-applicative.spec ++++++
--- /var/tmp/diff_new_pack.JssoXz/_old 2020-09-07 21:22:19.525021777 +0200
+++ /var/tmp/diff_new_pack.JssoXz/_new 2020-09-07 21:22:19.529021779 +0200
@@ -1,7 +1,7 @@
#
# spec file for package ghc-regex-applicative
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
%global pkg_name regex-applicative
%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 0.3.3.1
+Version: 0.3.4
Release: 0
Summary: Regex-based parsing with applicative interface
License: MIT
@@ -27,6 +27,7 @@
Source0:
https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz
BuildRequires: ghc-Cabal-devel
BuildRequires: ghc-containers-devel
+BuildRequires: ghc-filtrable-devel
BuildRequires: ghc-rpm-macros
BuildRequires: ghc-transformers-devel
%if %{with tests}
@@ -52,7 +53,7 @@
files.
%prep
-%setup -q -n %{pkg_name}-%{version}
+%autosetup -n %{pkg_name}-%{version}
%build
%ghc_lib_build
++++++ regex-applicative-0.3.3.1.tar.gz -> regex-applicative-0.3.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/regex-applicative-0.3.3.1/CHANGES.md
new/regex-applicative-0.3.4/CHANGES.md
--- old/regex-applicative-0.3.3.1/CHANGES.md 2019-08-18 22:57:42.000000000
+0200
+++ new/regex-applicative-0.3.4/CHANGES.md 2020-07-24 11:43:05.000000000
+0200
@@ -1,6 +1,13 @@
Changes
=======
+0.3.4
+-----
+
+* Let the user provide a custom `uncons` function (add
+ `find{First,Longest,Shortest}PrefixWithUncons`)
+* Add `Filtrable` and `Monoid` instances for `RE`
+
0.3.3.1
-------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/regex-applicative-0.3.3.1/README.md
new/regex-applicative-0.3.4/README.md
--- old/regex-applicative-0.3.3.1/README.md 2013-08-06 23:30:46.000000000
+0200
+++ new/regex-applicative-0.3.4/README.md 2020-01-31 22:46:54.000000000
+0100
@@ -1,41 +1,64 @@
regex-applicative
=================
-*regex-applicative* is aimed to be an efficient and easy to use parsing
combinator
-library for Haskell based on regular expressions.
+*regex-applicative* is a parsing combinator library for Haskell based on
regular
+expressions.
-Perl programmers often use regular expressions for parsing, even if it is not
-an appropriate tool for the job, because Perl has so good support for regexps.
+Example
+-------
-The opposite seems to be valid about Haskell programmers -- they use parsing
-combinators (which recognize context-free or even context-sensitive grammars),
-even when the language is actually regular!
+``` haskell
+import Text.Regex.Applicative
-Hopefully, this library will improve the situation.
+data Protocol = HTTP | FTP deriving Show
-Installation
-------------
-Install this library using `cabal-install` tool:
+protocol :: RE Char Protocol
+protocol = HTTP <$ string "http" <|> FTP <$ string "ftp"
- cabal update
- cabal install regex-applicative
+type Host = String
+type Location = String
+data URL = URL Protocol Host Location deriving Show
+
+host :: RE Char Host
+host = many $ psym $ (/= '/')
+
+url :: RE Char URL
+url = URL <$> protocol <* string "://" <*> host <* sym '/' <*> many anySym
+
+main = print $ "http://stackoverflow.com/questions" =~ url
+```
Documentation
-------------
-The [API reference][haddock] is available from Hackage.
-To get started, see some [examples][examples] on the wiki.
+See the [API reference][haddock].
+
+Performance
+-----------
+
+For common tasks, this package is several times slower than monadic
+parser combinator libraries like parsec. However, this library has a roughly
+linear complexity, whereas monadic parser combinators have exponential
+worst-time complexity (see [here](https://swtch.com/~rsc/regexp/regexp1.html)).
+
+Some tips to make your regex run faster:
+
+1. If you don't care about the result of the whole regex or its part, only
+ whether it matches or not, mark it with `void` or `<$`. Recognition is
faster
+ than parsing.
+1. If you apply the same regex to multiple strings, partially apply it like so:
+
+ ```
+ let matcher = match my_regex
+ in map matcher my_strings
+ ```
-Other resources
----------------
+ This way the compiled regex is stored in the `matcher` value and shared
among
+ the strings.
-* [This package on Hackage][hackage]
-* [Issue tracker][issues]
-* [Repository][github]
+GHC support
+-----------
+Only GHC versions >= 8.0 are supported, although older versions may work too.
-[examples]: https://github.com/feuerbach/regex-applicative/wiki/Examples
[haddock]:
http://hackage.haskell.org/packages/archive/regex-applicative/latest/doc/html/Text-Regex-Applicative.html
-[hackage]: http://hackage.haskell.org/package/regex-applicative
-[issues]: https://github.com/feuerbach/regex-applicative/issues
-[github]: https://github.com/feuerbach/regex-applicative
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Compile.hs
new/regex-applicative-0.3.4/Text/Regex/Applicative/Compile.hs
--- old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Compile.hs
2015-07-03 13:03:30.000000000 +0200
+++ new/regex-applicative-0.3.4/Text/Regex/Applicative/Compile.hs
2020-07-24 11:37:31.000000000 +0200
@@ -1,12 +1,13 @@
{-# LANGUAGE GADTs #-}
-{-# OPTIONS_GHC -fno-do-lambda-eta-expansion #-}
module Text.Regex.Applicative.Compile (compile) where
+import Control.Monad ((<=<))
import Control.Monad.Trans.State
-import Text.Regex.Applicative.Types
-import Control.Applicative
+import Data.Foldable
import Data.Maybe
+import Data.Monoid (Any (..))
import qualified Data.IntMap as IntMap
+import Text.Regex.Applicative.Types
compile :: RE s a -> (a -> [Thread s r]) -> [Thread s r]
compile e k = compile2 e (SingleCont k)
@@ -30,15 +31,6 @@
SingleCont a -> a
EmptyNonEmpty _ a -> a
--- The whole point of this module is this function, compile2, which needs to be
--- compiled with -fno-do-lambda-eta-expansion for efficiency.
---
--- Since this option would make other code perform worse, we place this
--- function in a separate module and make sure it's not inlined.
---
--- The point of "-fno-do-lambda-eta-expansion" is to make sure the tree is
--- "compiled" only once.
---
-- compile2 function takes two continuations: one when the match is empty and
-- one when the match is non-empty. See the "Rep" case for the reason.
compile2 :: RE s a -> Cont (a -> [Thread s r]) -> [Thread s r]
@@ -68,6 +60,7 @@
in \k -> a1 k ++ a2 k
Fail -> const []
Fmap f n -> let a = compile2 n in \k -> a $ fmap (. f) k
+ CatMaybes n -> let a = compile2 n in \k -> a $ (<=< toList) <$> k
-- This is actually the point where we use the difference between
-- continuations. For the inner RE the empty continuation is a
-- "failing" one in order to avoid non-termination.
@@ -78,11 +71,13 @@
(a $ EmptyNonEmpty (\_ -> []) (\v -> let b' = f b v in
threads b' (SingleCont $ nonEmptyCont k)))
(emptyCont k b)
in threads b
- Void n -> let a = compile2_ n in \k -> a $ fmap ($ ()) k
+ Void n
+ | hasCatMaybes n -> compile2 n . fmap (. \ _ -> ())
+ | otherwise -> compile2_ n . fmap ($ ())
data FSMState
= SAccept
- | STransition ThreadId
+ | STransition !ThreadId
type FSMMap s = IntMap.IntMap (s -> Bool, [FSMState])
@@ -103,6 +98,7 @@
Alt n1 n2 -> (++) <$> go n1 k <*> go n2 k
Fail -> return []
Fmap _ n -> go n k
+ CatMaybes _ -> error "mkNFA CatMaybes"
Rep g _ _ n ->
let entries = findEntries n
cont = combine g entries k
@@ -118,6 +114,9 @@
-- just to use 'go'
evalState (go e []) IntMap.empty
+hasCatMaybes :: RE s a -> Bool
+hasCatMaybes = getAny . foldMapPostorder (Any . \ case CatMaybes _ -> True; _
-> False)
+
compile2_ :: RE s a -> Cont [Thread s r] -> [Thread s r]
compile2_ e =
let (entries, fsmap) = mkNFA e
@@ -131,6 +130,7 @@
in \k -> concatMap (mkThread (emptyCont k) (nonEmptyCont k)) entries
+combine :: Greediness -> [a] -> [a] -> [a]
combine g continue stop =
case g of
Greedy -> continue ++ stop
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Interface.hs
new/regex-applicative-0.3.4/Text/Regex/Applicative/Interface.hs
--- old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Interface.hs
2015-12-27 09:32:10.000000000 +0100
+++ new/regex-applicative-0.3.4/Text/Regex/Applicative/Interface.hs
2020-07-24 11:43:05.000000000 +0200
@@ -1,34 +1,13 @@
{-# LANGUAGE TypeFamilies, GADTs, TupleSections #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
module Text.Regex.Applicative.Interface where
import Control.Applicative hiding (empty)
-import qualified Control.Applicative
import Control.Arrow
-import Data.Traversable
-import Data.String
+import Control.Monad (guard)
+import qualified Data.List as List
import Data.Maybe
import Text.Regex.Applicative.Types
import Text.Regex.Applicative.Object
-instance Functor (RE s) where
- fmap f x = Fmap f x
- f <$ x = pure f <* x
-
-instance Applicative (RE s) where
- pure x = const x <$> Eps
- a1 <*> a2 = App a1 a2
- a *> b = pure (const id) <*> Void a <*> b
- a <* b = pure const <*> a <*> Void b
-
-instance Alternative (RE s) where
- a1 <|> a2 = Alt a1 a2
- empty = Fail
- many a = reverse <$> Rep Greedy (flip (:)) [] a
- some a = (:) <$> a <*> many a
-
-instance (char ~ Char, string ~ String) => IsString (RE char string) where
- fromString = string
-
-- | 'RE' is a profunctor. This is its contravariant map.
--
-- (A dependency on the @profunctors@ package doesn't seem justified.)
@@ -40,44 +19,15 @@
Alt r1 r2 -> Alt (comap f r1) (comap f r2)
App r1 r2 -> App (comap f r1) (comap f r2)
Fmap g r -> Fmap g (comap f r)
+ CatMaybes r -> CatMaybes (comap f r)
Fail -> Fail
Rep gr fn a r -> Rep gr fn a (comap f r)
Void r -> Void (comap f r)
--- | Match and return a single symbol which satisfies the predicate
-psym :: (s -> Bool) -> RE s s
-psym p = msym (\s -> if p s then Just s else Nothing)
-
--- | Like 'psym', but allows to return a computed value instead of the
--- original symbol
-msym :: (s -> Maybe a) -> RE s a
-msym p = Symbol (error "Not numbered symbol") p
-
--- | Match and return the given symbol
-sym :: Eq s => s -> RE s s
-sym s = psym (s ==)
-
-- | Match and return any single symbol
anySym :: RE s s
anySym = msym Just
--- | Match and return the given sequence of symbols.
---
--- Note that there is an 'IsString' instance for regular expression, so
--- if you enable the @OverloadedStrings@ language extension, you can write
--- @string \"foo\"@ simply as @\"foo\"@.
---
--- Example:
---
--- >{-# LANGUAGE OverloadedStrings #-}
--- >import Text.Regex.Applicative
--- >
--- >number = "one" *> pure 1 <|> "two" *> pure 2
--- >
--- >main = print $ "two" =~ number
-string :: Eq a => [a] -> RE a [a]
-string = traverse sym
-
-- | Match zero or more instances of the given expression, which are combined
using
-- the given folding function.
--
@@ -111,6 +61,8 @@
withMatched b
withMatched Fail = Fail
withMatched (Fmap f x) = (f *** id) <$> withMatched x
+withMatched (CatMaybes x) = CatMaybes $
+ (\ (as, s) -> flip (,) s <$> as) <$> withMatched x
withMatched (Rep gr f a0 x) =
Rep gr (\(a, s) (x, t) -> (f a x, s ++ t)) (a0, []) (withMatched x)
-- N.B.: this ruins the Void optimization
@@ -147,6 +99,8 @@
--
-- If match is found, the rest of the input is also returned.
--
+-- See also 'findFirstPrefixWithUncons', of which this is a special case.
+--
-- Examples:
--
-- >Text.Regex.Applicative> findFirstPrefix ("a" <|> "ab") "abc"
@@ -156,24 +110,20 @@
-- >Text.Regex.Applicative> findFirstPrefix "bc" "abc"
-- >Nothing
findFirstPrefix :: RE s a -> [s] -> Maybe (a, [s])
-findFirstPrefix re str = go (compile re) str Nothing
- where
+findFirstPrefix = findFirstPrefixWithUncons List.uncons
+
+-- | Find the first prefix, with the given @uncons@ function.
+--
+-- @since 0.3.4
+findFirstPrefixWithUncons :: (ss -> Maybe (s, ss)) -> RE s a -> ss -> Maybe
(a, ss)
+findFirstPrefixWithUncons = findPrefixWith' (walk emptyObject . threads)
+ where
walk obj [] = (obj, Nothing)
walk obj (t:ts) =
case getResult t of
Just r -> (obj, Just r)
Nothing -> walk (addThread t obj) ts
- go obj str resOld =
- case walk emptyObject $ threads obj of
- (obj', resThis) ->
- let res = ((flip (,) str) <$> resThis) <|> resOld
- in
- case str of
- _ | failed obj' -> res
- [] -> res
- (s:ss) -> go (step s obj') ss res
-
-- | Find the longest string prefix which is matched by the regular expression.
--
-- Submatches are still determined using left bias and greediness, so this is
@@ -181,6 +131,8 @@
--
-- If match is found, the rest of the input is also returned.
--
+-- See also 'findLongestPrefixWithUncons', of which this is a special case.
+--
-- Examples:
--
-- >Text.Regex.Applicative Data.Char> let keyword = "if"
@@ -191,28 +143,49 @@
-- >Text.Regex.Applicative Data.Char> findLongestPrefix lexeme "iffoo"
-- >Just (Right "iffoo","")
findLongestPrefix :: RE s a -> [s] -> Maybe (a, [s])
-findLongestPrefix re str = go (compile re) str Nothing
- where
- go obj str resOld =
- let res = (fmap (flip (,) str) $ listToMaybe $ results obj) <|> resOld
- in
- case str of
- _ | failed obj -> res
- [] -> res
- (s:ss) -> go (step s obj) ss res
+findLongestPrefix = findLongestPrefixWithUncons List.uncons
+
+-- | Find the longest prefix, with the given @uncons@ function.
+--
+-- @since 0.3.4
+findLongestPrefixWithUncons :: (ss -> Maybe (s, ss)) -> RE s a -> ss -> Maybe
(a, ss)
+findLongestPrefixWithUncons = findPrefixWith' ((,) <*> listToMaybe . results)
+
+findPrefixWith'
+ :: (ReObject s a -> (ReObject s a, Maybe a))
+ -- ^ Given the regex object, compute the regex object to feed the next input
value into, and
+ -- the result, if any.
+ -> (ss -> Maybe (s, ss)) -- ^ @uncons@
+ -> RE s a -> ss -> Maybe (a, ss)
+findPrefixWith' walk uncons = \ re -> go (compile re) Nothing
+ where
+ go obj resOld ss = case walk obj of
+ (obj', resThis) ->
+ let res = flip (,) ss <$> resThis <|> resOld
+ in
+ case uncons ss of
+ _ | failed obj' -> res
+ Nothing -> res
+ Just (s, ss) -> go (step s obj') res ss
-- | Find the shortest prefix (analogous to 'findLongestPrefix')
+--
+-- See also 'findShortestPrefixWithUncons', of which this is a special case.
findShortestPrefix :: RE s a -> [s] -> Maybe (a, [s])
-findShortestPrefix re str = go (compile re) str
- where
- go obj str =
- case results obj of
- r : _ -> Just (r, str)
- _ | failed obj -> Nothing
- _ ->
- case str of
- [] -> Nothing
- s:ss -> go (step s obj) ss
+findShortestPrefix = findShortestPrefixWithUncons List.uncons
+
+-- | Find the shortest prefix (analogous to 'findLongestPrefix'), with the
given @uncons@ function.
+--
+-- @since 0.3.4
+findShortestPrefixWithUncons :: (ss -> Maybe (s, ss)) -> RE s a -> ss -> Maybe
(a, ss)
+findShortestPrefixWithUncons uncons = go . compile
+ where
+ go obj ss = case results obj of
+ r:_ -> Just (r, ss)
+ _ -> do
+ guard (not (failed obj))
+ (s, ss) <- uncons ss
+ go (step s obj) ss
-- | Find the leftmost substring that is matched by the regular expression.
-- Otherwise behaves like 'findFirstPrefix'. Returns the result together with
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Object.hs
new/regex-applicative-0.3.4/Text/Regex/Applicative/Object.hs
--- old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Object.hs
2015-05-30 18:38:42.000000000 +0200
+++ new/regex-applicative-0.3.4/Text/Regex/Applicative/Object.hs
2020-07-24 11:37:31.000000000 +0200
@@ -34,7 +34,6 @@
import Data.Maybe
import Data.Foldable as F
import Control.Monad.Trans.State
-import Control.Applicative hiding (empty)
-- | The state of the engine is represented as a \"regex object\" of type
-- @'ReObject' s r@, where @s@ is the type of symbols and @r@ is the
@@ -116,19 +115,9 @@
renumber
renumber :: RE s a -> RE s a
-renumber e = flip evalState (ThreadId 1) $ go e
- where
- go :: RE s a -> State ThreadId (RE s a)
- go e =
- case e of
- Eps -> return Eps
- Symbol _ p -> Symbol <$> fresh <*> pure p
- Alt a1 a2 -> Alt <$> go a1 <*> go a2
- App a1 a2 -> App <$> go a1 <*> go a2
- Fail -> return Fail
- Fmap f a -> Fmap f <$> go a
- Rep g f b a -> Rep g f b <$> go a
- Void a -> Void <$> go a
+renumber =
+ flip evalState (ThreadId 1) .
+ traversePostorder (\ case Symbol _ p -> flip Symbol p <$> fresh; a -> pure
a)
fresh :: State ThreadId ThreadId
fresh = do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Reference.hs
new/regex-applicative-0.3.4/Text/Regex/Applicative/Reference.hs
--- old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Reference.hs
2015-07-03 13:09:24.000000000 +0200
+++ new/regex-applicative-0.3.4/Text/Regex/Applicative/Reference.hs
2020-07-24 11:37:31.000000000 +0200
@@ -58,6 +58,7 @@
Alt a1 a2 -> re2monad a1 <|> re2monad a2
App a1 a2 -> re2monad a1 <*> re2monad a2
Fmap f a -> fmap f $ re2monad a
+ CatMaybes a -> maybe empty pure =<< re2monad a
Rep g f b a -> rep b
where
am = re2monad a
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/regex-applicative-0.3.3.1/Text/Regex/Applicative/StateQueue.hs
new/regex-applicative-0.3.4/Text/Regex/Applicative/StateQueue.hs
--- old/regex-applicative-0.3.3.1/Text/Regex/Applicative/StateQueue.hs
2015-05-30 17:28:32.000000000 +0200
+++ new/regex-applicative-0.3.4/Text/Regex/Applicative/StateQueue.hs
2020-01-31 22:46:54.000000000 +0100
@@ -1,5 +1,6 @@
-- | This internal module is exposed only for testing and benchmarking. You
-- don't need to import it.
+{-# LANGUAGE RecordWildCards #-}
module Text.Regex.Applicative.StateQueue
( StateQueue
, empty
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Types.hs
new/regex-applicative-0.3.4/Text/Regex/Applicative/Types.hs
--- old/regex-applicative-0.3.3.1/Text/Regex/Applicative/Types.hs
2015-07-03 13:02:36.000000000 +0200
+++ new/regex-applicative-0.3.4/Text/Regex/Applicative/Types.hs 2020-07-24
11:43:05.000000000 +0200
@@ -1,12 +1,17 @@
{-# LANGUAGE GADTs #-}
-{-# OPTIONS_GHC -fno-do-lambda-eta-expansion -fno-warn-unused-imports #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE CPP #-}
module Text.Regex.Applicative.Types where
import Control.Applicative
--- The above import is needed for haddock to properly generate links to
--- Applicative methods. But it's not actually used in the code, hence
--- -fno-warn-unused-imports.
-
+import Control.Monad ((<=<))
+import Data.Filtrable (Filtrable (..))
+import Data.Functor.Identity (Identity (..))
+import Data.String
+#if !MIN_VERSION_base(4,11,0)
+import Data.Semigroup
+#endif
newtype ThreadId = ThreadId Int
@@ -31,8 +36,8 @@
-- | Type of regular expressions that recognize symbols of type @s@ and
-- produce a result of type @a@.
--
--- Regular expressions can be built using 'Functor', 'Applicative' and
--- 'Alternative' instances in the following natural way:
+-- Regular expressions can be built using 'Functor', 'Applicative',
+-- 'Alternative', and 'Filtrable' instances in the following natural way:
--
-- * @f@ '<$>' @ra@ matches iff @ra@ matches, and its return value is the
result
-- of applying @f@ to the return value of @ra@.
@@ -55,12 +60,23 @@
--
-- * 'some' @ra@ matches concatenation of one or more strings matched by @ra@
-- and returns the list of @ra@'s return values on those strings.
+--
+-- * 'catMaybes' @ram@ matches iff @ram@ matches and produces 'Just _'.
+--
+-- * @ra@ '<>' @rb@ matches @ra@ followed by @rb@. The return value is @a <>
b@,
+-- where @a@ and @b@ are the return values of @ra@ and @rb@ respectively.
+-- (See
<https://github.com/feuerbach/regex-applicative/issues/37#issue-499781703>
+-- for an example usage.)
+--
+-- * 'mempty' matches the empty string (i.e. it does not consume any symbols),
+-- and its return value is the 'mempty' value of type @a@.
data RE s a where
Eps :: RE s ()
Symbol :: ThreadId -> (s -> Maybe a) -> RE s a
Alt :: RE s a -> RE s a -> RE s a
App :: RE s (a -> b) -> RE s a -> RE s b
Fmap :: (a -> b) -> RE s a -> RE s b
+ CatMaybes :: RE s (Maybe a) -> RE s a
Fail :: RE s a
Rep :: Greediness -- repetition may be greedy or not
-> (b -> a -> b) -- folding function (like in foldl)
@@ -69,3 +85,88 @@
-> RE s a
-> RE s b
Void :: RE s a -> RE s ()
+
+-- | Traverse each (reflexive, transitive) subexpression of a 'RE',
depth-first and post-order.
+traversePostorder :: forall s a m . Monad m => (forall a . RE s a -> m (RE s
a)) -> RE s a -> m (RE s a)
+traversePostorder f = go
+ where
+ go :: forall a . RE s a -> m (RE s a)
+ go = f <=< \ case
+ Eps -> pure Eps
+ Symbol i p -> pure (Symbol i p)
+ Alt a b -> Alt <$> go a <*> go b
+ App a b -> App <$> go a <*> go b
+ Fmap g a -> Fmap g <$> go a
+ CatMaybes a -> CatMaybes <$> go a
+ Fail -> pure Fail
+ Rep greed g b a -> Rep greed g b <$> go a
+ Void a -> Void <$> go a
+
+-- | Fold each (reflexive, transitive) subexpression of a 'RE', depth-first
and post-order.
+foldMapPostorder :: Monoid b => (forall a . RE s a -> b) -> RE s a -> b
+foldMapPostorder f = fst . traversePostorder ((,) <$> f <*> id)
+
+-- | Map each (reflexive, transitive) subexpression of a 'RE'.
+mapRE :: (forall a . RE s a -> RE s a) -> RE s a -> RE s a
+mapRE f = runIdentity . traversePostorder (Identity . f)
+
+instance Functor (RE s) where
+ fmap f x = Fmap f x
+ f <$ x = pure f <* x
+
+instance Applicative (RE s) where
+ pure x = const x <$> Eps
+ a1 <*> a2 = App a1 a2
+ a *> b = pure (const id) <*> Void a <*> b
+ a <* b = pure const <*> a <*> Void b
+
+instance Alternative (RE s) where
+ a1 <|> a2 = Alt a1 a2
+ empty = Fail
+ many a = reverse <$> Rep Greedy (flip (:)) [] a
+ some a = (:) <$> a <*> many a
+
+-- | @since 0.3.4
+instance Filtrable (RE s) where
+ catMaybes = CatMaybes
+
+instance (char ~ Char, string ~ String) => IsString (RE char string) where
+ fromString = string
+
+-- | @since 0.3.4
+instance Semigroup a => Semigroup (RE s a) where
+ x <> y = (<>) <$> x <*> y
+
+-- | @since 0.3.4
+instance Monoid a => Monoid (RE s a) where
+ mempty = pure mempty
+
+-- | Match and return the given sequence of symbols.
+--
+-- Note that there is an 'IsString' instance for regular expression, so
+-- if you enable the @OverloadedStrings@ language extension, you can write
+-- @string \"foo\"@ simply as @\"foo\"@.
+--
+-- Example:
+--
+-- >{-# LANGUAGE OverloadedStrings #-}
+-- >import Text.Regex.Applicative
+-- >
+-- >number = "one" *> pure 1 <|> "two" *> pure 2
+-- >
+-- >main = print $ "two" =~ number
+string :: Eq a => [a] -> RE a [a]
+string = traverse sym
+
+-- | Match and return a single symbol which satisfies the predicate
+psym :: (s -> Bool) -> RE s s
+psym p = msym (\s -> if p s then Just s else Nothing)
+
+-- | Like 'psym', but allows to return a computed value instead of the
+-- original symbol
+msym :: (s -> Maybe a) -> RE s a
+msym p = Symbol (error "Not numbered symbol") p
+
+-- | Match and return the given symbol
+sym :: Eq s => s -> RE s s
+sym s = psym (s ==)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/regex-applicative-0.3.3.1/Text/Regex/Applicative.hs
new/regex-applicative-0.3.4/Text/Regex/Applicative.hs
--- old/regex-applicative-0.3.3.1/Text/Regex/Applicative.hs 2015-12-27
09:32:10.000000000 +0100
+++ new/regex-applicative-0.3.4/Text/Regex/Applicative.hs 2020-07-24
11:43:05.000000000 +0200
@@ -32,9 +32,37 @@
, findFirstInfix
, findLongestInfix
, findShortestInfix
+ -- * Custom uncons function
+ -- $uncons
+ , findFirstPrefixWithUncons
+ , findLongestPrefixWithUncons
+ , findShortestPrefixWithUncons
, module Control.Applicative
)
where
import Text.Regex.Applicative.Types
import Text.Regex.Applicative.Interface
import Control.Applicative
+
+{- $uncons
+The following functions take an argument that splits the input into the first
symbol and
+the remaining input (if the input is non-empty).
+
+It is useful, for example, for feeding a @Text@ to a regex matcher:
+
+>>> findFirstPrefixWithUncons Text.uncons (many (sym 'a')) "aaa"
+Just ("aaa", "")
+
+For another example, feeding input symbols annotated with source positions
into a matcher,
+preserving the positions in the remaining input so the location of a lexical
error can be
+recovered:
+
+@
+data AList a b = AList { annotation :: a, stripAnnotation :: Maybe (b, AList a
b) }
+
+findLongestPrefixAnnotated :: RE s a -> AList b s -> Maybe (a, AList b s)
+fondLongestPrefixAnnotated = findLongestPrefixWithUncons stripAnnotation
+@
+
+The use of the other functions taking an @uncons@ argument is exactly
analogous.
+-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/regex-applicative-0.3.3.1/benchmark/benchmark.hs
new/regex-applicative-0.3.4/benchmark/benchmark.hs
--- old/regex-applicative-0.3.3.1/benchmark/benchmark.hs 2017-12-25
17:43:46.000000000 +0100
+++ new/regex-applicative-0.3.4/benchmark/benchmark.hs 2020-07-24
11:38:16.000000000 +0200
@@ -1,11 +1,58 @@
+{-# LANGUAGE FlexibleInstances, TypeApplications, RankNTypes, CPP #-}
import Data.List
import Data.Traversable
import Data.Maybe
+import Data.Void
+import Control.Monad
import Criterion.Main
import Text.Regex.Applicative
+import qualified Text.Parser.Combinators as PC
+import qualified Text.Parser.Char as PC
+import Control.DeepSeq
+import qualified Text.Parsec as Parsec
+import qualified Text.Megaparsec as Megaparsec
+import qualified Text.Megaparsec.Parsers as MP
+import qualified Data.Attoparsec.ByteString.Char8 as Attoparsec
+import qualified Data.ByteString.Char8 as BS8
-regex = sequenceA (replicate 500 $ sym 'a' <|> pure 'b') <* sequenceA
(replicate 500 $ sym 'a')
+parser1 :: PC.CharParsing f => f [String]
+parser1 = many $
+ PC.try (PC.string "foo") <|>
+ PC.try (PC.string "bar") <|>
+ PC.string "baz"
-main = defaultMain [bench "aaaaa" $ whnf (match regex) $ replicate 800 'a']
+str :: String
+str = concat $ replicate 10 "foobarfoobarbaz"
+
+benchmarkParser
+ :: NFData a
+ => (forall f . (PC.CharParsing f) => f a)
+ -> [Benchmark]
+benchmarkParser parser =
+ [ bench "regex-applicative" $ nf (match parser) str
+ , bench "parsec" $ nf (Parsec.parse parser "-") str
+ , bench "megaparsec" $ nf (Megaparsec.parseMaybe @Void (MP.unParsecT
parser)) str
+ , bench "attoparsec" $ nf (Attoparsec.parseOnly parser) (BS8.pack str)
+ ]
+
+main = defaultMain $
+ [ bgroup "parsing" (benchmarkParser parser1)
+ , bgroup "recognizing" (benchmarkParser (void parser1))
+ ]
+
+-- instances
+instance PC.Parsing (RE c) where
+ try = id
+ (<?>) = const
+ unexpected _ = empty
+ notFollowedBy = error "RE: notFollowedBy"
+ eof = error "RE: eof"
+instance PC.CharParsing (RE Char) where
+ satisfy = psym
+ char = sym
+ anyChar = anySym
+ string = string
+instance NFData Parsec.ParseError where
+ rnf = flip seq ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/regex-applicative-0.3.3.1/regex-applicative.cabal
new/regex-applicative-0.3.4/regex-applicative.cabal
--- old/regex-applicative-0.3.3.1/regex-applicative.cabal 2019-08-18
22:56:36.000000000 +0200
+++ new/regex-applicative-0.3.4/regex-applicative.cabal 2020-07-24
11:43:05.000000000 +0200
@@ -1,5 +1,5 @@
Name: regex-applicative
-Version: 0.3.3.1
+Version: 0.3.4
Synopsis: Regex-based parsing with applicative interface
Description:
regex-applicative is a Haskell library for parsing using regular
expressions.
@@ -13,6 +13,12 @@
Build-type: Simple
Extra-source-files: README.md CREDITS.md CHANGES.md
Cabal-version: >=1.10
+Tested-With:
+ GHC ==8.0.2 ||
+ ==8.2.2 ||
+ ==8.4.4 ||
+ ==8.6.5 ||
+ ==8.8.2
Source-repository head
type: git
@@ -20,7 +26,9 @@
Library
Default-language: Haskell2010
+ Default-extensions: LambdaCase
Build-depends: base < 5,
+ filtrable >= 0.1.3,
containers,
transformers
Exposed-modules: Text.Regex.Applicative
@@ -32,9 +40,8 @@
Text.Regex.Applicative.Types
Text.Regex.Applicative.Compile
GHC-Options: -Wall
+ -Werror=incomplete-patterns
-fno-warn-name-shadowing
- -fno-warn-missing-signatures
- -fno-warn-orphans
Test-Suite test-regex-applicative
type: exitcode-stdio-1.0
@@ -48,6 +55,7 @@
Default-language: Haskell2010
Build-depends: base < 5,
containers,
+ filtrable >= 0.1.3,
transformers,
smallcheck >= 1.0,
tasty,
@@ -62,4 +70,11 @@
build-depends: base <5
, criterion
, regex-applicative
+ , parsers
+ , deepseq
+ , parsec
+ , attoparsec
+ , megaparsec
+ , parsers-megaparsec
+ , bytestring
default-language: Haskell2010
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/regex-applicative-0.3.3.1/tests/test.hs
new/regex-applicative-0.3.4/tests/test.hs
--- old/regex-applicative-0.3.3.1/tests/test.hs 2017-12-25 16:55:08.000000000
+0100
+++ new/regex-applicative-0.3.4/tests/test.hs 2020-07-24 11:37:31.000000000
+0200
@@ -3,6 +3,7 @@
import Text.Regex.Applicative.Reference
import Control.Applicative
import Control.Monad
+import Data.Filtrable
import Data.Traversable
import Data.Maybe
import Text.Printf
@@ -69,6 +70,8 @@
re9 = many (sym 'a' <|> empty) <* sym 'b'
re10 = few (sym 'a' <|> empty) <* sym 'b'
+re11 = (\ a b -> a <$ guard (a == b)) <$> anySym <*?> anySym
+
prop re f s =
let fs = map f s in
reference re fs == (fs =~ re)
@@ -88,14 +91,15 @@
tests = testGroup "Tests"
[ testGroup "Engine tests"
- [ t "re1" 10 $ prop re1 a
- , t "re2" 10 $ prop re2 ab
- , t "re3" 10 $ prop re3 ab
- , t "re4" 10 $ prop re4 ab
- , t "re5" 10 $ prop re5 a
- , t "re6" 10 $ prop re6 a
- , t "re7" 7 $ prop re7 abc
- , t "re8" 7 $ prop re8 abc
+ [ t "re1" 10 $ prop re1 a
+ , t "re2" 10 $ prop re2 ab
+ , t "re3" 10 $ prop re3 ab
+ , t "re4" 10 $ prop re4 ab
+ , t "re5" 10 $ prop re5 a
+ , t "re6" 10 $ prop re6 a
+ , t "re7" 7 $ prop re7 abc
+ , t "re8" 7 $ prop re8 abc
+ , t "re11" 7 $ prop re11 abc
]
, testGroup "Recognition vs parsing"
[ t "re1" 10 $ testRecognitionAgainstParsing re1 a
@@ -108,6 +112,7 @@
, t "re8" 7 $ testRecognitionAgainstParsing re8 abc
, t "re8" 10 $ testRecognitionAgainstParsing re9 ab
, t "re8" 10 $ testRecognitionAgainstParsing re10 ab
+ , t "re11" 7 $ testRecognitionAgainstParsing re11 abc
]
, testProperty "withMatched" prop_withMatched
, testGroup "Tests for matching functions"