packages feed

pcre2 2.3.0 → 2.3.1

raw patch · 9 files changed

+131/−120 lines, 9 filesdep +tasty-benchdep −criterion

Dependencies added: tasty-bench

Dependencies removed: criterion

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog and Acknowledgements +## 2.3.1+* Fixed [#52](https://github.com/sjshuck/hs-pcre2/issues/52) where the caret+  appeared in the wrong place.+ ## 2.3.0 * Disabled building JIT by default.   * Removed various JIT-related functions and constants from
README.md view
@@ -7,11 +7,14 @@  ## Teasers ```haskell-licensePlate :: Text -> Maybe Text-licensePlate = match "[A-Z]{3}[0-9]{3,4}"+licensePlateRegex :: (Alternative f) => Text -> f Text+licensePlateRegex = match "[A-Z]{3}[0-9]{3,4}" -licensePlates :: Text -> [Text]-licensePlates = match "[A-Z]{3}[0-9]{3,4}"+firstLicensePlate :: Text -> Maybe Text+firstLicensePlate = licensePlateRegex++allLicensePlates :: Text -> [Text]+allLicensePlates = licensePlateRegex ``` ```haskell case "The quick brown fox" of@@ -31,16 +34,21 @@         \s*$          # Ignore trailing whitespace     |] -forMOf kv'd file $ execStateT $ do-    k <- gets $ capture @1-    v <- gets $ capture @2-    liftIO $ Text.putStrLn $ "found " <> k <> " set to " <> v+forOf kv'd file $ \kv -> do+    let k = capture @1 kv+        v = capture @2 kv -    case myMap ^. at k of+    Text.putStrLn $ "found " <> k <> " set to " <> v++    kv' <- case Map.lookup k replacements of         Just v' | v /= v' -> do-            liftIO $ Text.putStrLn $ "setting " <> k <> " to " <> v'-            _capture @2 .= v'-        _ -> liftIO $ Text.putStrLn $ "no change for " <> k+            Text.putStrLn $ "setting " <> k <> " to " <> v'+            return $ set (_capture @2) v' kv+        _ -> do+            Text.putStrLn $ "no change for " <> k+            return kv++    ... ```  ## Features@@ -49,7 +57,6 @@   `-> result`. * No [custom typeclasses](https://hackage.haskell.org/package/regex-base/docs/Text-Regex-Base-RegexLike.html#t:RegexContext). * A single datatype for both compile and match options, the `Option` monoid.-* UTF-8 `Text` everywhere. * Match success expressed via `Alternative`. * Opt-in Template Haskell facilities for compile-time verification of patterns,   indexing captures, and memoizing inline regexes.@@ -66,14 +73,9 @@   complete, exposed Haskell binding.  ## Performance-Currently we are slower than other libraries.  The difference is less pronounced-for `Text` where no conversions are necessary to use this library.+Currently (2026-05-02) we are much slower than other libraries. -| Operation                   | `pcre2`    | `regex-pcre-builtin` | `pcre-light` |-| :--                         |        --: |                  --: |          --: |-| Matching a `String`         | 1.22 &mu;s |           0.34 &mu;s |   0.23 &mu;s |-| Matching a `Text` (shorter) | 1.22 &mu;s |           0.93 &mu;s |   0.29 &mu;s |-| Matching a `Text` (longer)  | 1.89 &mu;s |           1.52 &mu;s |  11.12 &mu;s |+![Benchmarks graph](https://raw.githubusercontent.com/sjshuck/hs-pcre2/master/bench/bench.svg)  If it's really regex processing that's causing a bottleneck, [pcre-light](https://hackage.haskell.org/package/pcre-light)/[-heavy](https://hackage.haskell.org/package/pcre-heavy)/[lens-regex-pcre](https://hackage.haskell.org/package/lens-regex-pcre)@@ -85,6 +87,7 @@   some upstream changes as well but in theory it's possible. * Improve compile time.   * Support external `libpcre2` maybe.+* Support more types than just `Text`.  ## License [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).
bench/Bench.hs view
@@ -1,21 +1,20 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-}  module Main where -import           Criterion.Main-import           Data.List.NonEmpty          (NonEmpty(..))-import qualified Data.Text                   as Text-import           Lens.Micro.Platform-import           System.IO.Unsafe            (unsafePerformIO)-import qualified Text.Regex.PCRE-import qualified Text.Regex.PCRE.Light.Char8-import qualified Text.Regex.PCRE.String-import qualified Text.Regex.PCRE.Text-import           Text.Regex.Pcre2+import Data.List.NonEmpty          (NonEmpty(..))+import Data.Text                   qualified as Text+import Lens.Micro.Platform+import System.IO.Unsafe            (unsafePerformIO)+import Test.Tasty.Bench+import Text.Regex.PCRE             qualified+import Text.Regex.PCRE.Light.Char8 qualified+import Text.Regex.PCRE.String      qualified+import Text.Regex.PCRE.Text        qualified+import Text.Regex.Pcre2  main :: IO () main = defaultMain [@@ -52,9 +51,9 @@             in bar],      bgroup "texts" [-        bgroupTexts "short" strings,+        bgroupTexts "shorter" strings, -        bgroupTexts "long" (+        bgroupTexts "longer" (             "foo (ba*r) baz",             "foo b" ++ replicate 1000 'a' ++ "r baz")], 
pcre2.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.38.1.+-- This file has been generated from package.yaml by hpack version 0.39.1. -- -- see: https://github.com/sol/hpack  name:           pcre2-version:        2.3.0+version:        2.3.1 synopsis:       Regular expressions via the PCRE2 C library (included) description:    Please see the README on GitHub at <https://github.com/sjshuck/hs-pcre2> category:       Text@@ -203,7 +203,7 @@     , mtl     , template-haskell     , text >=2-  default-language: Haskell2010+  default-language: GHC2021   if os(darwin)     ghc-options: -optc=-Wno-ignored-qualifiers   else@@ -231,7 +231,7 @@     , tasty-hunit     , template-haskell     , text >=2-  default-language: Haskell2010+  default-language: GHC2021  benchmark pcre2-benchmarks   type: exitcode-stdio-1.0@@ -240,17 +240,17 @@       Paths_pcre2   hs-source-dirs:       bench-  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -rtsopts   build-depends:       base >=4.9 && <5     , containers-    , criterion     , microlens     , microlens-platform     , mtl     , pcre-light     , pcre2     , regex-pcre-builtin+    , tasty-bench     , template-haskell     , text >=2-  default-language: Haskell2010+  default-language: GHC2021
src/hs/Text/Regex/Pcre2.hs view
@@ -290,8 +290,8 @@     -- * User errors     SomePcre2Exception(),     Pcre2Exception(),-    Pcre2CompileException())-where+    Pcre2CompileException(),+) where  import Text.Regex.Pcre2.Internal import Text.Regex.Pcre2.TH
src/hs/Text/Regex/Pcre2/Internal.hs view
@@ -1,35 +1,32 @@-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-}  module Text.Regex.Pcre2.Internal where -import           Control.Applicative        (Alternative(..))-import           Control.Exception-import           Control.Monad-import           Control.Monad.Cont-import           Control.Monad.State.Strict-import           Data.Either                (partitionEithers)-import           Data.Foldable              (foldl', toList)-import           Data.Functor.Identity      (Identity(..))-import           Data.IORef-import           Data.List.NonEmpty         (NonEmpty(..))-import           Data.Maybe                 (fromMaybe)-import           Data.Monoid                (Alt(..), First)-import           Data.Proxy                 (Proxy(..))-import           Data.Text                  (Text)-import qualified Data.Text                  as Text-import qualified Data.Text.Foreign          as Text-import           Data.Typeable              (cast)-import           Foreign-import           Foreign.C.Types            (CInt(..), CUChar, CUInt(..))-import           Lens.Micro-import           Lens.Micro.Extras          (preview, view)-import           System.IO.Unsafe           (unsafePerformIO)-import           Text.Regex.Pcre2.Foreign+import Control.Applicative        (Alternative(..))+import Control.Exception+import Control.Monad+import Control.Monad.Cont+import Control.Monad.State.Strict+import Data.Either                (partitionEithers)+import Data.Foldable              (foldl', toList)+import Data.Functor.Identity      (Identity(..))+import Data.IORef+import Data.List.NonEmpty         (NonEmpty(..))+import Data.Maybe                 (fromMaybe)+import Data.Monoid                (Alt(..), First)+import Data.Proxy                 (Proxy(..))+import Data.Text                  (Text)+import Data.Text                  qualified as Text+import Data.Text.Foreign          qualified as Text+import Data.Typeable              (cast)+import Foreign+import Foreign.C.Types            (CInt(..), CUChar, CUInt(..))+import Lens.Micro+import Lens.Micro.Extras          (preview, view)+import System.IO.Unsafe           (unsafePerformIO)+import Text.Regex.Pcre2.Foreign  -- * General utilities @@ -1156,7 +1153,8 @@             -- FIXME Do not use Text.length since offsets are in code units             | offset' == Text.length patt = pattLines             | otherwise                   = insertCaretLine numberedPattLines-        offset' = fromIntegral offset+        -- See https://github.com/PCRE2Project/pcre2/issues/906+        offset' = max (fromIntegral offset - 1) 0         pattLines = unchompedLines $ Text.unpack patt         numberedPattLines = zip [0 :: Int ..] pattLines         (caretRow, caretCol) = (!! offset') $ do
src/hs/Text/Regex/Pcre2/TH.hs view
@@ -1,43 +1,38 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}  module Text.Regex.Pcre2.TH where -import           Control.Applicative        (Alternative(..))-import           Control.Monad              (forM)-import           Control.Monad.State.Strict (evalStateT)-import           Data.IORef-import           Data.List                  (sortBy)-import           Data.List.NonEmpty         (NonEmpty)-import           Data.Map.Lazy              (Map)-import qualified Data.Map.Lazy              as Map-import           Data.Ord                   (comparing)-import           Data.Proxy                 (Proxy(..))-import           Data.Text                  (Text)-import qualified Data.Text                  as Text-import qualified Data.Text.Foreign          as Text-import           Data.Type.Bool             (If)-import           Foreign-import           Foreign.C                  (CUChar, CUInt)-import           GHC.TypeLits               hiding (Text)-import qualified GHC.TypeLits               as TypeLits-import           Language.Haskell.TH-import           Language.Haskell.TH.Quote-import           Language.Haskell.TH.Syntax (liftData)-import           Lens.Micro-import           Lens.Micro.Extras          (view)-import           System.IO.Unsafe           (unsafePerformIO)-import           Text.Regex.Pcre2.Foreign-import           Text.Regex.Pcre2.Internal+import Control.Applicative        (Alternative(..))+import Control.Monad              (forM)+import Control.Monad.State.Strict (evalStateT)+import Data.IORef+import Data.List                  (sortBy)+import Data.List.NonEmpty         (NonEmpty)+import Data.Map.Lazy              (Map)+import Data.Map.Lazy              qualified as Map+import Data.Ord                   (comparing)+import Data.Proxy                 (Proxy(..))+import Data.Text                  (Text)+import Data.Text                  qualified as Text+import Data.Text.Foreign          qualified as Text+import Data.Type.Bool             (If)+import Foreign+import Foreign.C                  (CUChar, CUInt)+import GHC.TypeLits               hiding (Text)+import GHC.TypeLits               qualified as TypeLits+import Language.Haskell.TH+import Language.Haskell.TH.Quote  (QuasiQuoter(..))+import Language.Haskell.TH.Syntax (liftData)+import Lens.Micro+import Lens.Micro.Extras          (view)+import System.IO.Unsafe           (unsafePerformIO)+import Text.Regex.Pcre2.Foreign+import Text.Regex.Pcre2.Internal  -- | A wrapper around a list of captures that carries additional type-level -- information about the number and names of those captures.@@ -59,7 +54,8 @@  -- | Look up the number of a capture at compile time, either by number or by -- name.  Throw a helpful 'TypeError' if the index doesn't exist.-type family CaptNum (i :: k) (info :: CapturesInfo) :: Nat where+type CaptNum :: k -> CapturesInfo -> Nat+type family CaptNum i info where     CaptNum (i :: Nat) '(hi, _) = If (i <=? hi)         {- then -} i         {- else -} (TypeError
src/hs/Text/Regex/Pcre2/Unsafe.hs view
@@ -28,8 +28,8 @@     CalloutIndex(..),     CalloutResult(..),     SubCalloutInfo(..),-    SubCalloutResult(..))-where+    SubCalloutResult(..),+) where  import Text.Regex.Pcre2.Internal import Text.Regex.Pcre2.TH
test/Spec.hs view
@@ -2,26 +2,24 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-}  module Main where -import           Control.Applicative     (Alternative)-import           Control.Exception-import           Control.Monad           (forM_, void)-import           Control.Monad.RWS.Lazy  (RWS, ask, evalRWS, tell)-import           Data.IORef              (modifyIORef', newIORef, readIORef)-import           Data.List.NonEmpty      (NonEmpty(..))-import           Data.Text               (Text)-import qualified Data.Text               as Text-import           Lens.Micro.Platform-import           Test.Tasty              (defaultMain, testGroup)-import           Test.Tasty.HUnit-import           Text.Printf             (printf)-import           Text.Regex.Pcre2-import           Text.Regex.Pcre2.Unsafe+import Control.Applicative     (Alternative)+import Control.Exception+import Control.Monad           (forM_, unless, void)+import Control.Monad.RWS.Lazy  (RWS, ask, evalRWS, tell)+import Data.IORef              (modifyIORef', newIORef, readIORef)+import Data.List.NonEmpty      (NonEmpty(..))+import Data.Text               (Text)+import Data.Text               qualified as Text+import Lens.Micro.Platform+import Test.Tasty              (defaultMain, testGroup)+import Test.Tasty.HUnit+import Text.Printf             (printf)+import Text.Regex.Pcre2+import Text.Regex.Pcre2.Unsafe  main :: IO () main = defaultMain $ testGroup "tests" [@@ -139,7 +137,20 @@         testCase "are catchable using instance Alternative IO" $ do             let example = handle @SomePcre2Exception (\_ -> return "broken") $                     broken "foo"-            example >>= (@?= "broken")],+            example >>= (@?= "broken"),++        testCase ("show the caret in the right place" `issue` 52) $ do+            infoOrE <- try @Pcre2CompileException $+                predictCapturesInfo mempty "abc)def"+            msg <- case infoOrE of+                Right _ -> assertFailure "regex compiled"+                Left e  -> return $ displayException e+            case lines msg of+                [_, pattLine, caretLine] ->+                    assertBool ("caret doesn't line up:\n" ++ msg) $+                        (')', '^') `elem` zip pattLine caretLine+                _ -> assertFailure $+                    "didn't get 3-line message, got:\n" ++ msg],      testGroup "native substitution" [         testCase "works using sub" $ do