packages feed

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 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