packages feed

rex 0.3.1 → 0.4.1

raw patch · 9 files changed

+313/−262 lines, 9 filesdep −MissingHdep ~haskell-src-metaPVP ok

version bump matches the API change (PVP)

Dependencies removed: MissingH

Dependency ranges changed: haskell-src-meta

API changes (from Hackage documentation)

- Text.Regex.PCRE.Rex: rex, brex :: QuasiQuoter
- Text.Regex.PCRE.Rex: rexConf :: Bool -> Bool -> String -> [PCREOption] -> [PCREExecOption] -> QuasiQuoter
- Text.Regex.PCRE.Rex: rexPCREOptions :: [PCREOption]
+ Text.Regex.PCRE.Rex: RexConf :: Bool -> Bool -> String -> [PCREOption] -> [PCREExecOption] -> RexConf
+ Text.Regex.PCRE.Rex: brex :: QuasiQuoter
+ Text.Regex.PCRE.Rex: data RexConf
+ Text.Regex.PCRE.Rex: defaultRexConf :: RexConf
+ Text.Regex.PCRE.Rex: rex :: QuasiQuoter
+ Text.Regex.PCRE.Rex: rexByteString :: RexConf -> Bool
+ Text.Regex.PCRE.Rex: rexCompiled :: RexConf -> Bool
+ Text.Regex.PCRE.Rex: rexPCREExecOpts :: RexConf -> [PCREExecOption]
+ Text.Regex.PCRE.Rex: rexPCREOpts :: RexConf -> [PCREOption]
+ Text.Regex.PCRE.Rex: rexView :: RexConf -> String
+ Text.Regex.PCRE.Rex: rexWithConf :: RexConf -> QuasiQuoter

Files

