packages feed

pcre2 1.1.0 → 1.1.1

raw patch · 7 files changed

+67/−47 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog and Acknowledgements +## 1.1.1+* Fixed [#12](https://github.com/sjshuck/pcre2/4), where some functions returned+  too many match results.+ ## 1.1.0 * Added global matching.     * New functions `matchAll`, `matchAllOpt`, `capturesAll`, `capturesAllOpt`.
README.md view
@@ -48,7 +48,7 @@   Both are first-class. * Vast presentation of PCRE2 functionality.  We can even register Haskell   callbacks to run during matching!-* No dependencies that aren't distributed with GHC.+* Few dependencies. * Bundled, statically-linked UTF-16 build of ~~up-to-date~~ PCRE2 (version   10.35), with a complete, exposed Haskell binding. 
pcre2.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 0a7a573e61659cfbca9092c36ae2549d63b0c6745b4bc3953f29dfc97aebd1b6+-- hash: d8aba62e213c9b15ec9218a159e7922eb4ebb298385cd3ff0e1acd1f15fd6506  name:           pcre2-version:        1.1.0+version:        1.1.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
src/hs/Text/Regex/Pcre2/Foreign.hs view
@@ -5,7 +5,7 @@ -- -- Items here are named identically to their C counterparts.  Therefore, -- documentation will be sparse;--- [the official PCRE2 API docs](https://pcre.org/current/doc/html/pcre2api.html#SEC36)+-- [the official PCRE2 API docs](https://pcre.org/current/doc/html/pcre2api.html) -- should suffice. module Text.Regex.Pcre2.Foreign where 
src/hs/Text/Regex/Pcre2/Internal.hs view
@@ -150,10 +150,11 @@ -- * Assembling inputs into @Matcher@s and @Subber@s  -- | A matching function where all inputs and auxilliary data structures have--- been \"compiled\".  It takes a subject and produces a list of match data--- objects, representing a global match, to be passed to further validation and--- inspection.-type Matcher = Text -> IO [MatchData]+-- been \"compiled\".  It takes a subject and a whitelist of capture indexes+-- to extract, and produces lists of capture offsets representing a global+-- match.  The whitelist is @[]@ rather than @NonEmpty@ to facilitate writing+-- literals.+type Matcher = Text -> [Int] -> IO [NonEmpty SliceRange]  -- | A substitution function.  It takes a subject and produces the number of -- substitutions performed (0 or 1, or more in the presence of `SubGlobal`)@@ -658,12 +659,12 @@     return $ MatchEnv {..}  -- | Helper for @assemble*@ functions.  Basically, extract all options and help--- produce a function that takes a `Text` subject and does something.+-- produce a function that takes a `Text` subject. assembleSubjFun-    :: (MatchEnv -> Text -> IO a)+    :: (MatchEnv -> Text -> a)     -> Option     -> Text-    -> IO (Text -> IO a)+    -> IO (Text -> a) assembleSubjFun mkSubjFun option patt =     runStateT extractAll (applyOption option) <&> \case         (subjFun, []) -> subjFun@@ -684,27 +685,29 @@     -> IO Matcher assembleMatcher = assembleSubjFun $ \matchEnv@(MatchEnv {..}) ->     let matchTempEnvWithSubj = mkMatchTempEnv matchEnv-    in \subject ->+    in \subject whitelist ->         withForeignPtr matchEnvCode $ \codePtr ->         Text.useAsPtr subject $ \subjPtr subjCUs -> do             MatchTempEnv {..} <- matchTempEnvWithSubj subject -            -- Loop over the subject, emitting MatchData's until stopping.-            execWriterT $ runMaybeT $ fix1 0 $ \continue curOff -> do-                -- TODO Can one of these be reused for a whole global match?-                matchData <- liftIO $ mkForeignPtr pcre2_match_data_free $-                    pcre2_match_data_create_from_pattern codePtr nullPtr+            -- These need to happen one after the other.  We need the+            -- ForeignPtr to touch later, to allow cleanup after lazy matching.+            matchDataPtr <- pcre2_match_data_create_from_pattern codePtr nullPtr+            matchData <-+                Conc.newForeignPtr <*> pcre2_match_data_free $ matchDataPtr +            -- Loop over the subject, emitting slice lists until stopping.+            lists <- execWriterT $ runMaybeT $ fix1 0 $ \continue curOff -> do                 result <- liftIO $                     withForeignOrNullPtr matchTempEnvCtx $ \ctxPtr ->-                    withForeignPtr matchData $ \matchDataPtr -> pcre2_match-                        codePtr-                        (castCUs subjPtr)-                        (fromIntegral subjCUs)-                        curOff-                        matchEnvOpts-                        matchDataPtr-                        ctxPtr+                        pcre2_match+                            codePtr+                            (castCUs subjPtr)+                            (fromIntegral subjCUs)+                            curOff+                            matchEnvOpts+                            matchDataPtr+                            ctxPtr                  -- Handle no match and errors                 when (result == pcre2_ERROR_NOMATCH) stop@@ -712,22 +715,30 @@                     liftIO $ maybeRethrow matchTempEnvRef                 liftIO $ check (> 0) result -                emit matchData+                slices <- liftIO $ unsafeInterleaveIO $+                    getOvecEntriesAt whitelist matchDataPtr +                emit slices+                 lazy $ do                     -- Determine next starting offset-                    nextOff <- liftIO $-                        withForeignPtr matchData $ \matchDataPtr -> do-                            ovecPtr <- pcre2_get_ovector_pointer matchDataPtr-                            curOffEnd <- peekElemOff ovecPtr 1-                            -- Prevent infinite loop upon empty match-                            return $ max curOffEnd (curOff + 1)+                    nextOff <- liftIO $ do+                        ovecPtr <- pcre2_get_ovector_pointer matchDataPtr+                        curOffEnd <- peekElemOff ovecPtr 1+                        -- Prevent infinite loop upon empty match+                        return $ max curOffEnd (curOff + 1)                      -- Handle end of subject                     when (nextOff > fromIntegral subjCUs) stop -                    continue nextOff+                    -- Force slices out of the current match_data state before+                    -- clobbering it with the next match+                    slices `seq` continue nextOff +            touchForeignPtr matchData++            return lists+     where     stop = MaybeT $ return Nothing     emit x = tell [x]@@ -1028,17 +1039,15 @@ -- Internal only!  Users should not (have to) know about `Matcher`. _capturesInternal :: Matcher -> [Int] -> Traversal' Text (NonEmpty Text) _capturesInternal matcher whitelist f subject = traverse f css <&> \css' ->-    -- Swag foldl-as-foldr to create only as many segments as we need to-    -- stitch back together and no more.+    -- Swag foldl-as-foldr to create only as many segments as we need to stitch+    -- back together and no more.     let triples = zip3 (flatten ovecEntries) (flatten css) (flatten css')     in Text.concat $ foldr mkSegments termSegments triples 0      where      flatten = concatMap NE.toList-    ovecEntries = do-        matchData <- unsafePerformIO $ matcher subject-        return $ unsafePerformIO $ getOvecEntriesAt whitelist matchData+    ovecEntries = unsafePerformIO $ matcher subject whitelist     css = do         ovecEntry <- ovecEntries         return $ unsafePerformIO $ mapM (evaluate . slice subject) ovecEntry@@ -1061,12 +1070,12 @@  -- | Strictly read specifically indexed captures' offsets from match results. -- Truncate indexes when they go out of bounds, to support infinite lists.-getOvecEntriesAt :: [Int] -> MatchData -> IO (NonEmpty SliceRange)-getOvecEntriesAt ns matchData = withForeignPtr matchData $ \matchDataPtr -> do+getOvecEntriesAt :: [Int] -> Ptr Pcre2_match_data -> IO (NonEmpty SliceRange)+getOvecEntriesAt whitelist matchDataPtr = do     count <- fromIntegral <$> pcre2_get_ovector_count matchDataPtr -    case NE.nonEmpty $ takeWhile (< count) ns of-        Nothing -> error "BUG! Tried to get empty list of captures"+    case NE.nonEmpty $ takeWhile (< count) whitelist of+        Nothing -> error "BUG! Empty whitelist"         Just ns -> do             ovecPtr <- pcre2_get_ovector_pointer matchDataPtr @@ -1089,7 +1098,8 @@  -- | @capturesOpt mempty = captures@ capturesOpt :: Option -> Text -> Text -> [Text]-capturesOpt option patt = view $ _capturesOpt option patt . to NE.toList+capturesOpt option patt =+    maybe [] NE.toList . preview (_capturesOpt option patt)  -- | Match a pattern to a subject once and return a non-empty list of captures -- in an `Alternative`, or `empty` if no match.  The non-empty list constructor@@ -1108,9 +1118,8 @@ capturesAOpt :: (Alternative f) => Option -> Text -> Text -> f (NonEmpty Text) capturesAOpt option patt = toAlternativeOf $ _capturesOpt option patt --- | Match a pattern to a subject and lazily return zero or more non-empty lists--- of captures corresponding to every non-overlapping place in the subject the--- pattern matched.+-- | Match a pattern to a subject and lazily a list of all non-overlapping+-- portions, with all capture groups, that matched. -- -- @since 1.1.0 capturesAll :: Text -> Text -> [NonEmpty Text]
src/hs/Text/Regex/Pcre2/TH.hs view
@@ -126,7 +126,7 @@                 (nums, names) = unzip numberedNames                 e = [e|                     let _cs = _capturesInternal $(matcherQ s) $(liftData nums)-                    in view $ _cs . to NE.toList |]+                    in maybe [] NE.toList . preview _cs |]                 p = listP $ map (varP . mkName . Text.unpack) names,      quoteType = const $ fail "regex: cannot produce a type",
test/Spec.hs view
@@ -215,6 +215,13 @@         f "a" `shouldReturn` ""         f "b" `shouldReturn` "b" +    issue 12 $ do+        captures ".a." "foo bar baz" `shouldBe` ["bar"]+        case "foo bar baz" of+            [regex|.a(?<x>.)|] -> return ()+            _                  ->+                expectationFailure "quasi-quoted pattern didn't match"+     where     issue :: Int -> Expectation -> Spec     issue n = it $ "https://github.com/sjshuck/issues/" ++ show n