regex 0.0.0.2 → 0.1.0.0
raw patch · 38 files changed
+2158/−916 lines, 38 filesdep +base-compatdep +http-conduitdep +time-locale-compatdep ~basedep ~regex-tdfadep ~textnew-component:exe:re-gen-cabalsnew-component:exe:re-prepnew-component:exe:re-testsPVP ok
version bump matches the API change (PVP)
Dependencies added: base-compat, http-conduit, time-locale-compat
Dependency ranges changed: base, regex-tdfa, text, time, transformers
API changes (from Hackage documentation)
- Text.RE.Internal.NamedCaptures: instance Monad m => Serial m Token
- Text.RE.Internal.NamedCaptures: namedCapturesTestTree :: TestTree
- Text.RE.Internal.PreludeMacros: PM_decimal :: PreludeMacro
- Text.RE.Internal.PreludeMacros: PM_integer :: PreludeMacro
- Text.RE.Internal.PreludeMacros: PM_natural :: PreludeMacro
- Text.RE.Internal.PreludeMacros: PM_natural_hex :: PreludeMacro
+ Text.RE: (!$$) :: Match a -> CaptureID -> a
+ Text.RE: (!$$?) :: Match a -> CaptureID -> Maybe a
+ Text.RE: (!$) :: Match a -> CaptureID -> Capture a
+ Text.RE: (!$?) :: Match a -> CaptureID -> Maybe (Capture a)
+ Text.RE: ALL :: Context
+ Text.RE: Alert :: Severity
+ Text.RE: Block :: Mode
+ Text.RE: BlockInsensitive :: SimpleRegexOptions
+ Text.RE: BlockSensitive :: SimpleRegexOptions
+ Text.RE: CID_name :: CaptureName -> CaptureID
+ Text.RE: CID_ordinal :: CaptureOrdinal -> CaptureID
+ Text.RE: Capture :: !a -> !a -> !Int -> !Int -> Capture a
+ Text.RE: CaptureName :: Text -> CaptureName
+ Text.RE: CaptureOrdinal :: Int -> CaptureOrdinal
+ Text.RE: Crit :: Severity
+ Text.RE: Debug :: Severity
+ Text.RE: Delete :: LineEdit s
+ Text.RE: EDIT_fun :: Context -> (LineNo -> Match s -> Location -> Capture s -> m (Maybe s)) -> Edit m s
+ Text.RE: EDIT_gen :: (LineNo -> Matches s -> m (LineEdit s)) -> Edit m s
+ Text.RE: EDIT_phi :: (Phi s) -> Edit m s
+ Text.RE: EDIT_tpl :: s -> Edit m s
+ Text.RE: Emerg :: Severity
+ Text.RE: Err :: Severity
+ Text.RE: Info :: Severity
+ Text.RE: Location :: Int -> CaptureOrdinal -> Location
+ Text.RE: MacroID :: String -> MacroID
+ Text.RE: Match :: !a -> !CaptureNames -> !(Array CaptureOrdinal (Capture a)) -> Match a
+ Text.RE: Matches :: !a -> ![Match a] -> Matches a
+ Text.RE: MultilineInsensitive :: SimpleRegexOptions
+ Text.RE: MultilineSensitive :: SimpleRegexOptions
+ Text.RE: NoEdit :: LineEdit s
+ Text.RE: Notice :: Severity
+ Text.RE: Options :: !Mode -> !(Macros r) -> !c -> !e -> Options_ r c e
+ Text.RE: Phi :: Context -> (Location -> a -> a) -> Phi a
+ Text.RE: Pipe :: [(re, Edit m s)] -> Edits m re s
+ Text.RE: ReplaceWith :: s -> LineEdit s
+ Text.RE: Replace_ :: (a -> Int) -> ((a -> a) -> Capture a -> a) -> Replace_ a
+ Text.RE: SUB :: Context
+ Text.RE: Select :: [(re, Edit m s)] -> Edits m re s
+ Text.RE: Simple :: Mode
+ Text.RE: TOP :: Context
+ Text.RE: Warning :: Severity
+ Text.RE: ZeroBasedLineNo :: Int -> LineNo
+ Text.RE: _MacroID :: MacroID -> String
+ Text.RE: _loc_capture :: Location -> CaptureOrdinal
+ Text.RE: _loc_match :: Location -> Int
+ Text.RE: _options_comp :: Options_ r c e -> !c
+ Text.RE: _options_exec :: Options_ r c e -> !e
+ Text.RE: _options_macs :: Options_ r c e -> !(Macros r)
+ Text.RE: _options_mode :: Options_ r c e -> !Mode
+ Text.RE: _phi_context :: Phi a -> Context
+ Text.RE: _phi_phi :: Phi a -> Location -> a -> a
+ Text.RE: _r_length :: Replace_ a -> a -> Int
+ Text.RE: _r_subst :: Replace_ a -> (a -> a) -> Capture a -> a
+ Text.RE: alex :: IsRegex re s => [(re, Match s -> Maybe t)] -> t -> s -> [t]
+ Text.RE: alex' :: Replace s => (re -> s -> Match s) -> [(re, Match s -> Maybe t)] -> t -> s -> [t]
+ Text.RE: allMatches :: Matches a -> ![Match a]
+ Text.RE: anyMatches :: Matches a -> Bool
+ Text.RE: appendNewline :: Replace a => a -> a
+ Text.RE: applyEdit :: (IsRegex re s, Monad m, Functor m) => (s -> s) -> LineNo -> re -> Edit m s -> s -> m (Maybe s)
+ Text.RE: applyEdits :: (IsRegex re s, Monad m, Functor m) => LineNo -> Edits m re s -> s -> m s
+ Text.RE: applyLineEdit :: Monoid s => (s -> s) -> LineEdit s -> Maybe s
+ Text.RE: capture :: CaptureID -> Match a -> Capture a
+ Text.RE: captureLength :: Capture a -> !Int
+ Text.RE: captureMaybe :: CaptureID -> Match a -> Maybe (Capture a)
+ Text.RE: captureNames :: Match a -> !CaptureNames
+ Text.RE: captureOffset :: Capture a -> !Int
+ Text.RE: capturePrefix :: Extract a => Capture a -> a
+ Text.RE: captureSource :: Capture a -> !a
+ Text.RE: captureSuffix :: Extract a => Capture a -> a
+ Text.RE: captureText :: CaptureID -> Match a -> a
+ Text.RE: captureTextMaybe :: CaptureID -> Match a -> Maybe a
+ Text.RE: capturedText :: Capture a -> !a
+ Text.RE: class IsOption o r c e | e -> r, c -> e, e -> c, r -> c, c -> r, r -> e
+ Text.RE: class Replace s => IsRegex re s
+ Text.RE: class (Extract a, Monoid a) => Replace a where textify = pack . unpack_ detextify = pack_ . unpack appendNewline = (<> pack_ "") subst f m@(Capture {..}) = capturePrefix m <> f capturedText <> captureSuffix m
+ Text.RE: countMatches :: Matches a -> Int
+ Text.RE: data Capture a
+ Text.RE: data CaptureID
+ Text.RE: data Context
+ Text.RE: data Edit m s
+ Text.RE: data Edits m re s
+ Text.RE: data LineEdit s
+ Text.RE: data Location
+ Text.RE: data Match a
+ Text.RE: data Matches a
+ Text.RE: data Mode
+ Text.RE: data Options_ r c e
+ Text.RE: data Phi a
+ Text.RE: data Replace_ a
+ Text.RE: data Severity
+ Text.RE: data SimpleRegexOptions
+ Text.RE: detextify :: Replace a => Text -> a
+ Text.RE: emptyMacros :: Macros r
+ Text.RE: expandMacros :: (r -> String) -> Mode -> Macros r -> String -> String
+ Text.RE: expandMacros' :: (MacroID -> Maybe String) -> String -> String
+ Text.RE: findCaptureID :: CaptureID -> CaptureNames -> Int
+ Text.RE: firstLine :: LineNo
+ Text.RE: getCaptureName :: CaptureName -> Text
+ Text.RE: getCaptureOrdinal :: CaptureOrdinal -> Int
+ Text.RE: getLineNo :: LineNo -> Int
+ Text.RE: getZeroBasedLineNo :: LineNo -> Int
+ Text.RE: grep :: IsRegex re ByteString => re -> FilePath -> IO ()
+ Text.RE: grepLines :: IsRegex re ByteString => re -> FilePath -> IO [Line]
+ Text.RE: grepScript :: IsRegex re s => GrepScript re s t -> [s] -> [t]
+ Text.RE: hasCaptured :: Capture a -> Bool
+ Text.RE: isTopLocation :: Location -> Bool
+ Text.RE: length_ :: Replace a => a -> Int
+ Text.RE: lineNo :: Int -> LineNo
+ Text.RE: linesMatched :: [Line] -> [Line]
+ Text.RE: mainCaptures :: Matches a -> [Capture a]
+ Text.RE: makeOptions :: IsOption o r c e => o -> Options_ r c e
+ Text.RE: matchArray :: Match a -> !(Array CaptureOrdinal (Capture a))
+ Text.RE: matchCapture :: Match a -> Maybe (Capture a)
+ Text.RE: matchCaptures :: Match a -> Maybe (Capture a, [Capture a])
+ Text.RE: matchMany :: IsRegex re s => re -> s -> Matches s
+ Text.RE: matchOnce :: IsRegex re s => re -> s -> Match s
+ Text.RE: matchSource :: Match a -> !a
+ Text.RE: matched :: Match a -> Bool
+ Text.RE: matchedText :: Match a -> Maybe a
+ Text.RE: matches :: Matches a -> [a]
+ Text.RE: matchesSource :: Matches a -> !a
+ Text.RE: newtype CaptureName
+ Text.RE: newtype CaptureOrdinal
+ Text.RE: newtype LineNo
+ Text.RE: newtype MacroID
+ Text.RE: noCaptureNames :: CaptureNames
+ Text.RE: noMatch :: a -> Match a
+ Text.RE: pack_ :: Replace a => String -> a
+ Text.RE: parseDate :: Replace a => a -> Maybe Day
+ Text.RE: parseDateTime :: Replace a => a -> Maybe UTCTime
+ Text.RE: parseDateTime8601 :: Replace a => a -> Maybe UTCTime
+ Text.RE: parseDateTimeCLF :: Replace a => a -> Maybe UTCTime
+ Text.RE: parseDouble :: Replace a => a -> Maybe Double
+ Text.RE: parseHex :: Replace a => a -> Maybe Int
+ Text.RE: parseIPv4Address :: Replace a => a -> Maybe IPV4Address
+ Text.RE: parseInteger :: Replace a => a -> Maybe Int
+ Text.RE: parseSeverity :: Replace a => a -> Maybe Severity
+ Text.RE: parseShortMonth :: Replace a => a -> Maybe Int
+ Text.RE: parseSimpleString :: Replace a => a -> Maybe Text
+ Text.RE: parseSlashesDate :: Replace a => a -> Maybe Day
+ Text.RE: parseString :: Replace a => a -> Maybe Text
+ Text.RE: parseTimeOfDay :: Replace a => a -> Maybe TimeOfDay
+ Text.RE: parseTimeZone :: Replace a => a -> Maybe TimeZone
+ Text.RE: parse_tpl :: Replace a => a -> Match a -> Location -> Capture a -> Maybe a
+ Text.RE: regexSource :: IsRegex re s => re -> String
+ Text.RE: replace :: Replace a => Match a -> a -> a
+ Text.RE: replaceAll :: Replace a => a -> Matches a -> a
+ Text.RE: replaceAllCaptures :: Replace a => Phi a -> Matches a -> a
+ Text.RE: replaceAllCaptures' :: Replace a => Context -> (Match a -> Location -> Capture a -> Maybe a) -> Matches a -> a
+ Text.RE: replaceAllCapturesM :: (Extract a, Monad m) => Replace_ a -> Context -> (Match a -> Location -> Capture a -> m (Maybe a)) -> Matches a -> m a
+ Text.RE: replaceAllCaptures_ :: Extract a => Replace_ a -> Context -> (Match a -> Location -> Capture a -> Maybe a) -> Matches a -> a
+ Text.RE: replaceCaptures :: Replace a => Phi a -> Match a -> a
+ Text.RE: replaceCaptures' :: Replace a => Context -> (Match a -> Location -> Capture a -> Maybe a) -> Match a -> a
+ Text.RE: replaceCapturesM :: (Monad m, Extract a) => Replace_ a -> Context -> (Match a -> Location -> Capture a -> m (Maybe a)) -> Match a -> m a
+ Text.RE: replaceCaptures_ :: Extract a => Replace_ a -> Context -> (Match a -> Location -> Capture a -> Maybe a) -> Match a -> a
+ Text.RE: replace_ :: Replace a => Replace_ a
+ Text.RE: sed :: IsRegex re ByteString => SedScript re -> FilePath -> FilePath -> IO ()
+ Text.RE: sed' :: (IsRegex re ByteString, Monad m, Functor m) => Edits m re ByteString -> ByteString -> m ByteString
+ Text.RE: severityKeywords :: Severity -> (Text, [Text])
+ Text.RE: shortMonthArray :: Array Int Text
+ Text.RE: subst :: Replace a => (a -> a) -> Capture a -> a
+ Text.RE: textify :: Replace a => a -> Text
+ Text.RE: type CaptureNames = HashMap CaptureName CaptureOrdinal
+ Text.RE: type GrepScript re s t = [(re, LineNo -> Matches s -> Maybe t)]
+ Text.RE: type IPV4Address = (Word8, Word8, Word8, Word8)
+ Text.RE: type Macros r = HashMap MacroID r
+ Text.RE: type SedScript re = Edits IO re ByteString
+ Text.RE: unpack_ :: Replace a => a -> String
+ Text.RE.Capture: (!$$) :: Match a -> CaptureID -> a
+ Text.RE.Capture: (!$$?) :: Match a -> CaptureID -> Maybe a
+ Text.RE.Capture: (!$) :: Match a -> CaptureID -> Capture a
+ Text.RE.Capture: (!$?) :: Match a -> CaptureID -> Maybe (Capture a)
+ Text.RE.Capture: emptyMatchArray :: Array CaptureOrdinal (Capture a)
+ Text.RE.Capture: noMatch :: a -> Match a
+ Text.RE.Internal.NamedCaptures: BS :: Char -> Token
+ Text.RE.Internal.NamedCaptures: Bra :: Token
+ Text.RE.Internal.NamedCaptures: ECap :: (Maybe String) -> Token
+ Text.RE.Internal.NamedCaptures: Other :: Char -> Token
+ Text.RE.Internal.NamedCaptures: PCap :: Token
+ Text.RE.Internal.NamedCaptures: PGrp :: Token
+ Text.RE.Internal.NamedCaptures: data Token
+ Text.RE.Internal.NamedCaptures: formatTokens :: [Token] -> String
+ Text.RE.Internal.NamedCaptures: formatTokens' :: FormatTokenOptions -> [Token] -> String
+ Text.RE.Internal.NamedCaptures: formatTokens0 :: [Token] -> String
+ Text.RE.Internal.NamedCaptures: idFormatTokenOptions :: FormatTokenOptions
+ Text.RE.Internal.NamedCaptures: scan :: String -> [Token]
+ Text.RE.Internal.NamedCaptures: validToken :: Token -> Bool
+ Text.RE.Internal.PreludeMacros: PM_frac :: PreludeMacro
+ Text.RE.Internal.PreludeMacros: PM_hex :: PreludeMacro
+ Text.RE.Internal.PreludeMacros: PM_id_ :: PreludeMacro
+ Text.RE.Internal.PreludeMacros: PM_int :: PreludeMacro
+ Text.RE.Internal.PreludeMacros: PM_nat :: PreludeMacro
+ Text.RE.Tools.Grep: linesMatched :: [Line] -> [Line]
- Text.RE.Capture: Match :: !a -> CaptureNames -> !(Array CaptureOrdinal (Capture a)) -> Match a
+ Text.RE.Capture: Match :: !a -> !CaptureNames -> !(Array CaptureOrdinal (Capture a)) -> Match a
- Text.RE.Capture: Matches :: !a -> [Match a] -> Matches a
+ Text.RE.Capture: Matches :: !a -> ![Match a] -> Matches a
- Text.RE.Capture: allMatches :: Matches a -> [Match a]
+ Text.RE.Capture: allMatches :: Matches a -> ![Match a]
- Text.RE.Capture: captureNames :: Match a -> CaptureNames
+ Text.RE.Capture: captureNames :: Match a -> !CaptureNames
- Text.RE.Parsers: parseSimpleString :: Replace a => a -> Maybe String
+ Text.RE.Parsers: parseSimpleString :: Replace a => a -> Maybe Text
- Text.RE.Parsers: parseString :: Replace a => a -> Maybe String
+ Text.RE.Parsers: parseString :: Replace a => a -> Maybe Text
- Text.RE.Parsers: severityKeywords :: Severity -> (String, [String])
+ Text.RE.Parsers: severityKeywords :: Severity -> (Text, [Text])
- Text.RE.Parsers: shortMonthArray :: Array Int String
+ Text.RE.Parsers: shortMonthArray :: Array Int Text
Files
- README.markdown +97/−0
- README.md +0/−47
- Text/RE.hs +185/−8
- Text/RE/Capture.lhs +39/−7
- Text/RE/Edit.lhs +6/−2
- Text/RE/Internal/NamedCaptures.lhs +11/−77
- Text/RE/Internal/PreludeMacros.hs +75/−16
- Text/RE/PCRE.hs +4/−0
- Text/RE/PCRE/ByteString.hs +4/−0
- Text/RE/PCRE/ByteString/Lazy.hs +4/−0
- Text/RE/PCRE/RE.hs +6/−1
- Text/RE/PCRE/Sequence.hs +4/−0
- Text/RE/PCRE/String.hs +4/−0
- Text/RE/Parsers.hs +15/−16
- Text/RE/Replace.lhs +4/−2
- Text/RE/TDFA.hs +4/−0
- Text/RE/TDFA/ByteString.hs +4/−0
- Text/RE/TDFA/ByteString/Lazy.hs +4/−0
- Text/RE/TDFA/RE.hs +6/−1
- Text/RE/TDFA/Sequence.hs +4/−0
- Text/RE/TDFA/String.hs +4/−0
- Text/RE/TDFA/Text.hs +4/−0
- Text/RE/TDFA/Text/Lazy.hs +4/−0
- Text/RE/TestBench.lhs +15/−8
- Text/RE/Tools/Grep.lhs +7/−4
- Text/RE/Tools/Lex.lhs +6/−2
- Text/RE/Tools/Sed.lhs +6/−1
- changelog +12/−0
- examples/TestKit.lhs +83/−1
- examples/re-gen-cabals.lhs +191/−0
- examples/re-gen-modules.lhs +3/−2
- examples/re-include.lhs +4/−3
- examples/re-nginx-log-processor.lhs +23/−22
- examples/re-pp.lhs +0/−459
- examples/re-prep.lhs +828/−0
- examples/re-tests.lhs +101/−20
- examples/re-tutorial.lhs +19/−16
- regex.cabal +368/−201
+ README.markdown view
@@ -0,0 +1,97 @@+# regex++Regex is a regular expression toolkit for regex-base with:++ * text-replacement operations with named captures;+ * special datatypes for matches and captures;+ * compile-time checking of RE syntax;+ * a unified means of controlling case-sensitivity and multi-line options;+ * high-level AWK-like tools for building text processing apps;+ * the option of using match operators with reduced polymorphism on the+ text and/or result types;+ * regular expression macros including:+ + a number of useful RE macros;+ + a test bench for testing and documenting new macro environments;+ * built-in support for the TDFA and PCRE backends;+ * comprehensive documentation and copious examples.+++See the [About page](http://about.regex.uk) for details.+++## Road Map++ ☒ 2017-01-26 v0.0.0.1 Pre-release (I)++ ☒ 2017-01-30 v0.0.0.2 Pre-release (II)++ ☒ 2017-02-19 v0.1.0.0 [Proposed core API with presentable Haddocks](https://github.com/iconnect/regex/milestone/1)++ ☐ 2017-02-26 v0.1.1.0 [Tutorials and examples finalized](https://github.com/iconnect/regex/milestone/2)++ ☐ 2017-03-20 v1.0.0.0 [First stable release](https://github.com/iconnect/regex/milestone/3)++ ☐ 2017-08-31 v2.0.0.0 [Fast text replacement with benchmarks](https://github.com/iconnect/regex/milestone/4)++++See the [Roadmap page](http://roadmap.regex.uk) for details.+++## Build Status++[](https://hackage.haskell.org/package/regex) [](https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29) [](https://travis-ci.org/iconnect/regex) [](https://ci.appveyor.com/project/engineerirngirisconnectcouk/regex/branch/master) [](https://coveralls.io/github/iconnect/regex?branch=master)<br/>+See [build status page](http://regex.uk/build-status) for details.+++## Installing the Package++The package can be easily installed with cabal or stack on GHC-8.0,+ 7.10 or 7.8 for the above platforms. See the+[Installation page](http://installation.regex.uk) for details.+++## The Tutorial Tests and Examples++See the [Tutorial page](http://tutorial.regex.uk) and+[Examples page](http://examples.regex.uk) for details.+++## Helping Out++If you have any feedback or suggestion then please drop us a line.++ `t` [@hregex](https://twitter.com/hregex)<br/>+ `e` maintainers@regex.uk<br/>+ `w` http://issues.regex.uk++The [Contact page](http://contact.regex.uk) has more details.+++## The API++The Haddocks can be found at http://hs.regex.uk.+++## The Macro Tables++The macro environments are an important part of the package and+are documented [here](http://macros.regex.uk).+++## The regex.uk Directory++A handy overview of the regex.uk domain can be found+[here](http://directory.regex.uk).+++## The Changelog++The `changelog` is posted [here](http://changelog.regex.uk).+++## The Authors++This library was written and is currently maintained by+[Chris Dornan](mailto:chris.dornan@irisconnect.com) aka+[@cdornan](https://twitter.com/cdornan)
− README.md
@@ -1,47 +0,0 @@-[](https://hackage.haskell.org/package/regex)-[](https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29)-[](https://travis-ci.org/iconnect/regex)-[](https://ci.appveyor.com/project/engineerirngirisconnectcouk/regex/branch/master)-[](https://coveralls.io/github/iconnect/regex?branch=master)--# regex: A Regular Expression Toolkit for regex-base--regex extends regex-base with:-- * a text-replacement toolkit- * special datatypes for many matches, first match and individual captures- * compile-time checking of RE syntax- * a unified means of controlling case-sensitivity and multi-line options- * high-level AWK-like tools for building text processing apps- * the option of using match operators with reduced polymorphism on the- text and/or result types- * regular expression macros including- + a number of useful RE macros- + a test bench for testing and documenting new macro environments- * built-in support for the TDFA and PCRE backends- * comprehensive documentation and copious examples---Schedule------------ [X] **2017-01-26** 0.0.0.1 Pre-release (I)-- [X] **2017-01-30** 0.0.0.2 Pre-release (II)-- [ ] **2017-02-06** 0.0.1.0 RFC-- [ ] **2017-02-20** 0.1.0.0 a candidate stable release-- [ ] **2017-03-20** 1.0.0.0 first stable release---The Web Page---------------We have a [web page](https://iconnect.github.io/regex/) with a tutorial,-a major example and and more examples than you can shake a stick at (most-of them used in the package itself).---The Macro Tables-------------------The macro environments are an important part of the package and they-are documented [in these tables](tables).
Text/RE.hs view
@@ -1,14 +1,133 @@ {-# OPTIONS_GHC -fno-warn-dodgy-exports #-}+-- |+-- Module : Text.RE+-- Copyright : (C) 2016-17 Chris Dornan+-- License : BSD3 (see the LICENSE file)+-- Maintainer : Chris Dornan <chris.dornan@irisconnect.com>+-- Stability : RFC+-- Portability : portable module Text.RE- ( module Text.RE.Capture- , module Text.RE.CaptureID- , module Text.RE.Edit- , module Text.RE.IsRegex- , module Text.RE.LineNo- , module Text.RE.Options- , module Text.RE.Parsers- , module Text.RE.Replace+ (+ -- * Tutorial+ -- $tutorial++ -- * How to use this library+ -- $use++ -- ** The Match Operators+ -- $operators++ -- * Matches, Match, Capture Types and Functions+ Matches(..)+ , Match(..)+ , Capture(..)+ , noMatch+ -- ** Matches functions+ , anyMatches+ , countMatches+ , matches+ , mainCaptures+ -- ** Match functions+ , matched+ , matchedText+ , matchCapture+ , matchCaptures+ , (!$$)+ , captureText+ , (!$$?)+ , captureTextMaybe+ , (!$)+ , capture+ , (!$?)+ , captureMaybe+ -- ** Capture functions+ , hasCaptured+ , capturePrefix+ , captureSuffix+ -- * IsRegex+ , IsRegex(..)+ -- * Options+ , Options_(..)+ , IsOption(..)+ , Mode(..)+ , MacroID(..)+ , Macros+ , emptyMacros+ , SimpleRegexOptions(..)+ -- * CaptureID+ , CaptureID(..)+ , CaptureNames+ , noCaptureNames+ , CaptureName(..)+ , CaptureOrdinal(..)+ , findCaptureID+ -- * Edit+ , Edits(..)+ , Edit(..)+ , LineEdit(..)+ , applyEdits+ , applyEdit+ , applyLineEdit+ -- * LineNo+ , LineNo(..)+ , firstLine+ , getLineNo+ , lineNo+ -- * Parsers+ , parseInteger+ , parseHex+ , parseDouble+ , parseString+ , parseSimpleString+ , parseDate+ , parseSlashesDate+ , parseTimeOfDay+ , parseTimeZone+ , parseDateTime+ , parseDateTime8601+ , parseDateTimeCLF+ , parseShortMonth+ , shortMonthArray+ , IPV4Address+ , parseIPv4Address+ , Severity(..)+ , parseSeverity+ , severityKeywords+ -- * Replace+ , Replace(..)+ , Replace_(..)+ , replace_+ , Phi(..)+ , Context(..)+ , Location(..)+ , isTopLocation+ , replace+ , replaceAll+ , replaceAllCaptures+ , replaceAllCaptures'+ , replaceAllCaptures_+ , replaceAllCapturesM+ , replaceCaptures+ , replaceCaptures'+ , replaceCaptures_+ , replaceCapturesM+ , expandMacros+ , expandMacros'+ -- * Tools+ -- ** Grep+ , grep+ , grepLines+ , GrepScript+ , grepScript+ , linesMatched+ -- ** Lex+ , alex+ , alex'+ -- ** Sed+ , SedScript+ , sed+ , sed' ) where import Text.RE.Capture@@ -19,3 +138,61 @@ import Text.RE.Options import Text.RE.Parsers import Text.RE.Replace+import Text.RE.Tools.Grep+import Text.RE.Tools.Lex+import Text.RE.Tools.Sed++-- $tutorial+-- We have a regex tutorial at <http://tutorial.regex.uk>. These API+-- docs are mainly for reference.++-- $use+--+-- This module won't provide any operators to match a regular expression+-- against text as it merely provides the toolkit for working with the+-- output of the match operators. You probably won't import it directly+-- but import one of the modules that provides the match operators,+-- which will in tuen re-export this module.+--+-- The module that you choose to import will depend upon two factors:+--+-- * Which flavour of regular expression do you want to use? If you want+-- Posix flavour REs then you want the TDFA modules, otherwise its+-- PCRE for Perl-style REs.+--+-- * What type of text do you want to match: (slow) @String@s, @ByteString@,+-- @ByteString.Lazy@, @Text@, @Text.Lazy@ or the anachronistic @Seq Char@+-- or indeed a good old-fashioned polymorphic operators?+--+-- While we aim to provide all combinations of these choices, some of them+-- are currently not available. We have:+--+-- * "Text.RE.PCRE"+-- * "Text.RE.PCRE.ByteString"+-- * "Text.RE.PCRE.ByteString.Lazy"+-- * "Text.RE.PCRE.RE"+-- * "Text.RE.PCRE.Sequence"+-- * "Text.RE.PCRE.String"+-- * "Text.RE.TDFA"+-- * "Text.RE.TDFA.ByteString"+-- * "Text.RE.TDFA.ByteString.Lazy"+-- * "Text.RE.TDFA.RE"+-- * "Text.RE.TDFA.Sequence"+-- * "Text.RE.TDFA.String"+-- * "Text.RE.TDFA.Text"+-- * "Text.RE.TDFA.Text.Lazy"++-- $operators+--+-- The traditional @=~@ and @=~~@ operators are exported by the @regex@,+-- but we recommend that you use the two new operators, especially if+-- you are not familiar with the old operators. We have:+--+-- * @txt ?=~ re@ searches for a single match yielding a value of type+-- 'Match' @a@ where @a@ is the type of the text you are searching.+--+-- * @txt *=~ re@ searches for all non-overlapping matches in @txt@,+-- returning a value of type 'Matches' @a@.+--+-- See the sections below for more information on these @Matches@ and+-- @Match@ result types.
Text/RE/Capture.lhs view
@@ -10,6 +10,8 @@ ( Matches(..) , Match(..) , Capture(..)+ , noMatch+ , emptyMatchArray -- Matches functions , anyMatches , countMatches@@ -20,9 +22,13 @@ , matchedText , matchCapture , matchCaptures+ , (!$$) , captureText+ , (!$$?) , captureTextMaybe+ , (!$) , capture+ , (!$?) , captureMaybe -- Capture functions , hasCaptured@@ -36,6 +42,8 @@ import Data.Maybe import Text.Regex.Base import Text.RE.CaptureID++infixl 9 !$, !$$ \end{code} @@ -46,7 +54,7 @@ data Matches a = Matches { matchesSource :: !a -- ^ the source text being matched- , allMatches :: [Match a] -- ^ all captures found, left to right+ , allMatches :: ![Match a] -- ^ all captures found, left to right } deriving (Show,Eq) \end{code}@@ -59,7 +67,7 @@ data Match a = Match { matchSource :: !a -- ^ the whole source text- , captureNames :: CaptureNames -- ^ the RE's capture names+ , captureNames :: !CaptureNames -- ^ the RE's capture names , matchArray :: !(Array CaptureOrdinal (Capture a)) -- ^ 0..n-1 captures, -- starting with the@@ -86,11 +94,21 @@ \end{code} \begin{code}+-- | Construct a Match that does not match anything.+noMatch :: a -> Match a+noMatch t = Match t noCaptureNames emptyMatchArray++-- | an empty array of Capture+emptyMatchArray :: Array CaptureOrdinal (Capture a)+emptyMatchArray = listArray (CaptureOrdinal 0,CaptureOrdinal $ -1) []+\end{code}++\begin{code} instance Functor Matches where fmap f Matches{..} = Matches { matchesSource = f matchesSource- , allMatches = map (fmap f) allMatches+ , allMatches = map (fmap f) allMatches } instance Functor Match where@@ -151,29 +169,45 @@ True -> Nothing False -> Just (matchArray!0,drop 1 $ elems matchArray) +-- | an alternative for captureText+(!$$) :: Match a -> CaptureID -> a+(!$$) = flip captureText+ -- | look up the text of the nth capture, 0 being the match of the whole -- RE against the source text, 1, the first bracketed sub-expression to -- be matched and so on captureText :: CaptureID -> Match a -> a captureText cid mtch = capturedText $ capture cid mtch +-- | an alternative for captureTextMaybe+(!$$?) :: Match a -> CaptureID -> Maybe a+(!$$?) = flip captureTextMaybe+ -- | look up the text of the nth capture (0 being the match of the -- whole), returning Nothing if the Match doesn't contain the capture captureTextMaybe :: CaptureID -> Match a -> Maybe a captureTextMaybe cid mtch = do- cap <- captureMaybe cid mtch+ cap <- mtch !$? cid case hasCaptured cap of True -> Just $ capturedText cap False -> Nothing +-- | an alternative for capture+(!$) :: Match a -> CaptureID -> Capture a+(!$) = flip capture+ -- | look up the nth capture, 0 being the match of the whole RE against -- the source text, 1, the first bracketed sub-expression to be matched -- and so on capture :: CaptureID -> Match a -> Capture a-capture cid mtch = fromMaybe oops $ captureMaybe cid mtch+capture cid mtch = fromMaybe oops $ mtch !$? cid where oops = error $ "capture: out of bounds (" ++ show cid ++ ")" +-- | an alternative for capture captureMaybe+(!$?) :: Match a -> CaptureID -> Maybe (Capture a)+(!$?) = flip captureMaybe+ -- | look up the nth capture, 0 being the match of the whole RE against -- the source text, 1, the first bracketed sub-expression to be matched -- and so on, returning Nothing if there is no such capture, or if the@@ -207,8 +241,6 @@ captureSuffix :: Extract a => Capture a -> a captureSuffix Capture{..} = after (captureOffset+captureLength) captureSource \end{code}-- \begin{code}
Text/RE/Edit.lhs view
@@ -1,5 +1,10 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.Edit ( LineNo@@ -11,9 +16,8 @@ , applyLineEdit ) where -import Control.Applicative import Data.Maybe-import Data.Monoid+import Prelude.Compat import Text.RE.Capture import Text.RE.IsRegex import Text.RE.LineNo
Text/RE/Internal/NamedCaptures.lhs view
@@ -1,17 +1,20 @@ \begin{code} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE RecordWildCards #-} module Text.RE.Internal.NamedCaptures ( cp , extractNamedCaptures- , namedCapturesTestTree- )- where+ , idFormatTokenOptions+ , Token(..)+ , validToken+ , formatTokens+ , formatTokens'+ , formatTokens0+ , scan+ ) where import Data.Char import qualified Data.HashMap.Strict as HM@@ -19,15 +22,10 @@ import GHC.Generics import qualified Language.Haskell.TH as TH import Language.Haskell.TH.Quote-import Test.SmallCheck.Series-import Test.Tasty-import Test.Tasty.HUnit-import Test.Tasty.SmallCheck as SC import Text.Heredoc import Text.RE import Text.RE.Internal.PreludeMacros import Text.RE.Internal.QQ-import Text.RE.Tools.Lex import Text.Regex.PCRE @@ -41,13 +39,6 @@ extractNamedCaptures s = Right (analyseTokens tks,formatTokens tks) where tks = scan s--namedCapturesTestTree :: TestTree-namedCapturesTestTree = localOption (SmallCheckDepth 4) $- testGroup "NamedCaptures"- [ formatScanTestTree- , analyseTokensTestTree- ] \end{code} @@ -64,8 +55,6 @@ | Other Char deriving (Show,Generic,Eq) -instance Monad m => Serial m Token- validToken :: Token -> Bool validToken tkn = case tkn of ECap mb -> maybe True check_ecap mb@@ -161,9 +150,9 @@ defFormatTokenOptions :: FormatTokenOptions defFormatTokenOptions = FormatTokenOptions- { _fto_regex_type = Nothing- , _fto_min_caps = False- , _fto_incl_caps = False+ { _fto_regex_type = Nothing+ , _fto_min_caps = False+ , _fto_incl_caps = False } idFormatTokenOptions :: FormatTokenOptions@@ -213,59 +202,4 @@ Bra -> "(" BS c -> "\\" ++ [c] Other c -> [c]-\end{code}---Testing : FormatToken/Scan Properties----------------------------------------\begin{code}-formatScanTestTree :: TestTree-formatScanTestTree =- testGroup "FormatToken/Scan Properties"- [ localOption (SmallCheckDepth 4) $- SC.testProperty "formatTokens == formatTokens0" $- \tks -> formatTokens tks == formatTokens0 tks- , localOption (SmallCheckDepth 4) $- SC.testProperty "scan . formatTokens' idFormatTokenOptions == id" $- \tks -> all validToken tks ==>- scan (formatTokens' idFormatTokenOptions tks) == tks- ]-\end{code}---Testing : Analysing [Token] Unit Tests-----------------------------------------\begin{code}-analyseTokensTestTree :: TestTree-analyseTokensTestTree =- testGroup "Analysing [Token] Unit Tests"- [ tc [here|foobar|] []- , tc [here||] []- , tc [here|$([0-9]{4})|] []- , tc [here|${x}()|] [(1,"x")]- , tc [here|${}()|] []- , tc [here|${}()${foo}()|] [(2,"foo")]- , tc [here|${x}(${y()})|] [(1,"x")]- , tc [here|${x}(${y}())|] [(1,"x"),(2,"y")]- , tc [here|${a}(${b{}())|] [(1,"a")]- , tc [here|${y}([0-9]{4})-${m}([0-9]{2})-${d}([0-9]{2})|] [(1,"y"),(2,"m"),(3,"d")]- , tc [here|@$(@|\{${name}([^{}]+)\})|] [(2,"name")]- , tc [here|${y}[0-9]{4}|] []- , tc [here|${}([0-9]{4})|] []- ]- where- tc s al =- testCase s $ assertEqual "CaptureNames"- (xnc s)- (HM.fromList- [ (CaptureName $ T.pack n,CaptureOrdinal i)- | (i,n)<-al- ]- )-- xnc = either oops fst . extractNamedCaptures- where- oops = error "analyseTokensTestTree: unexpected parse failure" \end{code}
Text/RE/Internal/PreludeMacros.hs view
@@ -1,6 +1,11 @@+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.Internal.PreludeMacros ( RegexType(..)@@ -18,12 +23,13 @@ , preludeMacroDescriptor ) where -import Control.Applicative import Data.Array-import qualified Data.HashMap.Lazy as HML+import qualified Data.HashMap.Lazy as HML import Data.List import Data.Maybe+import qualified Data.Text as T import Data.Time+import Prelude.Compat import Text.RE.Options import Text.RE.Parsers import Text.RE.TestBench@@ -72,14 +78,15 @@ -> PreludeMacro -> Maybe MacroDescriptor preludeMacroDescriptor rty env pm = case pm of- PM_natural -> natural_macro rty env pm- PM_natural_hex -> natural_hex_macro rty env pm- PM_integer -> integer_macro rty env pm- PM_decimal -> decimal_macro rty env pm+ PM_nat -> natural_macro rty env pm+ PM_hex -> natural_hex_macro rty env pm+ PM_int -> integer_macro rty env pm+ PM_frac -> decimal_macro rty env pm PM_string -> string_macro rty env pm PM_string_simple -> string_simple_macro rty env pm PM_id -> id_macro rty env pm PM_id' -> id'_macro rty env pm+ PM_id_ -> id__macro rty env pm PM_date -> date_macro rty env pm PM_date_slashes -> date_slashes_macro rty env pm PM_time -> time_macro rty env pm@@ -96,16 +103,17 @@ -- | an enumeration of all of the prelude macros data PreludeMacro -- numbers- = PM_natural- | PM_natural_hex- | PM_integer- | PM_decimal+ = PM_nat+ | PM_hex+ | PM_int+ | PM_frac -- strings | PM_string | PM_string_simple -- identifiers | PM_id | PM_id'+ | PM_id_ -- dates & times | PM_date | PM_date_slashes@@ -125,8 +133,12 @@ -- | naming the macros presentPreludeMacro :: PreludeMacro -> String-presentPreludeMacro = (prelude_prefix++) . map tr . drop 3 . show+presentPreludeMacro pm = case pm of+ PM_id_ -> prelude_prefix++"id-"+ _ -> fmt pm where+ fmt = (prelude_prefix++) . map tr . drop 3 . show+ tr '_' = '.' tr c = c @@ -263,7 +275,7 @@ -> Maybe MacroDescriptor string_macro PCRE _ _ = Nothing string_macro rty@TDFA env pm =- Just $ run_tests rty parseString samples env pm+ Just $ run_tests rty (fmap T.unpack . parseString) samples env pm MacroDescriptor { _md_source = "\"(?:[^\"\\]+|\\\\[\\\"])*\"" , _md_samples = map fst samples@@ -294,7 +306,7 @@ -> PreludeMacro -> Maybe MacroDescriptor string_simple_macro rty env pm =- Just $ run_tests rty parseSimpleString samples env pm+ Just $ run_tests rty (fmap T.unpack . parseSimpleString) samples env pm MacroDescriptor { _md_source = "\"[^\"[:cntrl:]]*\"" , _md_samples = map fst samples@@ -404,6 +416,53 @@ , "_1'" ] +id__macro :: RegexType+ -> MacroEnv+ -> PreludeMacro+ -> Maybe MacroDescriptor+id__macro rty env pm =+ Just $ run_tests rty Just samples env pm+ MacroDescriptor+ { _md_source = "_*[a-zA-Z][a-zA-Z0-9_'-]*"+ , _md_samples = map fst samples+ , _md_counter_samples = counter_samples+ , _md_test_results = []+ , _md_parser = Nothing+ , _md_description = "an identifier with -s"+ }+ where+ samples :: [(String,String)]+ samples =+ [ f "a"+ , f "A"+ , f "A1"+ , f "a_"+ , f "a1_B2"+ , f "_abc"+ , f "__abc"+ , f "a'"+ , f "_a'"+ , f "a'b"+ , f "a-"+ , f "a1-B2"+ , f "a1-B2-"+ ]+ where+ f s = (s,s)++ counter_samples =+ [ ""+ , "1"+ , "_"+ , "__"+ , "__1"+ , "1a"+ , "'"+ , "'a"+ , "_'"+ , "_1'"+ ]+ date_macro :: RegexType -> MacroEnv -> PreludeMacro -> Maybe MacroDescriptor date_macro rty env pm = Just $ run_tests rty parseDate samples env pm@@ -636,7 +695,7 @@ Just $ run_tests rty parseShortMonth samples env pm MacroDescriptor { _md_source = bracketedRegexSource $- intercalate "|" $ elems shortMonthArray+ intercalate "|" $ map T.unpack $ elems shortMonthArray , _md_samples = map fst samples , _md_counter_samples = counter_samples , _md_test_results = []@@ -742,14 +801,14 @@ re_tdfa = bracketedRegexSource $ intercalate "|" $- [ kw+ [ T.unpack kw | (kw0,kws) <- map severityKeywords [minBound..maxBound] , kw <- kw0:kws ] re_pcre = bracketedRegexSource $ intercalate "|" $- [ kw+ [ T.unpack kw | (kw0,kws) <- map severityKeywords $ filter (/=Err) [minBound..maxBound] , kw <- kw0:kws
Text/RE/PCRE.hs view
@@ -1,4 +1,8 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif {-# OPTIONS_GHC -fno-warn-dodgy-exports #-} module Text.RE.PCRE
Text/RE/PCRE/ByteString.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.PCRE.ByteString ( (*=~)
Text/RE/PCRE/ByteString/Lazy.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.PCRE.ByteString.Lazy ( (*=~)
Text/RE/PCRE/RE.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-}@@ -5,6 +6,10 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif {-# OPTIONS_GHC -fno-warn-orphans #-} module Text.RE.PCRE.RE@@ -39,11 +44,11 @@ , compileRegex ) where -import Control.Applicative import Data.Bits import Data.Functor.Identity import Language.Haskell.TH import Language.Haskell.TH.Quote+import Prelude.Compat import Text.RE import Text.RE.Internal.NamedCaptures import Text.RE.Internal.PreludeMacros
Text/RE/PCRE/Sequence.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.PCRE.Sequence ( (*=~)
Text/RE/PCRE/String.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.PCRE.String ( (*=~)
Text/RE/Parsers.hs view
@@ -1,3 +1,6 @@+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}+{-# LANGUAGE OverloadedStrings #-}+ module Text.RE.Parsers ( parseInteger , parseHex@@ -23,7 +26,9 @@ import Data.Array import qualified Data.HashMap.Strict as HM import Data.Maybe+import qualified Data.Text as T import Data.Time+import qualified Data.Time.Locale.Compat as LC import Data.Word import Text.Printf import Text.Read@@ -39,17 +44,11 @@ parseDouble :: Replace a => a -> Maybe Double parseDouble = readMaybe . unpack_ -parseString :: Replace a => a -> Maybe String+parseString :: Replace a => a -> Maybe T.Text parseString = readMaybe . unpack_ -parseSimpleString :: Replace a => a -> Maybe String-parseSimpleString = topntail . unpack_- where- topntail ('"':t) = topntail' $ reverse t- topntail _ = Nothing-- topntail' ('"':rt) = Just $ reverse rt- topntail' _ = Nothing+parseSimpleString :: Replace a => a -> Maybe T.Text+parseSimpleString = Just . T.dropEnd 1 . T.drop 1 . textify date_templates, time_templates, timezone_templates, date_time_8601_templates, date_time_templates :: [String]@@ -98,16 +97,16 @@ parse_time tpls = prs . unpack_ where prs s = listToMaybe $ catMaybes- [ parseTimeM False defaultTimeLocale fmt s+ [ parseTime LC.defaultTimeLocale fmt s | fmt<-tpls ] short_month_hm :: HM.HashMap String Int-short_month_hm = HM.fromList [ (shortMonthArray!i,i) | i<-[1..12] ]+short_month_hm = HM.fromList [ (T.unpack $ shortMonthArray!i,i) | i<-[1..12] ] -shortMonthArray :: Array Int String+shortMonthArray :: Array Int T.Text shortMonthArray = listArray (1,12) $- words "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"+ T.words "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" type IPV4Address = (Word8,Word8,Word8,Word8) @@ -138,9 +137,9 @@ deriving (Bounded,Enum,Ord,Eq,Show) parseSeverity :: Replace a => a -> Maybe Severity-parseSeverity = flip HM.lookup severity_hm . unpack_+parseSeverity = flip HM.lookup severity_hm . textify -severity_hm :: HM.HashMap String Severity+severity_hm :: HM.HashMap T.Text Severity severity_hm = HM.fromList [ (kw,pri) | pri<-[minBound..maxBound]@@ -148,7 +147,7 @@ , kw <- kw0:kws ] -severityKeywords :: Severity -> (String,[String])+severityKeywords :: Severity -> (T.Text,[T.Text]) severityKeywords pri = case pri of Emerg -> (,) "emerg" ["panic"] Alert -> (,) "alert" []
Text/RE/Replace.lhs view
@@ -1,4 +1,5 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}@@ -41,6 +42,7 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Data.Text.Lazy as LT+import Prelude.Compat import Text.Heredoc import Text.RE.Capture import Text.RE.CaptureID@@ -461,7 +463,7 @@ Just $ replaceAllCaptures' TOP phi $ tpl $=~ [here|\$(\$|[0-9]+|\{([^{}]+)\})|] where- phi t_mtch _ _ = case captureMaybe c2 t_mtch of+ phi t_mtch _ _ = case t_mtch !$? c2 of Just cap -> this $ CID_name $ CaptureName txt where txt = T.pack $ unpack $ capturedText cap@@ -472,7 +474,7 @@ s = unpack t t = capturedText $ capture c1 t_mtch - this cid = capturedText <$> captureMaybe cid mtch+ this cid = capturedText <$> mtch !$? cid c1 = CID_ordinal $ CaptureOrdinal 1 c2 = CID_ordinal $ CaptureOrdinal 2
Text/RE/TDFA.hs view
@@ -1,4 +1,8 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif {-# OPTIONS_GHC -fno-warn-dodgy-exports #-} module Text.RE.TDFA
Text/RE/TDFA/ByteString.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.TDFA.ByteString ( (*=~)
Text/RE/TDFA/ByteString/Lazy.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.TDFA.ByteString.Lazy ( (*=~)
Text/RE/TDFA/RE.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-}@@ -5,6 +6,10 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif {-# OPTIONS_GHC -fno-warn-orphans #-} module Text.RE.TDFA.RE@@ -39,10 +44,10 @@ , compileRegex ) where -import Control.Applicative import Data.Functor.Identity import Language.Haskell.TH import Language.Haskell.TH.Quote+import Prelude.Compat import Text.RE import Text.RE.Internal.NamedCaptures import Text.RE.Internal.PreludeMacros
Text/RE/TDFA/Sequence.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.TDFA.Sequence ( (*=~)
Text/RE/TDFA/String.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.TDFA.String ( (*=~)
Text/RE/TDFA/Text.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.TDFA.Text ( (*=~)
Text/RE/TDFA/Text/Lazy.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.TDFA.Text.Lazy ( (*=~)
Text/RE/TestBench.lhs view
@@ -1,7 +1,12 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.TestBench ( MacroID(..)@@ -23,17 +28,17 @@ , formatMacroSources , formatMacroSource , testMacroDescriptors--- , regexSource ) where import Data.Array-import Control.Applicative+import Data.Char import qualified Data.HashMap.Lazy as HML-import Data.List+import qualified Data.List as L import Data.Maybe import Data.Ord import Data.String import Text.Printf+import Prelude.Compat import Text.RE.Capture import Text.RE.Options import Text.RE.Replace@@ -200,8 +205,10 @@ writeFile fp_t $ formatMacroTable rty m_env writeFile fp_s $ formatMacroSources rty ExclCaptures m_env where- fp_t = "tables/" ++ lab ++ "-" ++ show rty ++ ".md"- fp_s = "tables/" ++ lab ++ "-" ++ show rty ++ ".txt"+ fp_t = "docs/" ++ rty_s ++ "-" ++ lab ++ ".txt"+ fp_s = "docs/" ++ rty_s ++ "-" ++ lab ++ "-src.txt"++ rty_s = map toLower $ show rty \end{code} \begin{code}@@ -209,7 +216,7 @@ formatMacroTable rty env = unlines $ format_table macro_table_hdr [ macro_table_row rty mid md- | (mid,md) <- sortBy (comparing fst) $ HML.toList env+ | (mid,md) <- L.sortBy (comparing fst) $ HML.toList env ] \end{code} @@ -240,7 +247,7 @@ -> String formatMacroSources rty wc env = unlines $ [ printf "%-20s : %s" (_MacroID mid) $ formatMacroSource rty wc env mid- | mid <- sort $ HML.keys env+ | mid <- L.sort $ HML.keys env ] \end{code} @@ -363,7 +370,7 @@ format_row :: Array Col Int -> TableRow -> [String] format_row cw_arr row =- [ ("|"++) $ intercalate "|"+ [ ("|"++) $ L.intercalate "|" [ field cw_arr row c i | c<-[minBound..maxBound] ] | i <- [0..depth-1] ]
Text/RE/Tools/Grep.lhs view
@@ -1,16 +1,19 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-} module Text.RE.Tools.Grep ( grep , grepLines , GrepScript , grepScript+ , linesMatched ) where -import Control.Applicative import qualified Data.ByteString.Lazy.Char8 as LBS+import Prelude.Compat import Text.Printf import Text.RE.Capture import Text.RE.IsRegex@@ -47,12 +50,12 @@ Just t -> t : loop (succ i) lns report :: [Line] -> String-report = unlines . map fmt . lines_matched+report = unlines . map fmt . linesMatched where fmt Line{..} = printf "%05d %s" (getLineNo _ln_no) $ LBS.unpack $ matchesSource _ln_matches -lines_matched :: [Line] -> [Line]-lines_matched = filter $ anyMatches . _ln_matches+linesMatched :: [Line] -> [Line]+linesMatched = filter $ anyMatches . _ln_matches \end{code}
Text/RE/Tools/Lex.lhs view
@@ -1,8 +1,12 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-}+ module Text.RE.Tools.Lex where -import Control.Applicative-import Text.RE+import Prelude.Compat+import Text.RE.Capture+import Text.RE.IsRegex+import Text.RE.Replace alex :: IsRegex re s => [(re,Match s->Maybe t)] -> t -> s -> [t]
Text/RE/Tools/Sed.lhs view
@@ -1,6 +1,11 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module Text.RE.Tools.Sed ( SedScript@@ -8,8 +13,8 @@ , sed' ) where -import Control.Applicative import qualified Data.ByteString.Lazy.Char8 as LBS+import Prelude.Compat import Text.RE.Edit import Text.RE.LineNo import Text.RE.IsRegex
changelog view
@@ -1,5 +1,17 @@ -*-change-log-*- +0.1.0.0 Chris Dornan <chris.dornan@irisconnect.co.uk> 2017-02-17+ * Cabal file generated from a DRY template+ * Library dependencies minimised, test depndencies moved into+ examples/re-tests+ * A proper static website generated by 're-prep all'+ * README/sidebar Badges are a static record of current release+ with links to a live build-status reporting on HEAD+ * Added !$, !$?, !$$ and !$$? alternatives for looking up captures+ in a Match+ * Text.RE.Parsers now generate Text where they were generating String+ * %nat, %int, %frac and %hex get their new names+ 0.0.0.2 Chris Dornan <chris.dornan@irisconnect.co.uk> 2017-01-30 * Fix for Windows * Remove hsyslog dependency
examples/TestKit.lhs view
@@ -1,22 +1,104 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif module TestKit- ( Test+ ( Vrn+ , bumpVersion+ , substVersion+ , substVersion_+ , Test , runTests , checkThis , test_pp+ , cmp ) where +import Control.Applicative import Control.Exception+import qualified Control.Monad as M+import Data.Maybe import qualified Data.Text as T+import qualified Data.ByteString.Lazy.Char8 as LBS+import Prelude.Compat import qualified Shelly as SH import System.Directory import System.Environment import System.Exit import System.IO+import Text.Printf+import Text.RE.TDFA \end{code}+++Vrn and friends+---------------++\begin{code}+data Vrn = Vrn { _vrn_a, _vrn_b, _vrn_c, _vrn_d :: Int }+ deriving (Show,Eq,Ord)++-- | register a new version of the package+bumpVersion :: String -> IO ()+bumpVersion vrn_s = do+ vrn0 <- read_current_version+ rex' <- compileRegex () $ printf "- \\[[xX]\\].*%d\\.%d\\.%d\\.%d" _vrn_a _vrn_b _vrn_c _vrn_d+ nada <- null . linesMatched <$> grepLines rex' "lib/md/roadmap-incl.md"+ M.when nada $+ error $ vrn_s ++ ": not ticked off in the roadmap"+ rex <- compileRegex () $ printf "%d\\.%d\\.%d\\.%d" _vrn_a _vrn_b _vrn_c _vrn_d+ nope <- null . linesMatched <$> grepLines rex "changelog"+ M.when nope $+ error $ vrn_s ++ ": not in the changelog"+ case vrn > vrn0 of+ True -> do+ write_current_version vrn+ substVersion "lib/hackage-template.svg" "docs/badges/hackage.svg"+ False -> error $+ printf "version not later ~(%s > %s)" vrn_s $ present_vrn vrn0+ where+ vrn@Vrn{..} = parse_vrn vrn_s++substVersion :: FilePath -> FilePath -> IO ()+substVersion in_f out_f =+ LBS.readFile in_f >>= substVersion_ >>= LBS.writeFile out_f++substVersion_ :: (IsRegex RE a,Replace a) => a -> IO a+substVersion_ txt =+ flip replaceAll ms . pack_ . present_vrn <$> read_current_version+ where+ ms = txt *=~ [re|<<\$version\$>>|]++read_current_version :: IO Vrn+read_current_version = parse_vrn <$> readFile "lib/version.txt"++write_current_version :: Vrn -> IO ()+write_current_version = writeFile "lib/version.txt" . present_vrn++present_vrn :: Vrn -> String+present_vrn Vrn{..} = printf "%d.%d.%d.%d" _vrn_a _vrn_b _vrn_c _vrn_d++parse_vrn :: String -> Vrn+parse_vrn vrn_s = case matched m of+ True -> Vrn (p [cp|a|]) (p [cp|b|]) (p [cp|c|]) (p [cp|d|])+ False -> error $ "not a valid version: " ++ vrn_s+ where+ p c = fromMaybe oops $ parseInteger $ m !$$ c+ m = vrn_s ?=~ [re|^${a}(@{%nat})\.${b}(@{%nat})\.${c}(@{%nat})\.${d}(@{%nat})$|]++ oops = error "parse_vrn"+\end{code}+++Test and friends+---------------- \begin{code} data Test =
+ examples/re-gen-cabals.lhs view
@@ -0,0 +1,191 @@+\begin{code}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}++module Main (main) where++import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Char+import Data.IORef+import qualified Data.List as L+import qualified Data.Map as Map+import Data.Maybe+import Data.Monoid+import Prelude.Compat+import System.Directory+import System.Environment+import System.Exit+import System.IO+import TestKit+import Text.Printf+import Text.RE.TDFA.ByteString.Lazy+++main :: IO ()+main = do+ (pn,as) <- (,) <$> getProgName <*> getArgs+ case as of+ [] -> test+ ["test"] -> test+ ["gen"] -> gen "lib/cabal-masters/regex.cabal" "regex.cabal"+ _ -> do+ hPutStrLn stderr $ "usage: " ++ pn ++ " [test|gen]"+ exitWith $ ExitFailure 1++test :: IO ()+test = do+ createDirectoryIfMissing False "tmp"+ gen "lib/cabal-masters/regex.cabal" "tmp/regex.cabal"+ ok <- cmp "tmp/regex.cabal" "regex.cabal"+ case ok of+ True -> return ()+ False -> exitWith $ ExitFailure 1++gen :: FilePath -> FilePath -> IO ()+gen in_f out_f = do+ ctx <- setup+ substVersion in_f "tmp/regex-vrn.cabal"+ sed (gc_script ctx) "tmp/regex-vrn.cabal" out_f++data Ctx =+ Ctx+ { _ctx_package_constraints :: IORef (Map.Map LBS.ByteString LBS.ByteString)+ , _ctx_test_exe :: IORef (Maybe TestExe)+ }++data TestExe =+ TestExe+ { _te_test :: Bool+ , _te_exe :: Bool+ , _te_name :: LBS.ByteString+ , _te_text :: LBS.ByteString+ }+ deriving (Show)++setup :: IO Ctx+setup = Ctx <$> (newIORef Map.empty) <*> (newIORef Nothing)++gc_script :: Ctx -> SedScript RE+gc_script ctx = Select+ [ (,) [re|^%- +${pkg}(@{%id-}) +${cond}(.*)$|] $ EDIT_gen $ cond_gen ctx+ , (,) [re|^%build-depends +${list}(@{%id-}( +@{%id-})+)$|] $ EDIT_gen $ build_depends_gen ctx+ , (,) [re|^%test +${i}(@{%id-})$|] $ EDIT_gen $ test_exe_gen True False ctx+ , (,) [re|^%exe +${i}(@{%id-})$|] $ EDIT_gen $ test_exe_gen False True ctx+ , (,) [re|^%test-exe +${i}(@{%id-})$|] $ EDIT_gen $ test_exe_gen True True ctx+ , (,) [re|^.*$|] $ EDIT_gen $ default_gen ctx+ ]++cond_gen, build_depends_gen,+ default_gen :: Ctx+ -> LineNo+ -> Matches LBS.ByteString+ -> IO (LineEdit LBS.ByteString)++cond_gen Ctx{..} _ mtchs = do+ modifyIORef _ctx_package_constraints $ Map.insert pkg cond+ return Delete+ where+ pkg = captureText [cp|pkg|] mtch+ cond = captureText [cp|cond|] mtch++ mtch = allMatches mtchs !! 0++build_depends_gen ctx@Ctx{..} _ mtchs = do+ mp <- readIORef _ctx_package_constraints+ put ctx $ mk_build_depends mp lst+ where+ lst = LBS.words $ captureText [cp|list|] mtch+ mtch = allMatches mtchs !! 0++default_gen ctx@Ctx{..} _ mtchs = do+ mb <- readIORef _ctx_test_exe+ case mb of+ Nothing -> return $ ReplaceWith ln+ Just te -> case isSpace $ LBS.head $ ln<>"\n" of+ True -> put ctx ln+ False -> adjust_le (<>ln) <$> close_test_exe ctx te+ where+ ln = matchSource mtch+ mtch = allMatches mtchs !! 0++test_exe_gen :: Bool+ -> Bool+ -> Ctx+ -> LineNo+ -> Matches LBS.ByteString+ -> IO (LineEdit LBS.ByteString)+test_exe_gen is_t is_e ctx _ mtchs = do+ mb <- readIORef (_ctx_test_exe ctx)+ le <- maybe (return Delete) (close_test_exe ctx) mb+ writeIORef (_ctx_test_exe ctx) $ Just $+ TestExe+ { _te_test = is_t+ , _te_exe = is_e+ , _te_name = i+ , _te_text = ""+ }+ return le+ where+ i = captureText [cp|i|] mtch++ mtch = allMatches mtchs !! 0++close_test_exe :: Ctx -> TestExe -> IO (LineEdit LBS.ByteString)+close_test_exe ctx@Ctx{..} te = do+ writeIORef _ctx_test_exe Nothing+ put ctx $ mconcat $ concat $+ [ [ mk_test_exe False te "Executable" | _te_exe te ]+ , [ mk_test_exe True te "Test-Suite" | _te_test te ]+ ]++put :: Ctx -> LBS.ByteString -> IO (LineEdit LBS.ByteString)+put Ctx{..} lbs = do+ mb <- readIORef _ctx_test_exe+ case mb of+ Nothing -> return $ ReplaceWith lbs+ Just te -> do+ writeIORef _ctx_test_exe $ Just te { _te_text = _te_text te <> lbs <> "\n" }+ return Delete++mk_test_exe :: Bool -> TestExe -> LBS.ByteString -> LBS.ByteString+mk_test_exe is_t te te_lbs_kw = (<>_te_text te) $ LBS.unlines $ concat+ [ [ LBS.pack $ printf "%s %s" (LBS.unpack te_lbs_kw) nm ]+ , [ " type: exitcode-stdio-1.0" | is_t ]+ ]+ where+ nm = case is_t of+ True -> LBS.unpack $ _te_name te <> "-test"+ False -> LBS.unpack $ _te_name te++mk_build_depends :: Map.Map LBS.ByteString LBS.ByteString+ -> [LBS.ByteString]+ -> LBS.ByteString+mk_build_depends mp pks = LBS.unlines $+ (:) " Build-depends:" $+ map fmt $ zip (True : repeat False) $+ L.sortBy comp pks+ where+ fmt (isf,pk) = LBS.pack $+ printf " %c %-20s %s"+ (if isf then ' ' else ',')+ (LBS.unpack pk)+ (maybe "" LBS.unpack $ Map.lookup pk mp)++ comp x y = case (x=="regex",y=="regex") of+ (True ,True ) -> EQ+ (True ,False) -> LT+ (False,True ) -> GT+ (False,False) -> compare x y++adjust_le :: (LBS.ByteString->LBS.ByteString)+ -> LineEdit LBS.ByteString+ -> LineEdit LBS.ByteString+adjust_le f le = case le of+ NoEdit -> error "adjust_le: not enough context"+ ReplaceWith lbs -> ReplaceWith $ f lbs+ Delete -> ReplaceWith $ f ""+\end{code}
examples/re-gen-modules.lhs view
@@ -1,21 +1,22 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} module Main (main) where -import Control.Applicative import Control.Exception import qualified Data.ByteString.Lazy.Char8 as LBS import qualified Data.Text as T+import Prelude.Compat import qualified Shelly as SH import System.Directory import System.Environment import System.Exit import System.IO import Text.RE.TDFA.ByteString.Lazy-import Text.RE.Tools.Sed main :: IO ()
examples/re-include.lhs view
@@ -1,4 +1,5 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TemplateHaskell #-}@@ -12,12 +13,12 @@ import Control.Applicative import qualified Data.ByteString.Lazy.Char8 as LBS import Data.Maybe+import qualified Data.Text as T+import Prelude.Compat import System.Environment import TestKit import Text.RE.Edit import Text.RE.TDFA.ByteString.Lazy-import Text.RE.Tools.Grep-import Text.RE.Tools.Sed \end{code} \begin{code}@@ -66,7 +67,7 @@ fp = prs_s $ captureText [cp|file|] mtch re_s = prs_s $ captureText [cp|rex|] mtch - prs_s = fromMaybe (error "includeDoc") . parseString+ prs_s = maybe (error "includeDoc") T.unpack . parseString \end{code}
examples/re-nginx-log-processor.lhs view
@@ -1,4 +1,5 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TemplateHaskell #-}@@ -22,6 +23,7 @@ import Data.String import qualified Data.Text as T import Data.Time+import Prelude.Compat import qualified Shelly as SH import System.Directory import System.Environment@@ -31,8 +33,7 @@ import Text.RE.Parsers import Text.RE.TestBench import Text.RE.PCRE.ByteString.Lazy-import qualified Text.RE.PCRE.String as S-import Text.RE.Tools.Sed+import qualified Text.RE.PCRE.String as S import Text.Printf \end{code} @@ -201,7 +202,7 @@ where (a,b,c,d) = _event_address - svrty_kw = fst . severityKeywords+ svrty_kw = T.unpack . fst . severityKeywords class IsEvent a where mkEvent :: LineNo -> Source -> a -> Event@@ -216,12 +217,12 @@ , _event_address = _a_remote_addr , _event_details = LBS.pack $ printf "%s %d %d %s %s %s"- _a_request- _a_status- _a_body_bytes- _a_http_referrer- _a_http_user_agent- _a_other+ (T.unpack _a_request )+ _a_status+ _a_body_bytes+ (T.unpack _a_http_referrer )+ (T.unpack _a_http_user_agent)+ (T.unpack _a_other ) } instance IsEvent Error where@@ -318,7 +319,7 @@ pid_tid_macro env mid = runTests regexType parse_pid_tid samples env mid MacroDescriptor- { _md_source = "(?:@{%natural})#(?:@{%natural}):"+ { _md_source = "(?:@{%nat})#(?:@{%nat}):" , _md_samples = map fst samples , _md_counter_samples = counter_samples , _md_test_results = []@@ -440,15 +441,15 @@ data Access = Access- { _a_remote_addr :: IPV4Address- , _a_remote_user :: User- , _a_time_local :: UTCTime- , _a_request :: String- , _a_status :: Int- , _a_body_bytes :: Int- , _a_http_referrer :: String- , _a_http_user_agent :: String- , _a_other :: String+ { _a_remote_addr :: !IPV4Address+ , _a_remote_user :: !User+ , _a_time_local :: !UTCTime+ , _a_request :: !T.Text+ , _a_status :: !Int+ , _a_body_bytes :: !Int+ , _a_http_referrer :: !T.Text+ , _a_http_user_agent :: !T.Text+ , _a_other :: !T.Text } deriving (Eq,Show) \end{code}@@ -461,8 +462,8 @@ , "(@{user})" , "\\[(@{%datetime.clf})\\]" , "(@{%string.simple})"- , "(@{%natural})"- , "(@{%natural})"+ , "(@{%nat})"+ , "(@{%nat})" , "(@{%string.simple})" , "(@{%string.simple})" , "(@{%string.simple})"@@ -563,7 +564,7 @@ -- parse_pid_tid :: Replace a => a -> Maybe (Int,Int)-parse_pid_tid x = case allMatches $ unpack_ x S.*=~ [re|@{%natural}|] of+parse_pid_tid x = case allMatches $ unpack_ x S.*=~ [re|@{%nat}|] of [cs,cs'] -> (,) <$> p cs <*> p cs' _ -> Nothing where
− examples/re-pp.lhs
@@ -1,459 +0,0 @@-\begin{code}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}--module Main- ( main- ) where--import Control.Applicative-import Control.Monad-import qualified Data.ByteString.Lazy.Char8 as LBS-import Data.IORef-import Data.Maybe-import Data.Monoid-import qualified Data.Text as T-import qualified Shelly as SH-import System.Directory-import System.Environment-import TestKit-import Text.Printf-import Text.RE.Edit-import Text.RE.TDFA.ByteString.Lazy-import Text.RE.TDFA.Text as T-import Text.RE.Tools.Grep-import Text.RE.Tools.Sed-\end{code}--\begin{code}-main :: IO ()-main = do- as <- getArgs- case as of- [] -> test- ["test"] -> test- ["doc",fn,fn'] | is_file fn -> doc fn fn'- ["gen",fn,fn'] | is_file fn -> gen fn fn'- ["all"] -> gen_all- _ -> usage- where- is_file = not . (== "--") . take 2-- doc fn fn' = docMode >>= \dm -> loop dm fn fn'- gen fn fn' = genMode >>= \gm -> loop gm fn fn'-- usage = do- pnm <- getProgName- let prg = ((pnm++" ")++)- putStr $ unlines- [ "usage:"- , " "++prg "--help"- , " "++prg "[test]"- , " "++prg "all"- , " "++prg "doc (-|<in-file>) (-|<out-file>)"- , " "++prg "gen (-|<in-file>) (-|<out-file>)"- ]-\end{code}---The Sed Script-----------------\begin{code}--- | the MODE determines whether we are generating documentation--- or a Haskell testsuite and includes any IO-accessible state--- needed by the relevant processor-data MODE- = Doc DocState -- ^ document-generation state- | Gen GenState -- ^ adjusting-the-program-for-testing state-\end{code}--The `DocState` is initialised to `Outside` and flips though the different-states as it traverses a code block, so that we can wrap code-blocks in special <div class="replcodeblock"> blocks when their-first line indicates that it contains a REPL calculation, which the-style sheet can pick up and present accordingly.--\begin{code}-data DocMode- = Outside -- not inside a begin{code} ... \end{code} block- | Beginning -- at the start of a begin{code} ... \end{code} block- | InsideRepl -- inside a REPL code block- | InsideProg -- inside a non-REPL code block- deriving (Eq,Show)--type DocState = IORef DocMode--genMode :: IO MODE-genMode = Gen <$> newIORef []-\end{code}--\begin{code}--- | the state is the accumulated test function identifiers for--- generating the list of them gets added to the end of the programme-type GenState = IORef [String]--docMode :: IO MODE-docMode = Doc <$> newIORef Outside-\end{code}---\begin{code}-loop :: MODE -> FilePath -> FilePath -> IO ()-loop mode =- sed $ Select- [ (,) [re|^%include ${file}(@{%string}) ${rex}(@{%string})$|] $ EDIT_fun TOP $ include mode- , (,) [re|^%main ${arg}(top|bottom)$|] $ EDIT_gen $ main_ mode- , (,) [re|^\\begin\{code\}$|] $ EDIT_gen $ begin mode- , (,) [re|^${fn}(evalme@{%id}) = checkThis ${arg}(@{%string}).*$|] $ EDIT_fun TOP $ evalme mode- , (,) [re|^\\end\{code\}$|] $ EDIT_fun TOP $ end mode- , (,) [re|^.*$|] $ EDIT_fun TOP $ other mode- ]-\end{code}--\begin{code}-include, evalme, end,- other :: MODE- -> LineNo- -> Match LBS.ByteString- -> Location- -> Capture LBS.ByteString- -> IO (Maybe LBS.ByteString)--main_,- begin :: MODE- -> LineNo- -> Matches LBS.ByteString- -> IO (LineEdit LBS.ByteString)--include (Doc _ ) = includeDoc-include (Gen _ ) = passthru--main_ (Doc _ ) = mainDoc-main_ (Gen gs) = mainGen gs--begin (Doc ds) = beginDoc ds-begin (Gen _ ) = passthru_g--evalme (Doc ds) = evalmeDoc ds-evalme (Gen gs) = evalmeGen gs--end (Doc ds) = endDoc ds-end (Gen _ ) = passthru--other (Doc ds) = otherDoc ds-other (Gen _ ) = passthru--passthru :: LineNo- -> Match LBS.ByteString- -> Location- -> Capture LBS.ByteString- -> IO (Maybe LBS.ByteString)-passthru _ _ _ _ = return Nothing--passthru_g :: LineNo- -> Matches LBS.ByteString- -> IO (LineEdit LBS.ByteString)-passthru_g _ _ = return NoEdit-\end{code}---Script to Generate All Tutorial Tests and Docs-------------------------------------------------\begin{code}-gen_all :: IO ()-gen_all = do- -- prepare HTML docs for the (literate) tools- pd "re-gen-modules"- pd "re-include"- pd "re-nginx-log-processor"- pd "re-pp"- pd "re-tests"- pd "TestKit"- pd "RE/Capture"- pd "RE/Edit"- pd "RE/IsRegex"- pd "RE/Options"- pd "RE/Replace"- pd "RE/TestBench"- pd "RE/Tools/Grep"- pd "RE/Tools/Lex"- pd "RE/Tools/Sed"- pd "RE/Internal/NamedCaptures"- -- render the tutorial in HTML- dm <- docMode- loop dm "examples/re-tutorial-master.lhs" "tmp/re-tutorial.lhs"- createDirectoryIfMissing False "tmp"- pandoc'- "re-tutorial.lhs"- "examples/re-tutorial.lhs"- "tmp/re-tutorial.lhs"- "docs/re-tutorial.html"- -- generate the tutorial-based tests- gm <- genMode- loop gm "examples/re-tutorial-master.lhs" "examples/re-tutorial.lhs"- putStrLn ">> examples/re-tutorial.lhs"- where- pd fnm = case captureTextMaybe [cp|mnm|] $ fnm T.?=~ [re|^RE/(Tools/|Internal/)?${mnm}(@{%id})|] of- Just mnm -> pandoc fnm ("Text/"<>fnm<>".lhs") ("docs/"<>mnm<>".html")- Nothing -> pandoc fnm ( "examples/"<>fnm<>".lhs") ("docs/"<>fnm<>".html")-\end{code}---Generating the Tutorial--------------------------\begin{code}-includeDoc :: LineNo- -> Match LBS.ByteString- -> Location- -> Capture LBS.ByteString- -> IO (Maybe LBS.ByteString)-includeDoc _ mtch _ _ = fmap Just $- extract fp =<< compileRegex () re_s- where- fp = prs_s $ captureText [cp|file|] mtch- re_s = prs_s $ captureText [cp|rex|] mtch-- prs_s = fromMaybe (error "includeDoc") . parseString-\end{code}--\begin{code}-mainDoc :: LineNo- -> Matches LBS.ByteString- -> IO (LineEdit LBS.ByteString)-mainDoc _ _ = return Delete-\end{code}--\begin{code}-beginDoc :: DocState- -> LineNo- -> Matches LBS.ByteString- -> IO (LineEdit LBS.ByteString)-beginDoc ds _ _ = writeIORef ds Beginning >> return Delete-\end{code}--\begin{code}-evalmeDoc, endDoc, otherDoc :: DocState- -> LineNo- -> Match LBS.ByteString- -> Location- -> Capture LBS.ByteString- -> IO (Maybe LBS.ByteString)--evalmeDoc ds lno _ _ _ = do- dm <- readIORef ds- when (dm/=Beginning) $- bad_state "evalme" lno dm- writeIORef ds InsideRepl- return $ Just $ "<div class=\"replcodeblock\">\n"<>begin_code--endDoc ds lno _ _ _ = do- dm <- readIORef ds- case dm of- Outside -> bad_state "end" lno dm- Beginning -> return $ Just $ begin_code <> "\n" <> end_code- InsideRepl -> return $ Just $ end_code <> "\n</div>"- InsideProg -> return Nothing--otherDoc ds _ mtch _ _ = do- dm <- readIORef ds- case dm of- Beginning -> do- writeIORef ds InsideProg- return $ Just $ begin_code <> "\n" <> matchSource mtch- _ -> return Nothing--bad_state :: String -> LineNo -> DocMode -> IO a-bad_state lab lno dm = error $- printf "Bad document syntax: %s: %d: %s" lab (getLineNo lno) $ show dm-\end{code}---Generating the Tests-----------------------\begin{code}-evalmeGen :: GenState- -> LineNo- -> Match LBS.ByteString- -> Location- -> Capture LBS.ByteString- -> IO (Maybe LBS.ByteString)-evalmeGen gs _ mtch0 _ _ = Just <$>- replaceCapturesM replace_ ALL f mtch0- where- f mtch loc cap = case _loc_capture loc of- 2 -> do- modifyIORef gs (ide:)- return $ Just $ LBS.pack $ show ide- where- ide = LBS.unpack $ captureText [cp|fn|] mtch- _ -> return $ Just $ capturedText cap-\end{code}--How are we doing?--\begin{code}-mainGen :: GenState- -> LineNo- -> Matches LBS.ByteString- -> IO (LineEdit LBS.ByteString)-mainGen gs _ mtchs = case allMatches mtchs of- [mtch] ->- case captureText [cp|arg|] $ mtch of- "top" -> return $ ReplaceWith $ LBS.unlines $- [ begin_code- , "module Main(main) where"- , end_code- , ""- , "*********************************************************"- , "*"- , "* WARNING: this is generated from pp-tutorial-master.lhs "- , "*"- , "*********************************************************"- ]- "bottom" -> do- fns <- readIORef gs- return $ ReplaceWith $ LBS.unlines $- [ begin_code- , "main :: IO ()"- , "main = runTests"- ] ++ mk_list fns ++- [ end_code- ]- _ -> error "mainGen (b)"- _ -> error "mainGen (a)"-\end{code}--We cannot place these strings inline without confusing pandoc so we-use these definitions instead.--\begin{code}-begin_code, end_code :: LBS.ByteString-begin_code = "\\"<>"begin{code}"-end_code = "\\"<>"end{code}"-\end{code}----\begin{code}-mk_list :: [String] -> [LBS.ByteString]-mk_list [] = ["[]"]-mk_list (ide0:ides) = f "[" ide0 $ foldr (f ",") [" ]"] ides- where- f pfx ide t = (" "<>pfx<>" "<>LBS.pack ide) : t-\end{code}---Extracting a Literate Fragment from a Haskell Program Text-------------------------------------------------------------\begin{code}-extract :: FilePath -> RE -> IO LBS.ByteString-extract fp rex = extr . LBS.lines <$> LBS.readFile fp- where- extr lns =- case parse $ scan rex lns of- Nothing -> oops- Just (lno,n) -> LBS.unlines $ (hdr :) $ (take n $ drop i lns) ++ [ftr]- where- i = getZeroBasedLineNo lno-- oops = error $ concat- [ "failed to locate fragment matching "- , show $ reSource rex- , " in file "- , show fp- ]-- hdr = "<div class='includedcodeblock'>"- ftr = "</div>"-\end{code}--\begin{code}-parse :: [Token] -> Maybe (LineNo,Int)-parse [] = Nothing-parse (tk:tks) = case (tk,tks) of- (Bra b_ln,Hit:Ket k_ln:_) -> Just (b_ln,count_lines_incl b_ln k_ln)- _ -> parse tks-\end{code}--\begin{code}-count_lines_incl :: LineNo -> LineNo -> Int-count_lines_incl b_ln k_ln =- getZeroBasedLineNo k_ln + 1 - getZeroBasedLineNo b_ln-\end{code}--\begin{code}-data Token = Bra LineNo | Hit | Ket LineNo deriving (Show)-\end{code}--\begin{code}-scan :: RE -> [LBS.ByteString] -> [Token]-scan rex = grepScript- [ (,) [re|\\begin\{code\}|] $ \i -> chk $ Bra i- , (,) rex $ \_ -> chk Hit- , (,) [re|\\end\{code\}|] $ \i -> chk $ Ket i- ]- where- chk x mtchs = case anyMatches mtchs of- True -> Just x- False -> Nothing-\end{code}---pandoc---------\begin{code}-pandoc :: T.Text -> T.Text -> T.Text -> IO ()-pandoc title in_file = pandoc' title in_file in_file--pandoc' :: T.Text -> T.Text -> T.Text -> T.Text -> IO ()-pandoc' title repo_path in_file out_file = do- writeFile "tmp/bc.html" bc- fmap (const ()) $- SH.shelly $ SH.verbosely $- SH.run "pandoc"- [ "-f", "markdown+lhs+grid_tables"- , "-t", "html"- , "-s"- , "-B", "tmp/bc.html"- , "-c", "lib/styles.css"- , "-c", "lib/bs.css"- , "-o", out_file- , in_file- ]- where- bc = concat- [ "<ol class='breadcrumb'><li><a href='.' title='Home'>"- , "Home</a></li> > <a title='source file' href='"- , repo_url- , "'>"- , T.unpack title- , "</a></ol>"- ]-- repo_url = concat- [ "https://github.com/iconnect/regex/blob/master/"- , T.unpack repo_path- ]-\end{code}--testing----------\begin{code}-test :: IO ()-test = do- dm <- docMode- test_pp "pp-doc" (loop dm) "data/pp-test.lhs" "data/pp-result-doc.lhs"- gm <- genMode- test_pp "pp-gen" (loop gm) "data/pp-test.lhs" "data/pp-result-gen.lhs"- putStrLn "tests passed"-\end{code}
+ examples/re-prep.lhs view
@@ -0,0 +1,828 @@+\begin{code}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++module Main+ ( main+ ) where++import Control.Applicative+import qualified Control.Monad as M+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.IORef+import Data.Maybe+import Data.Monoid+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import Network.HTTP.Conduit+import Prelude.Compat+import qualified Shelly as SH+import System.Directory+import System.Environment+import TestKit+import Text.Heredoc+import Text.Printf+import Text.RE.Edit+import Text.RE.TDFA.ByteString.Lazy+import qualified Text.RE.TDFA.Text as TT+\end{code}++\begin{code}+main :: IO ()+main = do+ as <- getArgs+ case as of+ [] -> test+ ["test"] -> test+ ["doc",fn,fn'] | is_file fn -> doc fn fn'+ ["gen",fn,fn'] | is_file fn -> gen fn fn'+ ["badges"] -> badges+ ["bump-version",vrn] -> bumpVersion vrn+ ["pages"] -> pages+ ["all"] -> gen_all+ _ -> usage+ where+ is_file = not . (== "--") . take 2++ doc fn fn' = docMode >>= \dm -> loop dm fn fn'+ gen fn fn' = genMode >>= \gm -> loop gm fn fn'++ usage = do+ pnm <- getProgName+ let prg = ((" "++pnm++" ")++)+ putStr $ unlines+ [ "usage:"+ , prg "--help"+ , prg "[test]"+ , prg "badges"+ , prg "bump-version <version>"+ , prg "pages"+ , prg "all"+ , prg "doc (-|<in-file>) (-|<out-file>)"+ , prg "gen (-|<in-file>) (-|<out-file>)"+ ]+\end{code}+++The Sed Script+--------------++\begin{code}+-- | the MODE determines whether we are generating documentation+-- or a Haskell testsuite and includes any IO-accessible state+-- needed by the relevant processor+data MODE+ = Doc DocState -- ^ document-generation state+ | Gen GenState -- ^ adjusting-the-program-for-testing state+\end{code}++The `DocState` is initialised to `Outside` and flips though the different+states as it traverses a code block, so that we can wrap code+blocks in special <div class="replcodeblock"> blocks when their+first line indicates that it contains a REPL calculation, which the+style sheet can pick up and present accordingly.++\begin{code}+data DocMode+ = Outside -- not inside a begin{code} ... \end{code} block+ | Beginning -- at the start of a begin{code} ... \end{code} block+ | InsideRepl -- inside a REPL code block+ | InsideProg -- inside a non-REPL code block+ deriving (Eq,Show)++type DocState = IORef DocMode++genMode :: IO MODE+genMode = Gen <$> newIORef []+\end{code}++\begin{code}+-- | the state is the accumulated test function identifiers for+-- generating the list of them gets added to the end of the programme+type GenState = IORef [String]++docMode :: IO MODE+docMode = Doc <$> newIORef Outside+\end{code}+++\begin{code}+loop :: MODE -> FilePath -> FilePath -> IO ()+loop mode =+ sed $ Select+ [ (,) [re|^%include ${file}(@{%string}) ${rex}(@{%string})$|] $ EDIT_fun TOP $ inclde mode+ , (,) [re|^%main ${arg}(top|bottom)$|] $ EDIT_gen $ main_ mode+ , (,) [re|^\\begin\{code\}$|] $ EDIT_gen $ begin mode+ , (,) [re|^${fn}(evalme@{%id}) = checkThis ${arg}(@{%string}).*$|] $ EDIT_fun TOP $ evalme mode+ , (,) [re|^\\end\{code\}$|] $ EDIT_fun TOP $ end mode+ , (,) [re|^.*$|] $ EDIT_fun TOP $ other mode+ ]+\end{code}++\begin{code}+inclde, evalme, end,+ other :: MODE+ -> LineNo+ -> Match LBS.ByteString+ -> Location+ -> Capture LBS.ByteString+ -> IO (Maybe LBS.ByteString)++main_,+ begin :: MODE+ -> LineNo+ -> Matches LBS.ByteString+ -> IO (LineEdit LBS.ByteString)++inclde (Doc _ ) = includeDoc+inclde (Gen _ ) = passthru++main_ (Doc _ ) = mainDoc+main_ (Gen gs) = mainGen gs++begin (Doc ds) = beginDoc ds+begin (Gen _ ) = passthru_g++evalme (Doc ds) = evalmeDoc ds+evalme (Gen gs) = evalmeGen gs++end (Doc ds) = endDoc ds+end (Gen _ ) = passthru++other (Doc ds) = otherDoc ds+other (Gen _ ) = passthru++passthru :: LineNo+ -> Match LBS.ByteString+ -> Location+ -> Capture LBS.ByteString+ -> IO (Maybe LBS.ByteString)+passthru _ _ _ _ = return Nothing++passthru_g :: LineNo+ -> Matches LBS.ByteString+ -> IO (LineEdit LBS.ByteString)+passthru_g _ _ = return NoEdit+\end{code}+++Script to Generate the Whole Web Site+-------------------------------------++\begin{code}+gen_all :: IO ()+gen_all = do+ -- prepare HTML docs for the (literate) tools+ pd "re-gen-cabals"+ pd "re-gen-modules"+ pd "re-include"+ pd "re-nginx-log-processor"+ pd "re-prep"+ pd "re-tests"+ pd "TestKit"+ pd "RE/Capture"+ pd "RE/Edit"+ pd "RE/IsRegex"+ pd "RE/Options"+ pd "RE/Replace"+ pd "RE/TestBench"+ pd "RE/Tools/Grep"+ pd "RE/Tools/Lex"+ pd "RE/Tools/Sed"+ pd "RE/Internal/NamedCaptures"+ -- render the tutorial in HTML+ dm <- docMode+ loop dm "examples/re-tutorial-master.lhs" "tmp/re-tutorial.lhs"+ createDirectoryIfMissing False "tmp"+ pandoc_lhs'+ "re-tutorial.lhs"+ "examples/re-tutorial.lhs"+ "tmp/re-tutorial.lhs"+ "docs/re-tutorial.html"+ -- generate the tutorial-based tests+ gm <- genMode+ loop gm "examples/re-tutorial-master.lhs" "examples/re-tutorial.lhs"+ putStrLn ">> examples/re-tutorial.lhs"+ pages+ where+ pd fnm = case (mtch !$$? [cp|fdr|],mtch !$$? [cp|mnm|]) of+ (Nothing ,Just mnm) -> pandoc_lhs ("Text.RE." <>mnm) ("Text/" <>fnm<>".lhs") ("docs/"<>mnm<>".html")+ (Just fdr,Just mnm) -> pandoc_lhs ("Text.RE."<>fdr<>"."<>mnm) ("Text/" <>fnm<>".lhs") ("docs/"<>mnm<>".html")+ _ -> pandoc_lhs ("examples/"<>fnm<>".lhs" ) ("examples/"<>fnm<>".lhs") ("docs/"<>fnm<>".html")+ where+ mtch = fnm TT.?=~ [re|^RE/(${fdr}(Tools|Internal)/)?${mnm}(@{%id})|]+\end{code}+++Generating the Tutorial+-----------------------++\begin{code}+includeDoc :: LineNo+ -> Match LBS.ByteString+ -> Location+ -> Capture LBS.ByteString+ -> IO (Maybe LBS.ByteString)+includeDoc _ mtch _ _ = fmap Just $+ extract fp =<< compileRegex () re_s+ where+ fp = prs_s $ captureText [cp|file|] mtch+ re_s = prs_s $ captureText [cp|rex|] mtch++ prs_s = maybe (error "includeDoc") T.unpack . parseString+\end{code}++\begin{code}+mainDoc :: LineNo+ -> Matches LBS.ByteString+ -> IO (LineEdit LBS.ByteString)+mainDoc _ _ = return Delete+\end{code}++\begin{code}+beginDoc :: DocState+ -> LineNo+ -> Matches LBS.ByteString+ -> IO (LineEdit LBS.ByteString)+beginDoc ds _ _ = writeIORef ds Beginning >> return Delete+\end{code}++\begin{code}+evalmeDoc, endDoc, otherDoc :: DocState+ -> LineNo+ -> Match LBS.ByteString+ -> Location+ -> Capture LBS.ByteString+ -> IO (Maybe LBS.ByteString)++evalmeDoc ds lno _ _ _ = do+ dm <- readIORef ds+ M.when (dm/=Beginning) $+ bad_state "evalme" lno dm+ writeIORef ds InsideRepl+ return $ Just $ "<div class=\"replcodeblock\">\n"<>begin_code++endDoc ds lno _ _ _ = do+ dm <- readIORef ds+ case dm of+ Outside -> bad_state "end" lno dm+ Beginning -> return $ Just $ begin_code <> "\n" <> end_code+ InsideRepl -> return $ Just $ end_code <> "\n</div>"+ InsideProg -> return Nothing++otherDoc ds _ mtch _ _ = do+ dm <- readIORef ds+ case dm of+ Beginning -> do+ writeIORef ds InsideProg+ return $ Just $ begin_code <> "\n" <> matchSource mtch+ _ -> return Nothing++bad_state :: String -> LineNo -> DocMode -> IO a+bad_state lab lno dm = error $+ printf "Bad document syntax: %s: %d: %s" lab (getLineNo lno) $ show dm+\end{code}+++Generating the Tests+--------------------++\begin{code}+evalmeGen :: GenState+ -> LineNo+ -> Match LBS.ByteString+ -> Location+ -> Capture LBS.ByteString+ -> IO (Maybe LBS.ByteString)+evalmeGen gs _ mtch0 _ _ = Just <$>+ replaceCapturesM replace_ ALL f mtch0+ where+ f mtch loc cap = case _loc_capture loc of+ 2 -> do+ modifyIORef gs (ide:)+ return $ Just $ LBS.pack $ show ide+ where+ ide = LBS.unpack $ captureText [cp|fn|] mtch+ _ -> return $ Just $ capturedText cap+\end{code}++How are we doing?++\begin{code}+mainGen :: GenState+ -> LineNo+ -> Matches LBS.ByteString+ -> IO (LineEdit LBS.ByteString)+mainGen gs _ mtchs = case allMatches mtchs of+ [mtch] ->+ case captureText [cp|arg|] $ mtch of+ "top" -> return $ ReplaceWith $ LBS.unlines $+ [ begin_code+ , "module Main(main) where"+ , end_code+ , ""+ , "*********************************************************"+ , "*"+ , "* WARNING: this is generated from pp-tutorial-master.lhs "+ , "*"+ , "*********************************************************"+ ]+ "bottom" -> do+ fns <- readIORef gs+ return $ ReplaceWith $ LBS.unlines $+ [ begin_code+ , "main :: IO ()"+ , "main = runTests"+ ] ++ mk_list fns +++ [ end_code+ ]+ _ -> error "mainGen (b)"+ _ -> error "mainGen (a)"+\end{code}++We cannot place these strings inline without confusing pandoc so we+use these definitions instead.++\begin{code}+begin_code, end_code :: LBS.ByteString+begin_code = "\\"<>"begin{code}"+end_code = "\\"<>"end{code}"+\end{code}++++\begin{code}+mk_list :: [String] -> [LBS.ByteString]+mk_list [] = ["[]"]+mk_list (ide0:ides) = f "[" ide0 $ foldr (f ",") [" ]"] ides+ where+ f pfx ide t = (" "<>pfx<>" "<>LBS.pack ide) : t+\end{code}+++Extracting a Literate Fragment from a Haskell Program Text+----------------------------------------------------------++\begin{code}+extract :: FilePath -> RE -> IO LBS.ByteString+extract fp rex = extr . LBS.lines <$> LBS.readFile fp+ where+ extr lns =+ case parse $ scan rex lns of+ Nothing -> oops+ Just (lno,n) -> LBS.unlines $ (hdr :) $ (take n $ drop i lns) ++ [ftr]+ where+ i = getZeroBasedLineNo lno++ oops = error $ concat+ [ "failed to locate fragment matching "+ , show $ reSource rex+ , " in file "+ , show fp+ ]++ hdr = "<div class='includedcodeblock'>"+ ftr = "</div>"+\end{code}++\begin{code}+parse :: [Token] -> Maybe (LineNo,Int)+parse [] = Nothing+parse (tk:tks) = case (tk,tks) of+ (Bra b_ln,Hit:Ket k_ln:_) -> Just (b_ln,count_lines_incl b_ln k_ln)+ _ -> parse tks+\end{code}++\begin{code}+count_lines_incl :: LineNo -> LineNo -> Int+count_lines_incl b_ln k_ln =+ getZeroBasedLineNo k_ln + 1 - getZeroBasedLineNo b_ln+\end{code}++\begin{code}+data Token = Bra LineNo | Hit | Ket LineNo deriving (Show)+\end{code}++\begin{code}+scan :: RE -> [LBS.ByteString] -> [Token]+scan rex = grepScript+ [ (,) [re|\\begin\{code\}|] $ \i -> chk $ Bra i+ , (,) rex $ \_ -> chk Hit+ , (,) [re|\\end\{code\}|] $ \i -> chk $ Ket i+ ]+ where+ chk x mtchs = case anyMatches mtchs of+ True -> Just x+ False -> Nothing+\end{code}+++badges+------++\begin{code}+badges :: IO ()+badges = do+ mapM_ collect+ [ (,) "license" "https://img.shields.io/badge/license-BSD3-brightgreen.svg"+ , (,) "unix-build" "https://img.shields.io/travis/iconnect/regex.svg?label=Linux%2BmacOS"+ , (,) "windows-build" "https://img.shields.io/appveyor/ci/engineerirngirisconnectcouk/regex.svg?label=Windows"+ , (,) "coverage" "https://img.shields.io/coveralls/iconnect/regex.svg"+ , (,) "build-status" "https://img.shields.io/travis/iconnect/regex.svg?label=Build%20Status"+ , (,) "maintainers-contact" "https://img.shields.io/badge/email-maintainers%40regex.uk-blue.svg"+ , (,) "feedback-contact" "https://img.shields.io/badge/email-feedback%40regex.uk-blue.svg"+ ]+ where+ collect (nm,url) = do+ putStrLn $ "updating badge: " ++ nm+ simpleHttp url >>= LBS.writeFile (badge_fn nm)++ badge_fn nm = "docs/badges/"++nm++".svg"+\end{code}+++pages+-----++\begin{code}+pages :: IO ()+pages = do+ prep_page MM_hackage "lib/md/index.md" "README.markdown"+ prep_page MM_github "lib/md/index.md" "README.md"+ mapM_ pandoc_page [minBound..maxBound]+\end{code}++\begin{code}+data Page+ = PG_index+ | PG_about+ | PG_contact+ | PG_build_status+ | PG_installation+ | PG_tutorial+ | PG_examples+ | PG_roadmap+ | PG_macros+ | PG_directory+ | PG_changelog+ deriving (Bounded,Enum,Eq,Ord,Show)++page_root :: Page -> String+page_root = map tr . drop 3 . show+ where+ tr '_' = '-'+ tr c = c++page_master_file, page_docs_file :: Page -> FilePath+page_master_file pg = "lib/md/" ++ page_root pg ++ ".md"+page_docs_file pg = "docs/" ++ page_root pg ++ ".html"++page_address :: Page -> LBS.ByteString+page_address = LBS.pack . page_root++page_title :: Page -> LBS.ByteString+page_title pg = case pg of+ PG_index -> "Home"+ PG_about -> "About"+ PG_contact -> "Contact"+ PG_build_status -> "Build Status"+ PG_installation -> "Installation"+ PG_tutorial -> "Tutorial"+ PG_examples -> "Examples"+ PG_roadmap -> "Roadmap"+ PG_macros -> "Macro Tables"+ PG_directory -> "Directory"+ PG_changelog -> "Change Log"+\end{code}++\begin{code}+pandoc_page :: Page -> IO ()+pandoc_page pg = do+ mt_lbs <- LBS.readFile $ page_master_file pg+ (hdgs,md_lbs) <- prep_page' MM_pandoc mt_lbs+ LBS.writeFile "tmp/metadata.markdown" $ LBS.unlines ["---","title: "<>page_title pg,"---"]+ LBS.writeFile "tmp/heading.markdown" $ page_heading pg+ LBS.writeFile "tmp/page_pre_body.html" $ mk_pre_body_html pg hdgs+ LBS.writeFile "tmp/page_pst_body.html" pst_body_html+ LBS.writeFile "tmp/page.markdown" md_lbs+ fmap (const ()) $+ SH.shelly $ SH.verbosely $+ SH.run "pandoc"+ [ "-f", "markdown+grid_tables+autolink_bare_uris"+ , "-t", "html5"+ , "-T", "regex"+ , "-s"+ , "-H", "lib/favicons.html"+ , "-B", "tmp/page_pre_body.html"+ , "-A", "tmp/page_pst_body.html"+ , "-c", "lib/styles.css"+ , "-o", T.pack $ page_docs_file pg+ , "tmp/metadata.markdown"+ , "tmp/heading.markdown"+ , "tmp/page.markdown"+ ]++data Heading =+ Heading+ { _hdg_id :: LBS.ByteString+ , _hdg_title :: LBS.ByteString+ }+ deriving (Show)++data MarkdownMode+ = MM_github+ | MM_hackage+ | MM_pandoc+ deriving (Eq,Show)++page_heading :: Page -> LBS.ByteString+page_heading PG_index = ""+page_heading pg =+ "<p class='pagebc'><a href='.' title='Home'>Home</a> » **"<>page_title pg<>"**</p>\n"++prep_page :: MarkdownMode -> FilePath -> FilePath -> IO ()+prep_page mmd in_fp out_fp = do+ lbs <- LBS.readFile in_fp+ (_,lbs') <- prep_page' mmd lbs+ LBS.writeFile out_fp lbs'++prep_page' :: MarkdownMode -> LBS.ByteString -> IO ([Heading],LBS.ByteString)+prep_page' mmd lbs = do+ rf_h <- newIORef []+ rf_t <- newIORef False+ lbs1 <- sed' (scr rf_h rf_t) =<< include lbs+ lbs2 <- fromMaybe "" <$> fin_task_list' mmd rf_t+ hdgs <- reverse <$> readIORef rf_h+ return (hdgs,lbs1<>lbs2)+ where+ scr rf_h rf_t = Select+ [ (,) [re|^%heading#${ide}(@{%id}) +${ttl}([^ ].*)$|] $ EDIT_fun TOP $ heading mmd rf_t rf_h+ , (,) [re|^- \[ \] +${itm}(.*)$|] $ EDIT_fun TOP $ task_list mmd rf_t False+ , (,) [re|^- \[[Xx]\] +${itm}(.*)$|] $ EDIT_fun TOP $ task_list mmd rf_t True+ , (,) [re|^.*$|] $ EDIT_fun TOP $ fin_task_list mmd rf_t+ ]++heading :: MarkdownMode+ -> IORef Bool+ -> IORef [Heading]+ -> LineNo+ -> Match LBS.ByteString+ -> Location+ -> Capture LBS.ByteString+ -> IO (Maybe LBS.ByteString)+heading mmd rf_t rf_h _ mtch _ _ = do+ lbs <- fromMaybe "" <$> fin_task_list' mmd rf_t+ modifyIORef rf_h (Heading ide ttl:)+ return $ Just $ lbs<>h2+ where+ h2 = case mmd of+ MM_github -> "## "<>ttl+ MM_hackage -> "## "<>ttl+ MM_pandoc -> "<h2 id='"<>ide<>"'>"<>ttl<>"</h2>"++ ide = mtch !$$ [cp|ide|]+ ttl = mtch !$$ [cp|ttl|]++mk_pre_body_html :: Page -> [Heading] -> LBS.ByteString+mk_pre_body_html pg hdgs = hdr <> LBS.concat (map nav [minBound..maxBound]) <> ftr+ where+ hdr :: LBS.ByteString+ hdr = [here| <div id="container">+ <div id="sidebar">+ <div id="corner">+ |] <> branding <> [here|+ </div>+ <div class="widget" id="pages">+ <ul class="page-nav">+|]++ nav dst_pg = LBS.unlines $+ nav_li " " pg_cls pg_adr pg_ttl :+ [ nav_li " " ["secnav"] ("#"<>_hdg_id) _hdg_title+ | Heading{..} <- hdgs+ , is_moi+ ]+ where+ pg_cls = ["pagenav",if is_moi then "moi" else "toi"]+ pg_adr = page_address dst_pg+ pg_ttl = page_title dst_pg+ is_moi = pg == dst_pg++ nav_li pfx cls dst title = LBS.concat+ [ pfx+ , "<li class='"+ , LBS.unwords cls+ , "'><a href='"+ , dst+ , "'>"+ , title+ , "</a></li>"+ ]++ ftr = [here| </ul>+ </div>+ <div class="supplementary widget" id="github">+ <a href="https://github.com/iconnect/regex"><img src="images/code.svg" alt="github code" /> Code</a>+ </div>+ <div class="supplementary widget" id="github-issues">+ <a href="https://github.com/iconnect/regex/issues"><img src="images/issue-opened.svg" alt="github code" /> Issues</a>+ </div>+ <div class="widget-divider"> </div>+ <div class="supplementary widget" id="build-status">+ <a href="https://hackage.haskell.org/package/regex">+ <img src="badges/hackage.svg" alt="hackage version" />+ </a>+ </div>+ <div class="supplementary widget" id="build-status">+ <a href="build-status">+ <img src="badges/build-status.svg" alt="build status" />+ </a>+ </div>+ <div class="supplementary widget" id="maintainers-contact">+ <a href="mailto:maintainers@regex.uk">+ <img src="badges/maintainers-contact.svg" alt="build status" />+ </a>+ </div>+ <div class="supplementary widget" id="feedback-contact">+ <a href="mailto:feedback@regex.uk">+ <img src="badges/feedback-contact.svg" alt="build status" />+ </a>+ </div>+ <div class="supplementary widget twitter">+ <iframe style="width:162px; height:20px;" src="https://platform.twitter.com/widgets/follow_button.html?screen_name=hregex&show_count=false">+ </iframe>+ </div>+ </div>+ <div id="content">+|]++pst_body_html :: LBS.ByteString+pst_body_html = [here| </div>+ </div>+|]+\end{code}+++Task Lists+----------++\begin{code}+-- | replacement function to convert GFM task list line into HTML if we+-- aren't writing GFM (i.e., generating markdown for GitHub)+task_list :: MarkdownMode -- ^ what flavour of md are we generating+ -> IORef Bool -- ^ will contain True iff we have already entered a task list+ -> Bool -- ^ true if this is a checjed line+ -> LineNo -- ^ line no of the replacement redex (unused)+ -> Match LBS.ByteString -- ^ the matched task-list line+ -> Location -- ^ which match and capure (unused)+ -> Capture LBS.ByteString -- ^ the capture weare replacing (unsuded)+ -> IO (Maybe LBS.ByteString) -- ^ the replacement text, or Nothing to indicate no change to this line+task_list mmd rf chk _ mtch _ _ =+ case mmd of+ MM_github -> return Nothing+ MM_hackage -> return $ Just $ " "<>cb<>" "<>itm<>"\n"+ MM_pandoc -> do+ in_tl <- readIORef rf+ writeIORef rf True+ return $ tl_line in_tl chk+ where+ tl_line in_tl enbl = Just $ LBS.concat+ [ if in_tl then "" else "<ul class='contains-task-list'>\n"+ , " <li class='task-list-item'>"+ , "<input type='checkbox' class='task-list-item-checkbox'"+ , if enbl then " checked=''" else ""+ , " disabled=''/>"+ , itm+ , "</li>"+ ]++ cb = if chk then "☒" else "☐"++ itm = mtch !$$ [cp|itm|]++-- | replacement function used for 'other' lines -- terminate any task+-- list that was being generated+fin_task_list :: MarkdownMode -- ^ what flavour of md are we generating+ -> IORef Bool -- ^ will contain True iff we have already entered a task list+ -> LineNo -- ^ line no of the replacement redex (unused)+ -> Match LBS.ByteString -- ^ the matched task-list line+ -> Location -- ^ which match and capure (unused)+ -> Capture LBS.ByteString -- ^ the capture weare replacing (unsuded)+ -> IO (Maybe LBS.ByteString) -- ^ the replacement text, or Nothing to indicate no change to this line+fin_task_list mmd rf_t _ mtch _ _ =+ fmap (<>matchSource mtch) <$> fin_task_list' mmd rf_t++-- | close any task list being processed, returning the closing text+-- as necessary+fin_task_list' :: MarkdownMode -- ^ what flavour of md are we generating+ -> IORef Bool -- ^ will contain True iff we have already entered a task list+ -> IO (Maybe LBS.ByteString) -- ^ task-list closure HTML, if task-list HTML needs closing+fin_task_list' mmd rf = do+ in_tl <- readIORef rf+ writeIORef rf False+ case mmd==MM_github || not in_tl of+ True -> return Nothing+ False -> return $ Just $ "</ul>\n"+\end{code}+++Literate Haskell Pages+----------------------++\begin{code}+pandoc_lhs :: T.Text -> T.Text -> T.Text -> IO ()+pandoc_lhs title in_file = pandoc_lhs' title in_file in_file++pandoc_lhs' :: T.Text -> T.Text -> T.Text -> T.Text -> IO ()+pandoc_lhs' title repo_path in_file out_file = do+ LBS.writeFile "tmp/metadata.markdown" $+ LBS.unlines+ [ "---"+ , "title: "<>LBS.fromStrict (TE.encodeUtf8 title)+ ,"---"+ ]+ LBS.writeFile "tmp/bc.html" bc+ LBS.writeFile "tmp/ft.html" ft+ fmap (const ()) $+ SH.shelly $ SH.verbosely $+ SH.run "pandoc"+ [ "-f", "markdown+lhs+grid_tables"+ , "-t", "html5"+ , "-T", "regex"+ , "-s"+ , "-H", "lib/favicons.html"+ , "-B", "tmp/bc.html"+ , "-A", "tmp/ft.html"+ , "-c", "lib/lhs-styles.css"+ , "-c", "lib/bs.css"+ , "-o", out_file+ , "tmp/metadata.markdown"+ , in_file+ ]+ where+ bc = LBS.unlines+ -- [ "<div class='brandingdiv'>"+ -- , " " <> branding+ -- , "</div>"+ [ "<div class='bcdiv'>"+ , " <ol class='breadcrumb'>"+ , " <li>"<>branding<>"</li>"+ , " <li><a title='source file' href='" <>+ repo_url <> "'>" <> (LBS.pack $ T.unpack title) <> "</a></li>"+ , "</ol>"+ , "</div>"+ , "<div class='litcontent'>"+ ]++ ft = LBS.concat+ [ "</div>"+ ]++ repo_url = LBS.concat+ [ "https://github.com/iconnect/regex/blob/master/"+ , LBS.pack $ T.unpack repo_path+ ]+\end{code}+++simple include processor+------------------------++\begin{code}+include :: LBS.ByteString -> IO LBS.ByteString+include = sed' $ Select+ [ (,) [re|^%include ${file}(@{%string})$|] $ EDIT_fun TOP incl+ , (,) [re|^.*$|] $ EDIT_fun TOP $ \_ _ _ _->return Nothing+ ]+ where+ incl _ mtch _ _ = Just <$> LBS.readFile (prs_s $ mtch !$$ [cp|file|])+ prs_s = maybe (error "include") T.unpack . parseString+\end{code}+++branding+--------++\begin{code}+branding :: LBS.ByteString+branding = [here|<a href="." style="Arial, 'Helvetica Neue', Helvetica, sans-serif;" id="branding">[<span style='color:red;'>re</span>|${<span style='color:red;'>gex</span>}(.*)|<span></span>]</a>|]+\end{code}+++testing+-------++\begin{code}+test :: IO ()+test = do+ dm <- docMode+ test_pp "pp-doc" (loop dm) "data/pp-test.lhs" "data/pp-result-doc.lhs"+ gm <- genMode+ test_pp "pp-gen" (loop gm) "data/pp-test.lhs" "data/pp-result-gen.lhs"+ putStrLn "tests passed"+\end{code}
examples/re-tests.lhs view
@@ -1,17 +1,21 @@ \begin{code}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module Main (main) where -import Control.Applicative import Control.Exception import Data.Array import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as LBS import qualified Data.Foldable as F+import qualified Data.HashMap.Strict as HM import Data.Maybe import Data.Monoid import qualified Data.Sequence as S@@ -19,9 +23,14 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as LT import Language.Haskell.TH.Quote+import Prelude.Compat+import Test.SmallCheck.Series import Test.Tasty import Test.Tasty.HUnit+import Test.Tasty.SmallCheck as SC+import Text.Heredoc import qualified Text.Regex.PCRE as PCRE_+ import qualified Text.Regex.TDFA as TDFA_ import Text.RE import Text.RE.Internal.NamedCaptures@@ -65,11 +74,11 @@ where tc rty m_env = testCase (show rty) $ do- dumpMacroTable "prelude" rty m_env+ dumpMacroTable "macros" rty m_env assertBool "testMacroEnv" =<< testMacroEnv "prelude" rty m_env -str, str' :: String-str = "a bbbb aa b"+str_, str' :: String+str_ = "a bbbb aa b" str' = "foo" regex_, regex_alt :: RE@@ -158,35 +167,35 @@ parsing_tests = testGroup "Parsing" [ testCase "complete check (matchM/ByteString)" $ do r <- compileRegex () $ reSource regex_- assertEqual "Match" (B.pack <$> regex_str_match) $ B.pack str ?=~ r+ assertEqual "Match" (B.pack <$> regex_str_match) $ B.pack str_ ?=~ r , testCase "matched (matchM/Text)" $ do r <- compileRegex () $ reSource regex_- assertEqual "matched" True $ matched $ T.pack str ?=~ r+ assertEqual "matched" True $ matched $ T.pack str_ ?=~ r ] core_tests :: TestTree core_tests = testGroup "Match" [ testCase "text (=~~Text.Lazy)" $ do- txt <- LT.pack str =~~ [re|(a+) (b+)|] :: IO (LT.Text)+ txt <- LT.pack str_ =~~ [re|(a+) (b+)|] :: IO (LT.Text) assertEqual "text" txt "a bbbb" , testCase "multi (=~~/String)" $ do- let sm = str =~ regex_ :: Match String+ let sm = str_ =~ regex_ :: Match String m = capture [cp|0|] sm assertEqual "captureSource" "a bbbb aa b" $ captureSource m assertEqual "capturedText" "a bbbb" $ capturedText m assertEqual "capturePrefix" "" $ capturePrefix m assertEqual "captureSuffix" " aa b" $ captureSuffix m , testCase "complete (=~~/ByteString)" $ do- mtch <- B.pack str =~~ regex_ :: IO (Match B.ByteString)+ mtch <- B.pack str_ =~~ regex_ :: IO (Match B.ByteString) assertEqual "Match" mtch $ B.pack <$> regex_str_match , testCase "complete (all,String)" $ do- let mtchs = str =~ regex_ :: Matches String+ let mtchs = str_ =~ regex_ :: Matches String assertEqual "Matches" mtchs regex_str_matches , testCase "complete (all,reg_alt)" $ do- let mtchs = str =~ regex_alt :: Matches String+ let mtchs = str_ =~ regex_alt :: Matches String assertEqual "Matches" mtchs regex_alt_str_matches , testCase "complete (=~~,all)" $ do- mtchs <- str =~~ regex_ :: IO (Matches String)+ mtchs <- str_ =~~ regex_ :: IO (Matches String) assertEqual "Matches" mtchs regex_str_matches , testCase "fail (all)" $ do let mtchs = str' =~ regex_ :: Matches String@@ -196,27 +205,27 @@ replace_tests :: TestTree replace_tests = testGroup "Replace" [ testCase "String/single" $ do- let m = str =~ regex_ :: Match String+ let m = str_ =~ regex_ :: Match String r = replaceCaptures' ALL fmt m assertEqual "replaceCaptures'" r "(0:0:(0:1:a) (0:2:bbbb)) aa b" , testCase "String/alt" $ do- let ms = str =~ regex_ :: Matches String+ let ms = str_ =~ regex_ :: Matches String r = replaceAllCaptures' ALL fmt ms chk r , testCase "String" $ do- let ms = str =~ regex_ :: Matches String+ let ms = str_ =~ regex_ :: Matches String r = replaceAllCaptures' ALL fmt ms chk r , testCase "ByteString" $ do- let ms = B.pack str =~ regex_ :: Matches B.ByteString+ let ms = B.pack str_ =~ regex_ :: Matches B.ByteString r = replaceAllCaptures' ALL fmt ms chk r , testCase "LBS.ByteString" $ do- let ms = LBS.pack str =~ regex_ :: Matches LBS.ByteString+ let ms = LBS.pack str_ =~ regex_ :: Matches LBS.ByteString r = replaceAllCaptures' ALL fmt ms chk r , testCase "Seq Char" $ do- let ms = S.fromList str =~ regex_ :: Matches (S.Seq Char)+ let ms = S.fromList str_ =~ regex_ :: Matches (S.Seq Char) f = \_ (Location i j) Capture{..} -> Just $ S.fromList $ "(" <> show i <> ":" <> show_co j <> ":" <> F.toList capturedText <> ")"@@ -224,11 +233,11 @@ assertEqual "replaceAllCaptures'" r $ S.fromList "(0:0:(0:1:a) (0:2:bbbb)) (1:0:(1:1:aa) (1:2:b))" , testCase "Text" $ do- let ms = T.pack str =~ regex_ :: Matches T.Text+ let ms = T.pack str_ =~ regex_ :: Matches T.Text r = replaceAllCaptures' ALL fmt ms chk r , testCase "LT.Text" $ do- let ms = LT.pack str =~ regex_ :: Matches LT.Text+ let ms = LT.pack str_ =~ regex_ :: Matches LT.Text r = replaceAllCaptures' ALL fmt ms chk r ]@@ -438,4 +447,76 @@ tdfa_prelude_macros :: [PreludeMacro] tdfa_prelude_macros = [minBound..maxBound]+\end{code}+++Testing : FormatToken/Scan Properties+-------------------------------------++\begin{code}+namedCapturesTestTree :: TestTree+namedCapturesTestTree = localOption (SmallCheckDepth 4) $+ testGroup "NamedCaptures"+ [ formatScanTestTree+ , analyseTokensTestTree+ ]+\end{code}++\begin{code}+instance Monad m => Serial m Token+\end{code}+++Testing : FormatToken/Scan Properties+-------------------------------------++\begin{code}+formatScanTestTree :: TestTree+formatScanTestTree =+ testGroup "FormatToken/Scan Properties"+ [ localOption (SmallCheckDepth 4) $+ SC.testProperty "formatTokens == formatTokens0" $+ \tks -> formatTokens tks == formatTokens0 tks+ , localOption (SmallCheckDepth 4) $+ SC.testProperty "scan . formatTokens' idFormatTokenOptions == id" $+ \tks -> all validToken tks ==>+ scan (formatTokens' idFormatTokenOptions tks) == tks+ ]+\end{code}+++Testing : Analysing [Token] Unit Tests+--------------------------------------++\begin{code}+analyseTokensTestTree :: TestTree+analyseTokensTestTree =+ testGroup "Analysing [Token] Unit Tests"+ [ tc [here|foobar|] []+ , tc [here||] []+ , tc [here|$([0-9]{4})|] []+ , tc [here|${x}()|] [(1,"x")]+ , tc [here|${}()|] []+ , tc [here|${}()${foo}()|] [(2,"foo")]+ , tc [here|${x}(${y()})|] [(1,"x")]+ , tc [here|${x}(${y}())|] [(1,"x"),(2,"y")]+ , tc [here|${a}(${b{}())|] [(1,"a")]+ , tc [here|${y}([0-9]{4})-${m}([0-9]{2})-${d}([0-9]{2})|] [(1,"y"),(2,"m"),(3,"d")]+ , tc [here|@$(@|\{${name}([^{}]+)\})|] [(2,"name")]+ , tc [here|${y}[0-9]{4}|] []+ , tc [here|${}([0-9]{4})|] []+ ]+ where+ tc s al =+ testCase s $ assertEqual "CaptureNames"+ (xnc s)+ (HM.fromList+ [ (CaptureName $ T.pack n,CaptureOrdinal i)+ | (i,n)<-al+ ]+ )++ xnc = either oops fst . extractNamedCaptures+ where+ oops = error "analyseTokensTestTree: unexpected parse failure" \end{code}
examples/re-tutorial.lhs view
@@ -29,7 +29,7 @@ should be enabled. \begin{code}-{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE QuasiQuotes #-} \end{code} Use this command to configure ghci accordingly (not necessary if you@@ -38,21 +38,22 @@ :seti -XQuasiQuotes ``` -[Overloaded string-literals](https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/guide-to-ghc-extensions/basic-syntax-extensions#overloadedstrings)-are usually enabled in modern Haskell and we do so here.-\begin{code}-{-# LANGUAGE OverloadedStrings #-}-\end{code}- Because we are mimicking the REPL in this tutorial we will leave off the type signatures on the example calculations and disable the compiler warnings about missing type signatures. \begin{code}-{-# OPTIONS_GHC -fno-warn-missing-signatures #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures #-} \end{code} +This pragma is a just technical pragma, combined with the+`Prelude.Compat` import below used to avoid certain warnings while+comiling against multiple versions of the compiler. It can be safely+ignored.+\begin{code}+{-# LANGUAGE NoImplicitPrelude #-}+\end{code} + Loading Up: The Imports ----------------------- @@ -107,9 +108,11 @@ import Text.Printf \end{code} -And finally we will import a small specail toolkit will be used to help+And finally we a special edition of the prelude (see the commentary for+the pragma section above) and a small specail toolkit will be used to help manage the example calculations. \begin{code}+import Prelude.Compat import TestKit \end{code} This allows simple calculations to be defined stylistically@@ -613,7 +616,7 @@ that matches one of the REs, substituting the text returned from the action in the output stream. (Used in the [include](re-include.html), [gen-modules](re-gen-modules.html),- [log-processor](re-nginx-log-processor.html) and [tutorial-pp](re-pp)+ [log-processor](re-nginx-log-processor.html) and [tutorial-pp](re-prep) examples.) @@ -691,9 +694,9 @@ package's website uses the following 'gen_all' diriver which uses REs to analyse file paths. -%include "examples/re-pp.lhs" "^gen_all ::"+%include "examples/re-prep.lhs" "^gen_all ::" -See [examples/re-pp.lhs](re-pp.html)+See [examples/re-prep.lhs](re-prep.html) Example: parsing RE macros@@ -751,7 +754,7 @@ Just $ replaceAllCaptures' TOP phi $ tpl *=~ [re|\$${arg}(\$|[0-9]+|\{${name}([^{}]+)\})|] where- phi t_mtch _ _ = case captureMaybe [cp|name|] t_mtch of+ phi t_mtch _ _ = case t_mtch !$? [cp|name|] of Just cap -> this $ CID_name $ CaptureName txt where txt = T.pack $ capturedText cap@@ -761,7 +764,7 @@ where t = capturedText $ capture [cp|arg|] t_mtch - this cid = capturedText <$> captureMaybe cid mtch+ this cid = capturedText <$> mtch !$? cid my_replace :: RE -> Template-> String -> String my_replace rex tpl src = replaceAllCaptures' TOP (parse_tpl_ tpl) $ src *=~ rex@@ -813,7 +816,7 @@ The preprocessor that converts this literate Haskell program into a web page and a test suite that makes plenty of use of regex is in-[examples/re-pp.lhs](re-pp.html).+[examples/re-prep.lhs](re-prep.html). Example: gen-modules
regex.cabal view
@@ -1,6 +1,6 @@ Name: regex-Version: 0.0.0.2-Synopsis: A Regular Expression Toolkit for regex-base+Version: 0.1.0.0+Synopsis: Toolkit for regex-base Description: A Regular Expression Toolkit for regex-base with Compile-time checking of RE syntax, data types for matches and captures, a text replacement toolkit,@@ -18,23 +18,25 @@ Stability: rfc bug-reports: https://github.com/iconnect/regex/issues -extra-source-files:- README.md+Extra-Source-Files:+ README.markdown changelog -Cabal-version: >= 1.16+Cabal-Version: >= 1.16 -Source-repository head+Source-Repository head type: git location: https://github.com/iconnect/regex.git Source-Repository this Type: git Location: https://github.com/iconnect/regex.git- Tag: 0.0.0.2+ Tag: 0.1.0.0 + Library- Exposed-modules:+ Hs-Source-Dirs: .+ Exposed-Modules: Text.RE Text.RE.Capture Text.RE.CaptureID@@ -66,326 +68,491 @@ Text.RE.Tools.Lex Text.RE.Tools.Sed - Other-modules:+ Other-Modules: Text.RE.Internal.AddCaptureNames + Default-Language: Haskell2010+ GHC-Options:+ -Wall+ -fwarn-tabs+ Build-depends:- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- containers >= 0.4 ,- hashable >= 1.2.3.3 ,- heredoc >= 0.2.0.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.1 ,- regex-tdfa-text >= 1.0.0.3 ,- regex-pcre-builtin >= 0.94.4.8.8.35 ,- smallcheck >= 1.1.1 ,- tasty >= 0.10.1.2 ,- tasty-hunit >= 0.9.2 ,- tasty-smallcheck >= 0.8.0.1 ,- template-haskell >= 2.7 ,- transformers >= 0.2.2 ,- text >= 1.2.1.3 ,- time >= 1.5.0.1 ,- unordered-containers >= 0.2.5.1+ array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , hashable >= 1.2.3.3+ , heredoc >= 0.2.0.0+ , regex-base >= 0.93.2+ , regex-pcre-builtin >= 0.94.4.8.8.35+ , regex-tdfa >= 1.2.0+ , regex-tdfa-text >= 1.0.0.3+ , template-haskell >= 2.7+ , text >= 1.2.0.6+ , time >= 1.4.2+ , time-locale-compat >= 0.1.0.1+ , transformers >= 0.2.2+ , unordered-containers >= 0.2.5.1 ++Executable re-gen-cabals+ Hs-Source-Dirs: examples++ Main-Is: re-gen-cabals.lhs++ Other-Modules:+ TestKit+ Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs + Build-depends:+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , directory >= 1.2.1.0+ , regex-base >= 0.93.2+ , regex-tdfa >= 1.2.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6 ++Test-Suite re-gen-cabals-test+ type: exitcode-stdio-1.0+ Hs-Source-Dirs: examples++ Main-Is: re-gen-cabals.lhs++ Other-Modules:+ TestKit++ Default-Language: Haskell2010+ GHC-Options:+ -Wall+ -fwarn-tabs++ Build-depends:+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , directory >= 1.2.1.0+ , regex-base >= 0.93.2+ , regex-tdfa >= 1.2.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6+++ Executable re-gen-modules Hs-Source-Dirs: examples - Main-is: re-gen-modules.lhs+ Main-Is: re-gen-modules.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs Build-depends:- regex ,- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 ,- directory >= 1.2.1.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , regex-base >= 0.93.2+ , regex-tdfa >= 1.2.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6 Test-Suite re-gen-modules-test type: exitcode-stdio-1.0 Hs-Source-Dirs: examples - Main-is: re-gen-modules.lhs+ Main-Is: re-gen-modules.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs Build-depends:- regex ,- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- directory >= 1.2.1.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , regex-base >= 0.93.2+ , regex-tdfa >= 1.2.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6 + Executable re-include Hs-Source-Dirs: examples - Main-is: re-include.lhs+ Main-Is: re-include.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs - Other-modules:+ Other-Modules: TestKit Build-depends:- regex ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- directory >= 1.2.1.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3+ regex + , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6 Test-Suite re-include-test type: exitcode-stdio-1.0 Hs-Source-Dirs: examples - Main-is: re-include.lhs+ Main-Is: re-include.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs - Other-modules:+ Other-Modules: TestKit Build-depends:- regex ,- bytestring >= 0.10.2.0 ,- base >= 4 ,- directory >= 1.2.1.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3+ regex + , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6 ++Executable re-nginx-log-processor+ Hs-Source-Dirs: examples++ Main-Is: re-nginx-log-processor.lhs++ Default-Language: Haskell2010+ GHC-Options:+ -Wall+ -fwarn-tabs++ Build-depends:+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , regex-base >= 0.93.2+ , regex-tdfa >= 1.2.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6+ , time >= 1.4.2+ , time-locale-compat >= 0.1.0.1+ , transformers >= 0.2.2+ , unordered-containers >= 0.2.5.1++ Test-Suite re-nginx-log-processor-test type: exitcode-stdio-1.0 Hs-Source-Dirs: examples - Main-is: re-nginx-log-processor.lhs+ Main-Is: re-nginx-log-processor.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs Build-depends:- regex ,- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- directory >= 1.2.1.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3 ,- time >= 1.5.0.1 ,- transformers >= 0.3.0.0 ,- unordered-containers >= 0.2.5.1+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , regex-base >= 0.93.2+ , regex-tdfa >= 1.2.0+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6+ , time >= 1.4.2+ , time-locale-compat >= 0.1.0.1+ , transformers >= 0.2.2+ , unordered-containers >= 0.2.5.1 -Executable re-nginx-log-processor++Executable re-prep Hs-Source-Dirs: examples - Main-is: re-nginx-log-processor.lhs+ Main-Is: re-prep.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs + Other-Modules:+ TestKit+ Build-depends:- regex ,- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- directory >= 1.2.1.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3 ,- time >= 1.5.0.1 ,- transformers >= 0.3.0.0 ,- unordered-containers >= 0.2.5.1+ regex + , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , heredoc >= 0.2.0.0+ , http-conduit >= 2.1.7.2+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6 -Executable re-pp+Test-Suite re-prep-test+ type: exitcode-stdio-1.0 Hs-Source-Dirs: examples - Main-is: re-pp.lhs+ Main-Is: re-prep.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs - Other-modules:+ Other-Modules: TestKit Build-depends:- regex ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- directory >= 1.2.1.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3+ regex + , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , directory >= 1.2.1.0+ , heredoc >= 0.2.0.0+ , http-conduit >= 2.1.7.2+ , shelly >= 1.6.1.2+ , text >= 1.2.0.6 -Test-Suite re-pp-test- type: exitcode-stdio-1.0++Executable re-tests Hs-Source-Dirs: examples - Main-is: re-pp.lhs+ Main-Is: re-tests.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs - Other-modules:+ Other-Modules: TestKit Build-depends:- regex ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- directory >= 1.2.1.0 ,- shelly >= 1.6.1.2 ,- text >= 1.2.1.3+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , directory >= 1.2.1.0+ , heredoc >= 0.2.0.0+ , regex-base >= 0.93.2+ , regex-pcre-builtin >= 0.94.4.8.8.35+ , regex-tdfa >= 1.2.0+ , regex-tdfa-text >= 1.0.0.3+ , smallcheck >= 1.1.1+ , tasty >= 0.10.1.2+ , tasty-hunit >= 0.9.2+ , tasty-smallcheck >= 0.8.0.1+ , template-haskell >= 2.7+ , text >= 1.2.0.6+ , unordered-containers >= 0.2.5.1 -Test-Suite re-tests+Test-Suite re-tests-test type: exitcode-stdio-1.0 Hs-Source-Dirs: examples - Main-is: re-tests.lhs+ Main-Is: re-tests.lhs Default-Language: Haskell2010 GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs - Other-modules:+ Other-Modules: TestKit Build-depends:- regex ,- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- containers >= 0.4 ,- directory >= 1.2.1.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.0 ,- regex-tdfa-text >= 1.0.0.3 ,- regex-pcre-builtin >= 0.94.4.8.8.35 ,- tasty >= 0.10.1.2 ,- tasty-hunit >= 0.9.2 ,- template-haskell >= 2.7 ,- text >= 1.2.1.3+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , directory >= 1.2.1.0+ , heredoc >= 0.2.0.0+ , regex-base >= 0.93.2+ , regex-pcre-builtin >= 0.94.4.8.8.35+ , regex-tdfa >= 1.2.0+ , regex-tdfa-text >= 1.0.0.3+ , smallcheck >= 1.1.1+ , tasty >= 0.10.1.2+ , tasty-hunit >= 0.9.2+ , tasty-smallcheck >= 0.8.0.1+ , template-haskell >= 2.7+ , text >= 1.2.0.6+ , unordered-containers >= 0.2.5.1 + Executable re-tutorial- Hs-Source-Dirs: examples .+ Hs-Source-Dirs: examples - Main-is: re-tutorial.lhs+ Main-Is: re-tutorial.lhs - Other-modules:+ Other-Modules: TestKit Default-Language: Haskell2010 Default-Extensions: QuasiQuotes GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs Build-depends:- regex ,- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- containers >= 0.4 ,- directory >= 1.2.1.0 ,- hashable >= 1.2.3.3 ,- heredoc >= 0.2.0.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.1 ,- regex-tdfa-text >= 1.0.0.3 ,- regex-pcre-builtin >= 0.94.4.8.8.35 ,- shelly >= 1.6.1.2 ,- smallcheck >= 1.1.1 ,- tasty >= 0.10.1.2 ,- tasty-hunit >= 0.9.2 ,- tasty-smallcheck >= 0.8.0.1 ,- template-haskell >= 2.7 ,- transformers >= 0.2.2 ,- text >= 1.2.1.3 ,- time >= 1.5.0.1 ,- unordered-containers >= 0.2.5.1+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , directory >= 1.2.1.0+ , hashable >= 1.2.3.3+ , heredoc >= 0.2.0.0+ , regex-base >= 0.93.2+ , regex-pcre-builtin >= 0.94.4.8.8.35+ , regex-tdfa >= 1.2.0+ , regex-tdfa-text >= 1.0.0.3+ , shelly >= 1.6.1.2+ , smallcheck >= 1.1.1+ , tasty >= 0.10.1.2+ , tasty-hunit >= 0.9.2+ , tasty-smallcheck >= 0.8.0.1+ , template-haskell >= 2.7+ , text >= 1.2.0.6+ , time >= 1.4.2+ , time-locale-compat >= 0.1.0.1+ , transformers >= 0.2.2+ , unordered-containers >= 0.2.5.1 + Test-Suite re-tutorial-test type: exitcode-stdio-1.0- Hs-Source-Dirs: examples .+ Hs-Source-Dirs: examples - Main-is: re-tutorial.lhs+ Main-Is: re-tutorial.lhs - Other-modules:+ Other-Modules: TestKit Default-Language: Haskell2010 Default-Extensions: QuasiQuotes GHC-Options:- -Wall- -fwarn-tabs+ -Wall+ -fwarn-tabs Build-depends:- regex ,- array >= 0.4 ,- bytestring >= 0.10.2.0 ,- base >= 4 && < 5 ,- containers >= 0.4 ,- directory >= 1.2.1.0 ,- hashable >= 1.2.3.3 ,- heredoc >= 0.2.0.0 ,- regex-base >= 0.93.2 ,- regex-tdfa >= 1.2.1 ,- regex-tdfa-text >= 1.0.0.3 ,- regex-pcre-builtin >= 0.94.4.8.8.35 ,- shelly >= 1.6.1.2 ,- smallcheck >= 1.1.1 ,- tasty >= 0.10.1.2 ,- tasty-hunit >= 0.9.2 ,- tasty-smallcheck >= 0.8.0.1 ,- template-haskell >= 2.7 ,- transformers >= 0.2.2 ,- text >= 1.2.1.3 ,- time >= 1.5.0.1 ,- unordered-containers >= 0.2.5.1+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , directory >= 1.2.1.0+ , hashable >= 1.2.3.3+ , heredoc >= 0.2.0.0+ , regex-base >= 0.93.2+ , regex-pcre-builtin >= 0.94.4.8.8.35+ , regex-tdfa >= 1.2.0+ , regex-tdfa-text >= 1.0.0.3+ , shelly >= 1.6.1.2+ , smallcheck >= 1.1.1+ , tasty >= 0.10.1.2+ , tasty-hunit >= 0.9.2+ , tasty-smallcheck >= 0.8.0.1+ , template-haskell >= 2.7+ , text >= 1.2.0.6+ , time >= 1.4.2+ , time-locale-compat >= 0.1.0.1+ , transformers >= 0.2.2+ , unordered-containers >= 0.2.5.1++++Test-Suite re-tutorial-os-test+ type: exitcode-stdio-1.0+ Hs-Source-Dirs: examples++ Main-Is: re-tutorial.lhs++ Other-Modules:+ TestKit++ Default-Language: Haskell2010+ Extensions: OverloadedStrings+ Default-Extensions: QuasiQuotes+ GHC-Options:+ -Wall+ -fwarn-tabs++ Build-depends:+ regex + , array >= 0.4+ , base >= 4 && < 5+ , base-compat >= 0.6.0+ , bytestring >= 0.10.2.0+ , containers >= 0.4+ , directory >= 1.2.1.0+ , hashable >= 1.2.3.3+ , heredoc >= 0.2.0.0+ , regex-base >= 0.93.2+ , regex-pcre-builtin >= 0.94.4.8.8.35+ , regex-tdfa >= 1.2.0+ , regex-tdfa-text >= 1.0.0.3+ , shelly >= 1.6.1.2+ , smallcheck >= 1.1.1+ , tasty >= 0.10.1.2+ , tasty-hunit >= 0.9.2+ , tasty-smallcheck >= 0.8.0.1+ , template-haskell >= 2.7+ , text >= 1.2.0.6+ , time >= 1.4.2+ , time-locale-compat >= 0.1.0.1+ , transformers >= 0.2.2+ , unordered-containers >= 0.2.5.1+++-- Generated from lib/rgex-master.cabal with re-gen-cabals