Bench.hs view
@@ -3,22 +3,22 @@ module Main where  import Text.Regex.PCRE.Rex-import Test+import qualified Demo  import Criterion.Main  addEm :: Int -> [Double]-addEm n = map math $+addEm n = map Demo.math $   zipWith (++)     (zipWith (++) (map show [1..n])     (concat $ repeat ["+", "/", "-", "*"]))   (map show [100..]) -peanoize n = map (\i -> peano . (++"Z") . concat $ replicate i "S ") [0..n]+peanoize n = map (\i -> Demo.peano . (++"Z") . concat $ replicate i "S ") [0..n] -testPairs n = [parsePair $ "<" ++ replicate i ' ' ++ "a, pair>" | i <- [0..n]]+testPairs n = [Demo.parsePair $ "<" ++ replicate i ' ' ++ "a, pair>" | i <- [0..n]] -testDate n = [parseDate $ show i ++ ".10.20" | i <- [1900 .. 1900 + n]]+testDate n = [Demo.parseDate $ show i ++ ".10.20" | i <- [1900 .. 1900 + n]]  --NOTE: benchmark time includes test generation 
+ CHANGES.md view
@@ -0,0 +1,25 @@+0.1: Jul 25 2011+----------------+  * initial release++0.2: Sep 24 2011+----------------+  * Added custom configuration of PCRE options.+  * Added non-precompiling quasiquoters.+  * Fixed a bug where patterns with no captures would fail.+  * Decided to remove the defaulting to 'read' - too much magic.++0.3: Sep 25 2011+  * Fixed a capture indexing bug, where capture fields which aren't bound would+    cause subsequent bound captures to be incorrect.+  * Above bug fix actually neatened up code.+  * Added configuration of default mapping pattern.++0.4: Oct 11 2012+----------------+  * Made configuration into a datatype.++0.4.1: Feb 4 2013+------------------+  * Precompilation bugs fixed by [takano-akio](https://github.com/takano-akio)!+    Now precompilation is on by default.
+ Demo.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE TemplateHaskell, QuasiQuotes, ViewPatterns #-}++module Demo where++import Text.Regex.PCRE.Rex++import qualified Data.ByteString.Char8 as B+import Data.Maybe (catMaybes, isJust)++main =+  do demonstrate "math"      math      "1 + 3"+     demonstrate "math"      math      "3 * 2 + 100"+     demonstrate "math"      math      "20 / 3 + 100 * 2"+     demonstrate "peano"     peano     "S Z"+     demonstrate "peano"     peano     "S S S S Z"+     demonstrate "peano"     peano     "S   S   Z"+     demonstrate "parsePair" parsePair "<-1, 3>"+     demonstrate "parsePair" parsePair "<-4,3b0>"+     demonstrate "parsePair" parsePair "< a,  -30 >"+     demonstrate "parsePair" parsePair "< a,  other>"+     demonstrate "parseDate" parseDate "1993.8.10"+     demonstrate "parseDate" parseDate "1993.08.10"+     demonstrate "parseDate" parseDate "2003.02.28"+     demonstrate "parseDate" parseDate "2004.02.28"+     demonstrate "parseDate" parseDate "2003.02.27"+     demonstrate "disjunct"  disjunct  "a"+     demonstrate "disjunct"  disjunct  "ab"+     demonstrate "disjunct"  disjunct  "abc"+     print $ "btest: " ++ show btest++demonstrate n f input = putStrLn $ n ++ " \"" ++ input ++ "\" == " ++ show (f input)++math x = mathl x 0++mathl [] x = x+mathl [rex|^  \s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s y+mathl [rex|^\+\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x + y+mathl [rex|^ -\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x - y+mathl [rex|^\*\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x * y+mathl [rex|^ /\s*(?{ read -> y }\d+)\s*(?{ 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*$|]++parsePair :: String -> Maybe (String, String)+parsePair = [rex|^<\s* (?{ }[^\s,>]+) \s*,\s* (?{ }[^\s,>]+) \s*>$|]++-- From http://www.regular-expressions.info/dates.html+parseDate :: String -> Maybe (Int, Int, Int)+parseDate [rex|^(?{ read -> y }(?:19|20)\d\d)[- /.]+                (?{ read -> m }0[1-9]|1[012])[- /.]+                (?{ read -> 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]++btest = [brex|(?{}hello)|] (B.pack "hello") == Just (B.pack "hello")
− README
@@ -1,79 +0,0 @@-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.--Some examples (verbatim from Test.hs):--  math x = mathl x 0--  mathl [] x = x-  mathl [rex|^  \s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s y-  mathl [rex|^\+\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x + y-  mathl [rex|^ -\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x - y-  mathl [rex|^\*\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x * y-  mathl [rex|^ /\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x / y-  mathl str x = error str----- math "1 + 3" == 4.0--- math "3 * 2 + 100" == 106.0--- math "20 / 3 + 100 * 2" == 213.33333333333334---  peano :: String -> Maybe Int-  peano = [rex|^(?{ length . filter (=='S') } \s* (?:S\s+)*Z)\s*$|]----  peano "S Z" == Just 1---  peano "S S S S Z" == Just 4---  peano "S   S   Z" == Just 2--  parsePair :: String -> Maybe (String, String)-  parsePair = [rex|^<\s* (?{ }[^\s,>]+) \s*,\s* (?{ }[^\s,>]+) \s*>$|]----  parsePair "<-1, 3>" == Just ("-1","3")---  parsePair "<-4,3b0>" == Just ("-4","3b0")---  parsePair "< a,  -30 >" == Just ("a","-30")---  parsePair "< a,  other>" == Just ("a","other")----- From http://www.regular-expressions.info/dates.html-  parseDate :: String -> Maybe (Int, Int, Int)-  parseDate [rex|^(?{ read -> y }(?:19|20)\d\d)[- /.]-                  (?{ read -> m }0[1-9]|1[012])[- /.]-                  (?{ read -> 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----  parseDate "1993.8.10" == Nothing---  parseDate "1993.08.10" == Just (1993,8,10)---  parseDate "2003.02.28" == Just (2003,2,28)---  parseDate "2003.02.27" == Just (2003,2,27)--  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]----  disjunct "a" == 'a'---  disjunct "ab" == 'a'---  disjunct "abc" == 'c'
+ README.md view
@@ -0,0 +1,90 @@+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/Rex.hs` for documentation.++Some examples (verbatim from Test.hs):++```haskell+math x = mathl x 0++mathl [] x = x+mathl [rex|^  \s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s y+mathl [rex|^\+\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x + y+mathl [rex|^ -\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x - y+mathl [rex|^\*\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x * y+mathl [rex|^ /\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x / y+mathl str x = error str++-- math "1 + 3" == 4.0+-- math "3 * 2 + 100" == 106.0+-- math "20 / 3 + 100 * 2" == 213.33333333333334+```+++```haskell+peano :: String -> Maybe Int+peano = [rex|^(?{ length . filter (=='S') } \s* (?:S\s+)*Z)\s*$|]++--  peano "S Z" == Just 1+--  peano "S S S S Z" == Just 4+--  peano "S   S   Z" == Just 2+```++```haskell+parsePair :: String -> Maybe (String, String)+parsePair = [rex|^<\s* (?{ }[^\s,>]+) \s*,\s* (?{ }[^\s,>]+) \s*>$|]++--  parsePair "<-1, 3>" == Just ("-1","3")+--  parsePair "<-4,3b0>" == Just ("-4","3b0")+--  parsePair "< a,  -30 >" == Just ("a","-30")+--  parsePair "< a,  other>" == Just ("a","other")+```+++```haskell+-- From http://www.regular-expressions.info/dates.html+parseDate :: String -> Maybe (Int, Int, Int)+parseDate [rex|^(?{ read -> y }(?:19|20)\d\d)[- /.]+                (?{ read -> m }0[1-9]|1[012])[- /.]+                (?{ read -> 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++--  parseDate "1993.8.10" == Nothing+--  parseDate "1993.08.10" == Just (1993,8,10)+--  parseDate "2003.02.28" == Just (2003,2,28)+--  parseDate "2003.02.27" == Just (2003,2,27)+```++```haskell+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]++--  disjunct "a" == 'a'+--  disjunct "ab" == 'a'+--  disjunct "abc" == 'c'+```
− Test.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE TemplateHaskell, QuasiQuotes, ViewPatterns #-}--module Test where--import Text.Regex.PCRE.Rex--import qualified Data.ByteString.Char8 as B-import Data.Maybe (catMaybes, isJust)--demo =-  do demonstrate "math"      math      "1 + 3"-     demonstrate "math"      math      "3 * 2 + 100"-     demonstrate "math"      math      "20 / 3 + 100 * 2"-     demonstrate "peano"     peano     "S Z"-     demonstrate "peano"     peano     "S S S S Z"-     demonstrate "peano"     peano     "S   S   Z"-     demonstrate "parsePair" parsePair "<-1, 3>"-     demonstrate "parsePair" parsePair "<-4,3b0>"-     demonstrate "parsePair" parsePair "< a,  -30 >"-     demonstrate "parsePair" parsePair "< a,  other>"-     demonstrate "parseDate" parseDate "1993.8.10"-     demonstrate "parseDate" parseDate "1993.08.10"-     demonstrate "parseDate" parseDate "2003.02.28"-     demonstrate "parseDate" parseDate "2003.02.27"-     demonstrate "disjunct"  disjunct  "a"-     demonstrate "disjunct"  disjunct  "ab"-     demonstrate "disjunct"  disjunct  "abc"-     print $ "btest: " ++ show btest--demonstrate n f input = putStrLn $ n ++ " \"" ++ input ++ "\" == " ++ show (f input)--math x = mathl x 0--mathl [] x = x-mathl [rex|^  \s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s y-mathl [rex|^\+\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x + y-mathl [rex|^ -\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x - y-mathl [rex|^\*\s*(?{ read -> y }\d+)\s*(?{ s }.*)$|] x = mathl s $ x * y-mathl [rex|^ /\s*(?{ read -> y }\d+)\s*(?{ 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*$|]--parsePair :: String -> Maybe (String, String)-parsePair = [rex|^<\s* (?{ }[^\s,>]+) \s*,\s* (?{ }[^\s,>]+) \s*>$|]---- From http://www.regular-expressions.info/dates.html-parseDate :: String -> Maybe (Int, Int, Int)-parseDate [rex|^(?{ read -> y }(?:19|20)\d\d)[- /.]-                (?{ read -> m }0[1-9]|1[012])[- /.]-                (?{ read -> 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]--btest = [brex|(?{}hello)|] (B.pack "hello") == Just (B.pack "hello")
Text/Regex/PCRE/Precompile.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE TupleSections #-}-+{-# LANGUAGE MagicHash, BangPatterns #-} ----------------------------------------------------------------------------- -- | -- Module      :  Text.Regex.PCRE.Rex@@ -18,44 +17,41 @@  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 Control.Monad            (liftM)+import Data.ByteString.Char8    (ByteString, packCStringLen)+import Data.ByteString.Internal (toForeignPtr)+import Foreign.C.Types          (CSize)+import Foreign.ForeignPtr       (withForeignPtr)+import Foreign.Ptr              (nullPtr, castPtr)+import Foreign.Marshal          (alloca)+import Foreign.Storable         (peek)+import GHC.Exts                 (Int(..), plusAddr#)+import GHC.ForeignPtr           (ForeignPtr(..)) import Text.Regex.PCRE.Light import Text.Regex.PCRE.Light.Base -import Debug.Trace---- | A type synonym indicating which ByteStrings represent PCRE-format compiled--- data.-type CompiledBytes = B.ByteString+-- | A synonym indicating which ByteStrings represent PCRE-format compiled data.+type CompiledBytes = ByteString --- | 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 CompiledBytes)+-- | Compiles the given regular expression, and assuming nothing bad happens,+-- yields the bytestring filled with PCRE's compiled representation.+precompile :: ByteString -> [PCREOption] -> IO (Maybe CompiledBytes) precompile pat opts = regexToTable $ compile pat opts --- | Takes a compiled regular expression, and yields .+-- | Takes a compiled regular expression, and if successful, yields the+-- compiled representation. regexToTable :: Regex -> IO (Maybe CompiledBytes) 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)+    len <- return . fromIntegral =<< (peek res :: IO CSize)     if success >= 0 -      then withForeignPtr p (liftM Just . unsafePackCStringLen . (, len) . castPtr)+      then liftM Just $ packCStringLen (castPtr pcre, len)       else return Nothing  -- | Creates a regular expression from the compiled representation. regexFromTable :: CompiledBytes  -> IO Regex-regexFromTable bytes = unsafeUseAsCString bytes $ \cstr -> do-   ptr <- newForeignPtr_ (castPtr cstr)-   return $ Regex ptr bytes+regexFromTable bytes =+  return $ Regex (ForeignPtr (plusAddr# addr offset) content) bytes+ where+  !(ForeignPtr addr content, I# offset, _) = toForeignPtr bytes
Text/Regex/PCRE/Rex.hs view
@@ -20,13 +20,13 @@ -- 3) Allows for the inline interpolation of mapping functions :: String -> a. -- -- 4) Precompiles the regular expression at compile time, by calling into the--- PCRE library and storing a 'B.ByteString' literal representation of its state.+-- PCRE library and storing a 'ByteString' literal representation of its state. -- -- NOTE: for some unknown reason this feature is currently broken, and so off by -- default. -- -- 5) Compile-time configurable to use different PCRE options, turn off--- precompilation, use 'B.ByteString's, or set a default mapping expression.+-- precompilation, use 'ByteString's, or set a default mapping expression. -- -- Since this is a quasiquoter library that generates code using view patterns, -- the following extensions are required:@@ -102,12 +102,6 @@ -- 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.--- --- 3) The following error currently sometimes happens when using precompiled---    regular expressions.  This 'feature' is now off by default until this is---    fixed.--- --- >  <interactive>: out of memory (requested 17584491593728 bytes) -- -- 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| ... ]@@ -116,10 +110,13 @@ -- 'QuasiQuoter' is provided for this purpose.  You can also define your own -- 'QuasiQuoter' - the definitions of the default configurations are as follows: ----- > rex  = rexConf False True "id" rexPCREOptions []--- > brex = rexConf True  True "id" rexPCREOptions []+-- > rex  = rexWithConf $ defaultRexConf+-- > brex = rexWithConf $ defaultRexConf { rexByteString = True } +-- >+-- > defaultRexConf = RexConf False True "id" [PCRE.extended] [] ----- As mentioned, the other Bool determines whether precompilation is used.  The+-- The first @False@ specifies to use @String@ rather than 'ByteString'.  The+-- @True@ argument specifies to use precompilation.  --  The -- string following is the default mapping expression, used when omitted. -- Due to GHC staging restrictions, your configuration will need to be in a -- different module than its usage.@@ -132,49 +129,55 @@ -- ----------------------------------------------------------------------------- -module Text.Regex.PCRE.Rex (-  rex, brex, rexConf, rexPCREOptions,-  maybeRead, padRight, makeQuasiMultiline) where+module Text.Regex.PCRE.Rex+  (+  -- * Quasiquoters+    rex, brex+  -- * Configurable QuasiQuoter+  , rexWithConf, RexConf(..), defaultRexConf+  -- * Utility+  , makeQuasiMultiline+  -- * Used by Generated Code+  , maybeRead, padRight+  ) where -import qualified Text.Regex.PCRE.Light as PCRE-import qualified Text.Regex.PCRE.Light.Base as PCRE import Text.Regex.PCRE.Precompile -import Control.Arrow (first)-import Control.Monad (liftM)+import qualified Text.Regex.PCRE.Light as PCRE -import qualified Data.ByteString.Char8 as B-import Data.Either.Utils (forceEitherMsg)-import Data.List (find)-import Data.List.Split (split, onSublist)-import Data.Maybe (catMaybes, listToMaybe, fromJust, isJust)-import Data.Maybe.Utils (forceMaybeMsg)-import Data.Char (isSpace)+import Control.Applicative   ( (<$>) )+import Control.Arrow         ( first )+import Control.Monad         ( liftM )+import Data.ByteString.Char8 ( pack, unpack, empty )+import Data.List             ( find )+import Data.List.Split       ( split, onSublist )+import Data.Maybe            ( catMaybes, listToMaybe, fromJust, isJust )+import Data.Char             ( isSpace )+import System.IO.Unsafe      ( unsafePerformIO )  import Language.Haskell.TH import Language.Haskell.TH.Quote import Language.Haskell.Meta.Parse -import System.IO.Unsafe (unsafePerformIO)- {- TODO:-  * Fix mentioned caveats+  * Benchmark   * Target Text.Regex.Base ? -  * Provide a variant which allows splicing in an expression that evaluates to-    regex string.   * Add unit tests-  * Consider allowing passing arity lists in to configuration -} -type ParseChunk = Either String (Int, String)-type ParseChunks = (Int, String, [(Int, String)])-type Config = (Bool, Bool, String, [PCRE.PCREOption], [PCRE.PCREExecOption])+data RexConf = RexConf+  { rexByteString :: Bool+  , rexCompiled :: Bool+  , rexView :: String +  , rexPCREOpts :: [PCRE.PCREOption]+  , rexPCREExecOpts :: [PCRE.PCREExecOption]+  } --- | Default regular expression quasiquoter for 'String's and 'B.ByteString's,+-- | Default regular expression quasiquoter for 'String's and 'ByteString's, -- respectively. rex, brex :: QuasiQuoter-rex  = rexConf False False "id" rexPCREOptions []-brex = rexConf True  False "id" rexPCREOptions []+rex  = rexWithConf $ defaultRexConf+brex = rexWithConf $ defaultRexConf { rexByteString = True }  -- | This is a 'QuasiQuoter' transformer, which allows for a whitespace-sensitive -- quasi-quoter to be broken over multiple lines.  The default 'rex' and@@ -183,30 +186,28 @@ -- parameter, then this could be useful. The leading space of each line is -- ignored, and all newlines removed. makeQuasiMultiline :: QuasiQuoter -> QuasiQuoter-makeQuasiMultiline (QuasiQuoter a b c d) =-  QuasiQuoter (a . pre) (b . pre) (c . pre) (d . pre)+makeQuasiMultiline (QuasiQuoter a b c d)+  = QuasiQuoter (a . pre) (b . pre) (c . pre) (d . pre)  where   pre = concat . (\(x:xs) -> x : map (dropWhile isSpace) xs) . lines --- | Default compilation time PCRE options.  The default is 'PCRE.extended',--- which causes whitespace to be nonsemantic, and ignores # comments.-rexPCREOptions :: [PCRE.PCREOption]-rexPCREOptions = [ PCRE.extended ]-  -- , dotall, caseless, utf8-  -- , newline_any, PCRE.newline_crlf ]+-- | Default rex configuration, which specifies that the regexes operate on+-- strings, don't postprocess the matched patterns, and use 'PCRE.extended'.+-- This setting causes whitespace to be nonsemantic, and ignores # comments.+defaultRexConf :: RexConf+defaultRexConf = RexConf False False "id" [PCRE.extended] []  -- | A configureable regular-expression QuasiQuoter.  Takes the options to pass--- to the PCRE engine, along with 'Bool's to flag 'B.ByteString' usage and+-- to the PCRE engine, along with 'Bool's to flag 'ByteString' usage and -- non-compilation respecively.  The provided 'String' indicates which mapping -- function to use, when one is omitted - \"(?{} ...)\".-rexConf :: Bool -> Bool -> String -> [PCRE.PCREOption] -> [PCRE.PCREExecOption]-        -> QuasiQuoter-rexConf bs pc d os eos = QuasiQuoter-        (makeExp conf . parseIt)-        (makePat conf . parseIt)-        undefined undefined- where-  conf = (bs, pc, d, [PCRE.combineOptions os], [PCRE.combineExecOptions eos])+rexWithConf :: RexConf -> QuasiQuoter+rexWithConf conf+  = QuasiQuoter+      (makeExp conf . parseIt)+      (makePat conf . parseIt)+      undefined+      undefined  -- Template Haskell Code Generation -------------------------------------------------------------------------------@@ -215,10 +216,10 @@ -- 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 :: Config -> ParseChunks -> ExpQ+makeExp :: RexConf -> ParseChunks -> ExpQ makeExp conf (cnt, pat, exs) = buildExp conf cnt pat exs'  where-  exs' = map (\ix -> liftM (processExp conf . snd) $ find ((==ix).fst) exs) [0..cnt]+  exs' = map (\ix -> liftM (processExp conf . snd) $ find ((==ix) . fst) exs) [0..cnt]    -- Creates the template haskell Pat which corresponds to the parsed interpolated -- regex. As well as handling the aforementioned defaulting considerations, this@@ -226,7 +227,7 @@ --  -- E.g. [reg| ... (?{e1 -> v1} ...) ... (?{e2 -> v2} ...) ... |] becomes --      [reg| ... (?{e1} ...) ... (?{e2} ...) ... |] -> (v1, v2)-makePat :: Config -> ParseChunks -> PatQ+makePat :: RexConf -> ParseChunks -> PatQ makePat conf (cnt, pat, exs) = do   viewExp <- buildExp conf cnt pat $ map (liftM fst) views   return . ViewP viewExp@@ -249,29 +250,29 @@ -- 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 :: Config -> Int -> String -> [Maybe Exp] -> ExpQ-buildExp (bs, nc, _, pcreOpts, pcreExecOpts) cnt pat xs =+buildExp :: RexConf -> Int -> String -> [Maybe Exp] -> ExpQ+buildExp conf cnt pat xs =   [| let r = $(get_regex) in-     $(process) . (flip $ PCRE.match r) $(liftRS pcreExecOpts)-   . $(if bs then [| id |] else [| B.pack |]) |]+     $(process) . (flip $ PCRE.match r) $(liftRS $ rexPCREExecOpts conf)+   . $(if rexByteString conf then [| id |] else [| pack |]) |]  where-  liftRS x = [| read shown |]-   where shown = show x+  liftRS x = [| read shown |] where shown = show x    --TODO: make sure this takes advantage of bytestring fusion stuff - is   -- the right pack / unpack. Or use XOverloadedStrings-  get_regex = if nc-    then [| unsafePerformIO (regexFromTable $! $(table_bytes)) |]-    else [| PCRE.compile (B.pack pat) $(liftRS pcreOpts)|]-  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"+  get_regex +    | rexCompiled conf = [| unsafePerformIO (regexFromTable $! $(table_bytes)) |]+    | otherwise = [| PCRE.compile (pack pat) $(liftRS pcreOpts) |]+  table_bytes = [| pack $(LitE . StringL . unpack <$> runIO table_string) |]+  table_string+     = forceMaybeMsg "Error while getting PCRE compiled representation\n"+   <$> precompile (pack pat) pcreOpts+  pcreOpts = rexPCREOpts conf -  process = case (null vs, bs) of+  process = case (null vs, rexByteString conf) of     (True, _)  -> [| liftM ( const () ) |]-    (_, False) -> [| liftM (($(return maps)) . padRight "" pad . map B.unpack) |]-    (_, True)  -> [| liftM (($(return maps)) . padRight B.empty pad) |]+    (_, False) -> [| liftM ($(return maps) . padRight "" pad . map unpack) |]+    (_, True)  -> [| liftM ($(return maps) . padRight empty pad) |]   pad = cnt + 2   maps = LamE [ListP . (WildP:) $ map VarP vs]        . TupE . map (uncurry AppE)@@ -282,10 +283,10 @@   vs = [mkName $ "v" ++ show i | i <- [0..cnt]]  -- Parse a Haskell expression into a template Haskell Exp-processExp :: Config -> String -> Exp-processExp (_, _, d, _, _) xs+processExp :: RexConf -> String -> Exp+processExp conf xs   = forceEitherMsg ("Error while parsing capture mapper `" ++ xs ++ "'")-  . parseExp $ onSpace xs d id+  . parseExp $ onSpace xs (rexView conf) id  -- Parse a Haskell pattern match into a template Haskell Pat, yielding Nothing -- for patterns which consist of just whitespace.@@ -297,6 +298,9 @@ -- Parsing ------------------------------------------------------------------------------- +type ParseChunk = Either String (Int, String)+type ParseChunks = (Int, String, [(Int, String)])+ -- 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@@ -371,3 +375,16 @@  mapSnd :: (t -> t2) -> (t1, t) -> (t1, t2) mapSnd f (x, y) = (x, f y)++-- From MissingH++{- | Like 'forceMaybe', but lets you customize the error message raised if+Nothing is supplied. -}+forceMaybeMsg :: String -> Maybe a -> a+forceMaybeMsg msg Nothing = error msg+forceMaybeMsg _ (Just x) = x++{- | Like 'forceEither', but can raise a specific message with the error. -}+forceEitherMsg :: Show e => String -> Either e a -> a+forceEitherMsg msg (Left x) = error $ msg ++ ": " ++ show x+forceEitherMsg _ (Right x) = x
rex.cabal view
@@ -1,5 +1,5 @@ Name:                rex-Version:             0.3.1+Version:             0.4.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,@@ -18,8 +18,9 @@ Category:            Control Build-type:          Simple Stability:           experimental-Extra-source-files:  Test.hs, Bench.hs-Data-files:          README+Extra-source-files:  Demo.hs, Bench.hs+Data-files:          README.md+                     CHANGES.md Cabal-version:       >=1.6 Bug-Reports:         http://github.com/mgsloan/rex/issues Source-Repository head@@ -30,6 +31,6 @@   Extensions:        TemplateHaskell, QuasiQuotes, TupleSections, ViewPatterns   Exposed-modules:   Text.Regex.PCRE.Rex, Text.Regex.PCRE.Precompile   Build-depends:     base >= 3.0 && < 6, bytestring, containers, ghc >= 7.0,-                     haskell-src-meta, MissingH, pcre-light, split,+                     haskell-src-meta >= 0.5, pcre-light, split,                      template-haskell >= 2.5.0.0   Ghc-options:       -Wall