regexqq-0.2: Text/Regex/PCRE/QQ.hs
{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
{-|
Module : Text.Regex.PCRE.QQ
Copyright : (c) Matt Morrow 2008
License : BSD3
Maintainer : mjm2002@gmail.com
Stability : unstable
Portability : non-portable (GHC QuasiQuotes)
A quasiquoter for Text.Regex.PCRE regexes.
This makes use of a new GHC extension known as QuasiQuotes.
See the README for the temporary location of the docs for
Language.Haskell.TH.Quote. See the EXAMPLES file for examples.
> ghci> [$rx|([aeiou]).*(er|ing|tion)([\.,\?]*)$|] "helloing.!?!?!"
> Just ["elloing.!?!?!","e","ing",".!?!?!"]
-}
module Text.Regex.PCRE.QQ (
rx -- the regex QuasiQuoter
, regexToExpQ -- String -> ExpQ
, regexToPatQ -- String -> PatQ
-- should these be being exported here??
, module Language.Haskell.TH.Quote
, module Language.Haskell.TH.Syntax
, module Language.Haskell.TH.Lib
, module Language.Haskell.TH.Ppr
) where
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Lib
hiding (match)
import Language.Haskell.TH.Ppr
import Text.Regex.PCRE.Light
(Regex,PCREOption,PCREExecOption)
import qualified
Text.Regex.PCRE.Light as PCRE
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.ByteString.Internal (c2w,w2c)
-----------------------------------------------------------------------------
{- data QuasiQuoter
= QuasiQuoter { quoteExp :: String -> Q Exp,
quotePat :: String -> Q Pat}
-- Defined in Language.Haskell.TH.Quote -}
{- |
> ghci> maybe [] tail $ [$rx|^([+-])?([0-9]+)\.([0-9]+)|] (show $ negate pi)
> ["-","3","141592653589793"]
-}
rx :: QuasiQuoter
rx = QuasiQuoter
regexToExpQ
regexToPatQ
-- | Transform a string rep
-- of a regex to an ExpQ. The
-- resulting ExpQ, when spliced,
-- results in a function of type
-- @String -> Maybe [String]@,
-- where the input is the String
-- to match on. The result is
-- Nothing on error, and Just
-- a list of results on success.
-- Note: I'm packing\/unpacking\/...
-- the ByteString unnecessarily
-- for convenience in testing
-- out the first go at this.
-- This will be dealt with in
-- the future.
regexToExpQ :: String -> ExpQ
regexToExpQ s = case PCRE.compileM (pack s) pcreOpts of
Left err -> error err
-- Give an error at compile time
-- if the regex string is invalid
Right _ -> [|
(return . fmap unpack =<<)
. match (regex s) . pack
|]
-- | Transform a string (presumably)
-- containing a regex to a PatQ.
-- NOTE: Given a regex, a pattern
-- is constructed which matches
-- a literal string containing
-- the verbatim regex. It does
-- this because I couldn't think
-- of anything better for it to
-- do off the cuff. This needs
-- thought.
regexToPatQ :: String -> PatQ
regexToPatQ =
litP . stringL
. dropWhile (/='"')
. show . regex
-- | Regex compilation. Temporarily uses
-- hardcoded options @extended@ and
-- @multiline@.
regex :: String -> Regex
regex = flip PCRE.compile pcreOpts . pack
-- | Regex matching.
match :: Regex -> B.ByteString -> Maybe [B.ByteString]
match rx = flip (PCRE.match rx) pcreExecOpts
-- | Adjust these to your tastes. An
-- interface to options seems to be
-- the next logical (and practical)
-- step.
pcreOpts :: [PCREOption]
pcreOpts =
[ PCRE.extended
, PCRE.multiline ]
-- , dotall, caseless, utf8
-- , newline_any, PCRE.newline_crlf ]
-- | Adjust these to your tastes. An
-- interface to options seems to be
-- the next logical (and practical)
-- step.
pcreExecOpts :: [PCREExecOption]
pcreExecOpts = []
-- [ PCRE.exec_newline_crlf
-- , exec_newline_any, PCRE.exec_notempty
-- , PCRE.exec_notbol, PCRE.exec_noteol ]
pack :: String -> ByteString
pack = B.pack . fmap c2w
unpack :: ByteString -> String
unpack = fmap w2c . B.unpack
-----------------------------------------------------------------------------