rex (empty) → 0.1
raw patch · 8 files changed
+572/−0 lines, 8 filesdep +MissingHdep +basedep +bytestringsetup-changed
Dependencies added: MissingH, base, bytestring, containers, ghc, haskell-src-meta, pcre-light, split, template-haskell
Files
- Bench.hs +21/−0
- LICENSE +27/−0
- README +16/−0
- Setup.hs +3/−0
- Test.hs +46/−0
- Text/Regex/PCRE/Precompile.hs +56/−0
- Text/Regex/PCRE/Rex.hs +368/−0
- rex.cabal +35/−0
+ Bench.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE TemplateHaskell, QuasiQuotes, ViewPatterns #-}++module Main where++import Text.Regex.PCRE.Rex+import Test++import Criterion.Main++addEm :: Int -> [Double]+addEm n = map math $+ zipWith (++)+ (zipWith (++) (map show [1..n])+ (concat $ repeat ["+", "/", "-", "*"]))+ (map show [100..])++main = defaultMain [+ bgroup "math" [ bench "10" $ nf addEm 10+ , bench "1000" $ nf addEm 1000+ ]+ ]
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) Michael Sloan 2011++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of other contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ README view
@@ -0,0 +1,16 @@+http://hackage.haskell.org/package/rex++Provides a quasi-quoter for regular expressions which+yields a tuple, of appropriate arity and types,+representing the results of the captures. Allows the user +to specify parsers for captures as inline Haskell. Can +also be used to provide typeful pattern matching in+function definitions and case patterns.++To build / install:++./Setup.hs configure --user+./Setup.hs build+./Setup.hs install++See the haddock or Text/Regex/PCRE/QQT.hs for documentation.
+ Setup.hs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+main = defaultMain
+ Test.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE TemplateHaskell, QuasiQuotes, ViewPatterns #-}++module Test where++import Text.Regex.PCRE.Rex+import Data.Maybe (catMaybes)++-- main = interact (unlines . map (show . math) . lines)++math x = mathl x 0++mathl [] x = x+mathl [rex|^ \s*(?{ y }\d+)\s*(?{ id -> s }.*)$|] x = mathl s y+mathl [rex|^\+\s*(?{ y }\d+)\s*(?{ id -> s }.*)$|] x = mathl s $ x + y+mathl [rex|^ -\s*(?{ y }\d+)\s*(?{ id -> s }.*)$|] x = mathl s $ x - y+mathl [rex|^\*\s*(?{ y }\d+)\s*(?{ id -> s }.*)$|] x = mathl s $ x * y+mathl [rex|^ /\s*(?{ y }\d+)\s*(?{ id -> s }.*)$|] x = mathl s $ x / y+mathl str x = error str++peano :: String -> Maybe Int+peano = [rex|^(?{ length . filter (=='S') } \s* (?:S\s+)*Z)\s*$|]++vect2d :: String -> Maybe (Int, Int)+vect2d = [rex|^<\s* (?{}\d+) \s*,\s* (?{}\d+) \s*>$|]++-- From http://www.regular-expressions.info/dates.html+parseDate :: String -> Maybe (Int, Int, Int)+parseDate [rex|^(?{ y }(?:19|20)\d\d)[- /.]+ (?{ m }0[1-9]|1[012])[- /.]+ (?{ d }0[1-9]|[12][0-9]|3[01])$|]+ | (d > 30 && (m `elem` [4, 6, 9, 11]))+ || (m == 2 &&+ (d ==29 && not (mod y 4 == 0 && (mod y 100 /= 0 || mod y 400 == 0)))+ || (d > 29)) = Nothing+ | otherwise = Just (y, m, d)+parseDate _ = Nothing++onNull a f [] = a+onNull _ f xs = f xs++nonNull = onNull Nothing++disjunct [rex| ^(?:(?{nonNull $ Just . head -> a} .)+ | (?{nonNull $ Just . head -> b} ..)+ | (?{nonNull $ Just . last -> c} ...))$|] =+ head $ catMaybes [a, b, c]
+ Text/Regex/PCRE/Precompile.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE TupleSections #-}++-----------------------------------------------------------------------------+-- |+-- Module : Text.Regex.PCRE.Rex+-- Copyright : (c) Michael Sloan 2011+--+-- Maintainer : Michael Sloan (mgsloan@gmail.com)+-- Stability : unstable+-- Portability : unportable+-- +-- This module provides support for accessing the compiled representation of+-- PCRE regular expressions. This byte array encodes a lookup-table based+-- representation for the regular expression, and can be safely written+-- out and read back by compatible PCRE versions.+--+-----------------------------------------------------------------------------++module Text.Regex.PCRE.Precompile where++import Control.Monad (liftM)++import qualified Data.ByteString.Char8 as B+import Data.ByteString.Unsafe (unsafePackCStringLen, unsafeUseAsCString)++import Foreign.ForeignPtr (withForeignPtr, newForeignPtr_)+import Foreign.Ptr (nullPtr, castPtr)+import Foreign.Marshal (alloca)+import Foreign.Storable (peek)+import Foreign.C.Types (CInt)++import Text.Regex.PCRE.Light+import Text.Regex.PCRE.Light.Base++-- | Compiles the given regular expression, and assuming nothing bad+-- happens, yields the bytestring filled with PCRE's compiled+-- representation.+precompile :: B.ByteString -> [PCREOption] -> IO (Maybe B.ByteString)+precompile pat opts = regexToTable $ compile pat opts++-- | Takes a compiled regular expression adn yields its bytestring+-- representation.+regexToTable :: Regex -> IO (Maybe B.ByteString)+regexToTable (Regex p _) =+ withForeignPtr p $ \pcre -> alloca $ \res -> do+ success <- c_pcre_fullinfo pcre nullPtr info_size res+ len <- return . fromIntegral =<< (peek res :: IO CInt)+ if success >= 0 + then withForeignPtr p (liftM Just . unsafePackCStringLen . (, len) . castPtr)+ else return Nothing++-- | Creates a regular expression+regexFromTable :: B.ByteString -> IO Regex+regexFromTable bytes = unsafeUseAsCString bytes $ \cstr -> do+ ptr <- newForeignPtr_ (castPtr cstr)+ return $ Regex ptr bytes
+ Text/Regex/PCRE/Rex.hs view
@@ -0,0 +1,368 @@+{-# LANGUAGE TemplateHaskell, QuasiQuotes, TupleSections, ViewPatterns #-}++-----------------------------------------------------------------------------+-- |+-- Module : Text.Regex.PCRE.Rex+-- Copyright : (c) Michael Sloan 2011+--+-- Maintainer : Michael Sloan (mgsloan@gmail.com)+-- Stability : unstable+-- Portability : unportable+-- +-- This module provides a template Haskell quasiquoter for regular+-- expressions, which provides the following features:+-- +-- 1) Compile-time checking that the regular expression is valid.+-- +-- 2) Arity of resulting tuple based on the number of selected capture patterns+-- in the regular expression.+--+-- 3) By default utilizes type inference to determine how to parse capture+-- patterns - uses the 'read' function's return-type polymorphism+--+-- 4) Allows for the inline interpolation of a mapping function String -> a.+--+-- 5) Precompiles the regular expression at compile time, by calling into the+-- PCRE library and storing a ByteString literal representation of its state.+--+-- Here's a silly example which parses peano numbers of the form Z, S Z,+-- S S Z, etc. The \s+ means that it is not sensitive to the quantity or type+-- of seperating whitespace. (these examples can also be found in Test.hs)+--+-- > peano :: String -> Maybe Int+-- > peano = [rex|^(?{ length . filter (=='S') } \s* (?:S\s+)*Z)\s*$|]+--+-- > *Main> peano "Z"+-- > Just 0+-- > *Main> peano "S Z"+-- > Just 1+-- > *Main> peano "S S Z"+-- > Just 2+-- > *Main> peano "S S S Z"+-- > Just 3+-- > *Main> peano "invalid"+-- > Nothing+--+-- The token \"(?{\" introduces a capture group which has a mapping applied to the+-- result - in this case \"length . filter (=='S')\". If an expression is omitted, +-- e.g. \"(?{} ... )\", then there is an implicit usage of the read function.+-- +-- If the ?{ ... } are omitted, then the capture group is not taken as part of+-- the results of the match.+-- +-- > vect2d :: String -> Maybe (Int, Int)+-- > vect2d = [rex|^<\s* (?{}\d+) \s*,\s* (?{}\d+) \s*>$|]+--+-- The following example is derived from http://www.regular-expressions.info/dates.html+--+-- > parseDate :: String -> Maybe (Int, Int, Int)+-- > parseDate [rex|^(?{ y }(?:19|20)\d\d)[- /.]+-- > (?{ m }0[1-9]|1[012])[- /.]+-- > (?{ d }0[1-9]|[12][0-9]|3[01])$|]+-- > | (d > 30 && (m `elem` [4, 6, 9, 11]))+-- > || (m == 2 &&+-- > (d == 29 && not (mod y 4 == 0 && (mod y 100 /= 0 || mod y 400 == 0)))+-- > || (d > 29)) = Nothing+-- > | otherwise = Just (y, m, d)+-- > parseDate _ = Nothing+--+-- The above example makes use of the regex quasi-quoter as a pattern matcher.+-- The interpolated Haskell patterns are used to construct an implicit view+-- pattern. The above pattern is expanded to the equivalent:+--+-- > parseDate ([rex|^(?{}(?:19|20)\d\d)[- /.]+-- > (?{}0[1-9]|1[012])[- /.]+-- > (?{}0[1-9]|[12][0-9]|3[01])$|]+-- > -> Just (y, m, d))+--+-- In order to provide a capture-mapper along with a pattern, use view-patterns+-- inside the interpolation brackets.+--+-- Caveat: Since haskell-src-exts does not support parsing view-patterns, the+-- above is implemented as a relatively naive split on \"->\". It presumes that+-- the last \"->\" in the interpolated pattern seperates the pattern from an+-- expression on the left. This allows for lambdas to be present in the+-- expression, but prevents nesting view patterns.+--+-- There are a few other inelegances:+--+-- 1) PCRE captures, unlike .NET regular expressions, yield the last capture+-- made by a particular pattern. So, for example, (...)*, will only yield one+-- match for '...'. Ideally these would be detected and yield an implicit [a].+--+-- 2) Patterns with disjunction between captures ((?{f}a) | (?{g}b)) will+-- provide the empty string to one of f / g. In the case of pattern+-- expressions, it would be convenient to be able to map multiple captures into+-- a single variable / pattern, preferring the first non-empty option. The+-- general logic for this is a bit complicated, and postponed for a later+-- release.+--+-- Since pcre-light is a wrapper over a C API, the most efficient interface is+-- ByteStrings, as it does not natively speak Haskell lists. The [rex| ... ]+-- quasiquoter implicitely packs the input into a bystestring, and unpacks the+-- results to strings before providing them to your mappers. Use [brex| ... ]+-- to bypass this, and process raw ByteStrings. In order to preserve the+-- same default behavior, \"read . unpack\" is the default mapper for brex.+--+-- Inspired by / copy-modified from Matt Morrow's regexqq package:+-- <http://hackage.haskell.org/packages/archive/regexqq/latest/doc/html/src/Text-Regex-PCRE-QQ.html>+--+-- And code from Erik Charlebois's interpolatedstring-qq package:+-- <http://hackage.haskell.org/packages/archive/interpolatedstring-qq/latest/doc/html/Text-InterpolatedString-QQ.html>+--+-----------------------------------------------------------------------------++module Text.Regex.PCRE.Rex (rex, brex, maybeRead, padRight) where++import qualified Text.Regex.PCRE.Light as PCRE+import Text.Regex.PCRE.Precompile++import Control.Arrow (first, second)+import Control.Monad (liftM)++import qualified Data.ByteString.Char8 as B+import Data.Either.Utils (forceEitherMsg)+import Data.List (groupBy, sortBy)+import Data.List.Split (split, onSublist)+import Data.Maybe (catMaybes, listToMaybe, fromJust, isJust)+import Data.Maybe.Utils (forceMaybeMsg)+import Data.Ord (comparing)+import Data.Char (isSpace)++import Language.Haskell.TH+import Language.Haskell.TH.Quote+import Language.Haskell.Meta.Parse++import System.IO.Unsafe (unsafePerformIO)++type ParseChunk = Either String (Int, String)+type ParseChunks = (Int, String, [(Int, String)])++{- TODO: idea - provide a variant which allows splicing in an expression+ that evaluates to regex string. The tricky thing here is that this+ splice might contain capture groups - thus, the parser here would need to+ be referenced in order to dispatch +-}++{- TODO: target Text.Regex.Base -}++-- | The regular expression quasiquoter for strings.+rex, brex :: QuasiQuoter+rex = QuasiQuoter+ (makeExp False . parseIt)+ (makePat False . parseIt)+ undefined undefined++-- | The regular expression quasiquoter for Data.ByteString.Char8.+brex = QuasiQuoter+ (makeExp True . parseIt)+ (makePat True . parseIt)+ undefined undefined++-- Template Haskell Code Generation+-------------------------------------------------------------------------------++-- Creates the template haskell Exp which corresponds to the parsed interpolated+-- regex. This particular code mainly just handles making "read" the+-- default for captures which lack a parser definition, and defaulting to making+-- the parser that doesn't exist+makeExp :: Bool -> ParseChunks -> ExpQ+makeExp bs (cnt, pat, exs) = buildExp bs cnt pat+ . map (liftM (processExp bs) . snd . head)+ . groupSortBy (comparing fst)+ $ map (second Just) exs ++ [(i, Nothing) | i <- [0..cnt]]+ +-- Creates the template haskell Pat which corresponds to the parsed interpolated+-- regex. As well as handling the aforementioned defaulting considerations, this+-- turns per-capture view patterns into a single tuple-resulting view pattern.+-- +-- E.g. [reg| ... (?{e1 -> v1} ...) ... (?{e2 -> v2} ...) ... |] becomes+-- [reg| ... (?{e1} ...) ... (?{e2} ...) ... |] -> (v1, v2)+makePat :: Bool -> ParseChunks -> PatQ+makePat bs (cnt, pat, exs) = do+ viewExp <- buildExp bs cnt pat $ map (liftM fst) views+ return . ViewP viewExp+ . (\xs -> ConP (mkName "Just") [TupP xs])+ . map snd $ catMaybes views+ where+ views :: [Maybe (Exp, Pat)]+ views = map (floatSnd . processView . snd . head)+ . groupSortBy (comparing fst)+ $ exs ++ [(i, "") | i <- [0..cnt]]++ processView :: String -> (Exp, Maybe Pat)+ processView xs = case splitFromBack 2 ((split . onSublist) "->" xs) of+ (_, [r]) -> onSpace (error $ "blank pattern in: " ++ r)+ ((processExp bs "",) . processPat) r+ -- View pattern+ (l, [_, r]) -> (processExp bs $ concat l, processPat r)+ -- Included so that Haskell doesn't warn about non-exhaustive patterns+ -- (even though the above are exhaustive in this context)+ _ -> undefined++-- Here's where the main meat of the template haskell is generated. Given the+-- number of captures, the pattern string, and a list of capture expressions,+-- yields the template Haskell Exp which parses a string into a tuple.+buildExp :: Bool -> Int -> String -> [Maybe Exp] -> ExpQ+buildExp bs cnt pat xs = if bs+ then [| let r = unsafePerformIO (regexFromTable $! $(table_bytes)) in + liftM ( $(return maps) . padRight B.empty pad )+ . (flip $ PCRE.match r) pcreExecOpts |]+ else [| let r = unsafePerformIO (regexFromTable $! $(table_bytes)) in+ liftM ( $(return maps) . padRight "" pad . map B.unpack )+ . flip (PCRE.match r) pcreExecOpts . B.pack |]+ where pad = cnt + 2+ --TODO: make sure this takes advantage of bytestring fusion stuff - is+ -- the right pack / unpack. Or use XOverloadedStrings+ table_bytes = [| B.pack $(runIO table_string) |]+ table_string = precompile (B.pack pat) pcreOpts >>= + return . LitE . StringL . B.unpack . + forceMaybeMsg "Error while getting PCRE compiled representation\n"+ vs = [mkName $ "v" ++ show i | i <- [0..cnt]]+ maps = LamE [ListP . (WildP:) $ map VarP vs]+ (TupE . map (uncurry AppE)+ -- filter out all "Nothing" exprs+ . map (first fromJust) . filter (isJust . fst)+ -- [(Expr, Variable applied to)]+ . zip xs $ map VarE vs)++-- Default parsers, one for the bytestring case and one for the string.+defaultExp :: Bool -> String+defaultExp True = "read . unpack"+defaultExp False = "read"++-- Parse a Haskell expression into a template Haskell Exp, yielding the+-- default for strings which just consist of whitespace.+processExp :: Bool -> String -> Exp+processExp bs xs = forceEitherMsg ("Error while parsing capture mapper " ++ xs)+ . parseExp . onSpace (defaultExp bs) id $ xs++-- Parse a Haskell pattern match into a template Haskell Pat, yielding Nothing for+-- strings which just consist of whitespace.+processPat :: String -> Maybe Pat+processPat xs = onSpace Nothing+ (Just . forceEitherMsg ("Error while parsing capture pattern " ++ xs) . parsePat) xs++-- Parsing+-------------------------------------------------------------------------------++-- Postprocesses the results of the chunk-wise parse output, into the pattern to+-- be pased to the regex engine, and the interpolated +parseIt :: String -> ParseChunks+parseIt xs = ( cnt, concat [x | Left x <- results]+ , [(i, x) | Right (i, x) <- results])+ where (cnt, results) = parseRegex (filter (`notElem` "\r\n") xs) "" (-1)++-- A pair of mutually-recursive functions, one for processing the quotation+-- and the other for the anti-quotation.++-- TODO: add check for erroneous { }++parseRegex :: String -> String -> Int -> (Int, [ParseChunk])+parseRegex inp s ix = case inp of+ -- Disallow branch-reset capture.+ ('(':'?':'|':_) ->+ error "Branch reset pattern (?| not allowed in fancy quasi-quoted regex."++ -- Ignore non-capturing parens / handle backslash escaping.+ ('\\':'\\' :xs) -> parseRegex xs ("\\\\" ++ s) ix+ ('\\':'(' :xs) -> parseRegex xs (")\\" ++ s) ix+ ('\\':')' :xs) -> parseRegex xs ("(\\" ++ s) ix+ ('(':'?':':':xs) -> parseRegex xs (":?(" ++ s) ix++ -- Anti-quote for processing a capture group.+ ('(':'?':'{':xs) -> mapSnd ((Left $ reverse ('(':s)) :)+ $ parseHaskell xs "" (ix + 1)++ -- Keep track of how many capture groups we've seen.+ ('(':xs) -> parseRegex xs ('(':s) (ix + 1)++ -- Consume the regular expression contents.+ (x:xs) -> parseRegex xs (x:s) ix+ [] -> (ix, [Left $ reverse s])++parseHaskell :: String -> String -> Int -> (Int, [ParseChunk])+parseHaskell inp s ix = case inp of+ -- Escape } in the Haskell splice using a backslash.+ ('\\':'}':xs) -> parseHaskell xs ('}':s) ix++ -- Capture accumulated antiquote, and continue parsing regex literal.+ ('}':xs) -> mapSnd ((Right (ix, reverse s)):)+ $ parseRegex xs "" ix++ -- Consume the antiquoute contents, appending to a reverse accumulator.+ (x:xs) -> parseHaskell xs (x:s) ix+ [] -> error "Regular-expression Haskell splice is never terminated with a trailing }"++-- TODO: provide bytestring variant.++-- Utils+-------------------------------------------------------------------------------++-- | A possibly useful utility function - yields "Just x" when there is a valid+-- parse, and Nothing otherwise.+maybeRead :: (Read a) => String -> Maybe a+maybeRead = fmap fst . listToMaybe . reads++-- TODO: allow for a bundle of parameters to be passed in at the beginning+-- of the quasiquote. Would also be a juncture for informing arity /+-- extension information.++pcreOpts :: [PCRE.PCREOption]+pcreOpts =+ [ PCRE.extended+ , PCRE.multiline ]+ -- , dotall, caseless, utf8+ -- , newline_any, PCRE.newline_crlf ]++pcreExecOpts :: [PCRE.PCREExecOption]+pcreExecOpts = []+ -- [ PCRE.exec_newline_crlf+ -- , exec_newline_any, PCRE.exec_notempty+ -- , PCRE.exec_notbol, PCRE.exec_noteol ]++groupSortBy :: (a -> a -> Ordering) -> [a] -> [[a]]+groupSortBy f = groupBy (\x -> (==EQ) . f x) . sortBy f++splitFromBack :: Int -> [a] -> ([a], [a])+splitFromBack i xs = (reverse b, reverse a)+ where (a, b) = splitAt i $ reverse xs++onSpace :: a -> (String -> a) -> String -> a+onSpace x f s | all isSpace s = x+ | otherwise = f s++-- | Given a desired list-length, if the passed list is too short, it is padded+-- with the given element. Otherwise, it trims.+padRight :: a -> Int -> [a] -> [a]+padRight _ 0 xs = xs+padRight v i [] = replicate i v+padRight v i (x:xs) = x : padRight v (i-1) xs++mapLeft :: (a -> a') -> Either a b -> Either a' b+mapLeft f = either (Left . f) Right++mapSnd :: (b -> c) -> (a, b) -> (a, c)+mapSnd f (x, y) = (x, f y)++floatSnd :: (Functor f) => (a, f b) -> f (a, b)+floatSnd (x, y) = fmap (x,) y++{- for completeness:++mapRight :: (b -> b') -> Either a b -> Either a b'+mapRight f = either Left (Right . f)++mapFst :: (a -> c) -> (a, b) -> (c, b)+mapFst f (x, y) = (f x, y)++floatFst :: (Functor f) => (f a, b) -> f (a, b)+floatFst (x, y) = fmap (,y) x++floatBoth :: (Monad m) => (m a, m b) -> m (a, b)+floatBoth (x, y) = do+ x' <- x+ y' <- y+ return (x', y')++-}
+ rex.cabal view
@@ -0,0 +1,35 @@+Name: rex+Version: 0.1+Synopsis: A quasi-quoter for typeful results of regex captures.+Description: Provides a quasi-quoter for regular expressions which+ yields a tuple, of appropriate arity and types,+ representing the results of the captures. Allows the user + to specify parsers for captures as inline Haskell. Can + also be used to provide typeful pattern matching in+ function definitions and pattern matches. Also, it+ precompiles the regular expressions into a PCRE+ compiled byte-array representation, at compile time.+License: BSD3+License-file: LICENSE+Author: Michael Sloan+Maintainer: Michael Sloan <mgsloan at gmail>+Homepage: http://github.com/mgsloan/rex+Copyright: Michael Sloan 2011+Category: Control+Build-type: Simple+Stability: experimental+Extra-source-files: Test.hs, Bench.hs+Data-files: README+Cabal-version: >=1.6+Bug-Reports: http://github.com/mgsloan/rex/issues+Source-Repository head+ Type: git+ Location: git://github.com/mgsloan/rex++Library+ Extensions: TemplateHaskell, QuasiQuotes, TupleSections, ViewPatterns+ Exposed-modules: Text.Regex.PCRE.Rex, Text.Regex.PCRE.Precompile+ Build-depends: base >= 3.0 && < 6, template-haskell >= 2.5.0.0,+ haskell-src-meta, MissingH, bytestring, pcre-light,+ split, containers, ghc >= 7+ Ghc-options: -Wall