sjshuck / hs-pcre2

Complete Haskell binding to PCRE2
Apache License 2.0
12 stars 2 forks source link

Can regex compilation errors be caught before applying the regex? #15

Closed neongreen closed 2 years ago

neongreen commented 3 years ago

I am trying to do something like:

compileMatches :: Text -> Either String (Text -> Bool)

where any regex compilation errors should be caught before the regex is actually applied.

Is it possible?

sjshuck commented 3 years ago

Not currently. The recommendation is to use [regex|...|], in which case any compilation errors are caught during Haskell compilation, rather than a monad at runtime.

I'm open to suggestions for why the latter would be good to include.

neongreen commented 3 years ago

I suppose something getting access to Text -> Bool by itself doesn't buy you much. My usecase is "I'm trying to mimic another library's interface using pcre2 as the backend", but it's not a common usecase.

It does occur to me, though, that without an opaque data Regex type it seems to be impossible to write a reusable regex that a) would be checked at compile-time and b) would be usable both for matches and for pcre-native sub. Which is a slightly different issue.

sjshuck commented 3 years ago

Re: "seems to be impossible", I agree. The closest we can get currently is [_regex|...|], which is a) checked at compile-time and b) usable for both matching and subbing.

But yeah, the subbing is over a Traversal' rather than native, so it's slower and lacks the concise "$1" syntax. On the other hand, capture group references are validated at compile time.

sjshuck commented 3 years ago

FWIW,

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}

import Control.Exception (displayException, evaluate, try)
import Data.Text         (Text)
import Lens.Micro
import System.IO.Unsafe  (unsafePerformIO)
import Text.Regex.Pcre2  (Pcre2CompileException, matches)

compileMatches :: Text -> Either String (Text -> Bool)
compileMatches patt = unsafePerformIO $ do
    let r = matches patt

    try (evaluate $ r "")
        <&> _Left %~ displayException @Pcre2CompileException
        <&> _Right .~ r

main :: IO ()
main = do
    let test patt = putStrLn $ show patt ++ ": " ++ case compileMatches patt of
            Left e  -> e
            Right r -> "matches \"foo\": " ++ show (r "foo")

    test "foo"
    test "bar"
    test ")"
sjshuck commented 2 years ago

Closing due to inactivity.