regex-tdfa 1.3.1.3 → 1.3.1.4
raw patch · 8 files changed
+222/−95 lines, 8 filesdep +doctest-paralleldep ~base
Dependencies added: doctest-parallel
Dependency ranges changed: base
Files
- CHANGELOG.md +13/−2
- lib/Data/IntMap/CharMap2.hs +1/−1
- lib/Data/IntMap/EnumMap2.hs +1/−1
- lib/Text/Regex/TDFA.hs +38/−18
- lib/Text/Regex/TDFA/Common.hs +68/−49
- lib/Text/Regex/TDFA/ReadRegex.hs +70/−22
- regex-tdfa.cabal +15/−2
- test/DocTestMain.hs +16/−0
CHANGELOG.md view
@@ -1,11 +1,22 @@ For the package version policy (PVP), see http://pvp.haskell.org/faq . +### 1.3.1.4++_2022-07-17, Andreas Abel_++- Fix parsing of dashes in bracket expressions, e.g. `[-a-z]` ([#1](https://github.com/haskell-hvr/regex-tdfa/issues/1))+- Fix a deprecation warning except for on GHC 8.2 ([#21](https://github.com/haskell-hvr/regex-tdfa/issues/21))+- Documentation: link `defaultComptOpt` to its definition ([#13](https://github.com/haskell-hvr/regex-tdfa/issues/13))+- Verify documentation examples with new `doc-test` testsuite+- Tested with GHC 7.4 - 9.4+ ### 1.3.1.3 _2022-07-14, Andreas Abel_ -- Fix an `undefined` in `Show PatternSet` [#37](https://github.com/haskell-hvr/regex-tdfa/issues/37))-- Document POSIX character classes (e.g. `[[:digit:]]`)+- Fix an `undefined` in `Show PatternSet` ([#37](https://github.com/haskell-hvr/regex-tdfa/issues/37))+- Document POSIX character classes (e.g. `[[:digit:]]`) in README+- Tested with GHC 7.4 - 9.4 ### 1.3.1.2 Revision 1
lib/Data/IntMap/CharMap2.hs view
@@ -9,7 +9,7 @@ import Data.Char as C(ord) import Data.List as L (map) import qualified Data.IntMap as M-#if MIN_VERSION_containers(0,6,0)+#if MIN_VERSION_containers(0,5,11) import qualified Data.IntMap.Internal.Debug as MD #else import qualified Data.IntMap as MD
lib/Data/IntMap/EnumMap2.hs view
@@ -4,7 +4,7 @@ import Data.Foldable as F (Foldable(foldMap)) import qualified Data.IntMap as M-#if MIN_VERSION_containers(0,6,0)+#if MIN_VERSION_containers(0,5,11) import qualified Data.IntMap.Internal.Debug as MD #else import qualified Data.IntMap as MD
lib/Text/Regex/TDFA.hs view
@@ -32,10 +32,19 @@ = Basics @-λ> let emailRegex = "[a-zA-Z0-9+.\_-]+\@[a-zA-Z-]+\\\\.[a-z]+"-λ> "my email is email@email.com" '=~' emailRegex :: Bool->>> True+>>> let emailRegex = "[a-zA-Z0-9+._-]+\\@[-a-zA-Z]+\\.[a-z]+"+>>> "my email is first-name.lastname_1974@e-mail.com" =~ emailRegex :: Bool+True +>>> "invalid@mail@com" =~ emailRegex :: Bool+False++>>> "invalid@mail.COM" =~ emailRegex :: Bool+False++>>> "#@invalid.com" =~ emailRegex :: Bool+False+ /-- non-monadic/ λ> \<to-match-against\> '=~' \<regex\> @@ -61,11 +70,12 @@ /-- returns empty string if no match/ a '=~' b :: String /-- or ByteString, or Text.../ -λ> "alexis-de-tocqueville" '=~' "[a-z]+" :: String->>> "alexis"+>>> "alexis-de-tocqueville" =~ "[a-z]+" :: String+"alexis" -λ> "alexis-de-tocqueville" '=~' "[0-9]+" :: String->>> ""+>>> "alexis-de-tocqueville" =~ "[0-9]+" :: String+""+ @ == Check if it matched at all@@ -73,8 +83,9 @@ @ a '=~' b :: Bool -λ> "alexis-de-tocqueville" '=~' "[a-z]+" :: Bool->>> True+>>> "alexis-de-tocqueville" =~ "[a-z]+" :: Bool+True+ @ == Get first match + text before/after@@ -84,11 +95,12 @@ /-- string in the first element of the tuple/ a =~ b :: (String, String, String) -λ> "alexis-de-tocqueville" '=~' "de" :: (String, String, String)->>> ("alexis-", "de", "-tocqueville")+>>> "alexis-de-tocqueville" =~ "de" :: (String, String, String)+("alexis-","de","-tocqueville") -λ> "alexis-de-tocqueville" '=~' "kant" :: (String, String, String)->>> ("alexis-de-tocqueville", "", "")+>>> "alexis-de-tocqueville" =~ "kant" :: (String, String, String)+("alexis-de-tocqueville","","")+ @ == Get first match + submatches@@ -98,8 +110,9 @@ /-- submatch list is empty if regex doesn't match at all/ a '=~' b :: (String, String, String, [String]) -λ> "div[attr=1234]" '=~' "div\\\\[([a-z]+)=([^]]+)\\\\]" :: (String, String, String, [String])->>> ("", "div[attr=1234]", "", ["attr","1234"])+>>> "div[attr=1234]" =~ "div\\[([a-z]+)=([^]]+)\\]" :: (String, String, String, [String])+("","div[attr=1234]","",["attr","1234"])+ @ == Get /all/ matches@@ -108,8 +121,9 @@ /-- can also return Data.Array instead of List/ 'getAllTextMatches' (a '=~' b) :: [String] -λ> 'getAllTextMatches' ("john anne yifan" '=~' "[a-z]+") :: [String]->>> ["john","anne","yifan"]+>>> getAllTextMatches ("john anne yifan" =~ "[a-z]+") :: [String]+["john","anne","yifan"]+ @ = Feature support@@ -143,6 +157,12 @@ ASCII only, valid classes are alnum, digit, punct, alpha, graph, space, blank, lower, upper, cntrl, print, xdigit, word. +@+>>> getAllTextMatches ("john anne yifan" =~ "[[:lower:]]+") :: [String]+["john","anne","yifan"]++@+ This package does not provide "basic" regular expressions. This package does not provide back references inside regular expressions. @@ -165,7 +185,7 @@ import Text.Regex.TDFA λ> "2 * (3 + 1) / 4" '=~' [r|\\([^)]+\\)|] :: String->>> "(3 + 1)"+"(3 + 1)" @ -}
lib/Text/Regex/TDFA/Common.hs view
@@ -1,7 +1,9 @@ {-# OPTIONS -funbox-strict-fields #-}--- | Common provides simple functions to the backend. It defines most--- of the data types. All modules should call error via the--- common_error function below.++-- | Common provides simple functions to the backend.+-- It defines most of the data types.+-- All modules should call 'error' via the 'common_error' function below.+ module Text.Regex.TDFA.Common where import Text.Regex.Base(RegexOptions(..))@@ -31,14 +33,14 @@ on :: (t1 -> t1 -> t2) -> (t -> t1) -> t -> t -> t2 f `on` g = (\x y -> (g x) `f` (g y)) --- | after 'sort' or 'sortBy' the use of 'nub'\/'nubBy' can be replaced by 'norep'\/'norepBy'+-- | After 'sort' or 'sortBy' the use of 'nub' or 'nubBy' can be replaced by 'norep' or 'norepBy'. norep :: (Eq a) => [a]->[a] norep [] = [] norep x@[_] = x norep (a:bs@(c:cs)) | a==c = norep (a:cs) | otherwise = a:norep bs --- | after 'sort' or 'sortBy' the use of 'nub'\/'nubBy' can be replaced by 'norep'\/'norepBy'+-- | After 'sort' or 'sortBy' the use of 'nub' or 'nubBy' can be replaced by 'norep' or 'norepBy'. norepBy :: (a -> a -> Bool) -> [a] -> [a] norepBy _ [] = [] norepBy _ x@[_] = x@@ -68,8 +70,7 @@ noWin :: WinTags -> Bool noWin = null --- | Used to track elements of the pattern that accept characters or--- are anchors+-- | Used to track elements of the pattern that accept characters or are anchors. newtype DoPa = DoPa {dopaIndex :: Int} deriving (Eq,Ord) instance Enum DoPa where@@ -82,19 +83,26 @@ -- | Control whether the pattern is multiline or case-sensitive like Text.Regex and whether to -- capture the subgroups (\\1, \\2, etc). Controls enabling extra anchor syntax. data CompOption = CompOption {- caseSensitive :: Bool -- ^ True in blankCompOpt and defaultCompOpt- , multiline :: Bool {- ^ False in blankCompOpt, True in defaultCompOpt. Compile for- newline-sensitive matching. "By default, newline is a completely ordinary- character with no special meaning in either REs or strings. With this flag,- inverted bracket expressions and . never match newline, a ^ anchor matches the- null string after any newline in the string in addition to its normal- function, and the $ anchor matches the null string before any newline in the- string in addition to its normal function." -}- , rightAssoc :: Bool -- ^ True (and therefore Right associative) in blankCompOpt and defaultCompOpt- , newSyntax :: Bool -- ^ False in blankCompOpt, True in defaultCompOpt. Add the extended non-POSIX syntax described in "Text.Regex.TDFA" haddock documentation.- , lastStarGreedy :: Bool -- ^ False by default. This is POSIX correct but it takes space and is slower.- -- Setting this to true will improve performance, and should be done- -- if you plan to set the captureGroups ExecOption to False.+ caseSensitive :: Bool+ -- ^ True in 'blankCompOpt' and 'defaultCompOpt'.+ , multiline :: Bool+ -- ^ False in 'blankCompOpt', True in 'defaultCompOpt'.+ -- Compile for newline-sensitive matching.+ --+ -- From [regexp man page](https://www.tcl.tk/man/tcl8.4/TclCmd/regexp.html#M8):+ -- "By default, newline is a completely ordinary character with no special meaning in either REs or strings.+ -- With this flag, inverted bracket expressions @[^@ and @.@ never match newline,+ -- a @^@ anchor matches the null string after any newline in the string in addition to its normal function,+ -- and the @$@ anchor matches the null string before any newline in the string in addition to its normal function."+ , rightAssoc :: Bool+ -- ^ True (and therefore right associative) in 'blankCompOpt' and 'defaultCompOpt'.+ , newSyntax :: Bool+ -- ^ False in 'blankCompOpt', True in 'defaultCompOpt'.+ -- Enables the extended non-POSIX syntax described in "Text.Regex.TDFA" haddock documentation.+ , lastStarGreedy :: Bool+ -- ^ False by default. This is POSIX correct but it takes space and is slower.+ -- Setting this to True will improve performance, and should be done+ -- if you plan to set the 'captureGroups' 'ExecOption' to False. } deriving (Read,Show) data ExecOption = ExecOption {@@ -102,28 +110,31 @@ } deriving (Read,Show) -- | Used by implementation to name certain Postions during--- matching. Identity of Position tag to set during a transition+-- matching. Identity of Position tag to set during a transition. type Tag = Int--- | Internal use to indicate type of tag and preference for larger or smaller Positions++-- | Internal use to indicate type of tag and preference for larger or smaller Positions. data OP = Maximize | Minimize | Orbit | Ignore deriving (Eq,Show)--- | Internal NFA node identity number++-- | Internal NFA node identity number. type Index = Int--- | Internal DFA identity is this Set of NFA Index++-- | Internal DFA identity is this Set of NFA Index. type SetIndex = IntSet {- Index -}--- | Index into the text being searched++-- | Index into the text being searched. type Position = Int --- | GroupIndex is for indexing submatches from capturing--- parenthesized groups (PGroup\/Group)+-- | GroupIndex is for indexing submatches from capturing parenthesized groups ('PGroup' or 'Group'). type GroupIndex = Int--- | GroupInfo collects the parent and tag information for an instance--- of a group++-- | GroupInfo collects the parent and tag information for an instance of a group. data GroupInfo = GroupInfo { thisIndex, parentIndex :: GroupIndex , startTag, stopTag, flagTag :: Tag } deriving Show --- | The TDFA backend specific 'Regex' type, used by this module's RegexOptions and RegexMaker+-- | The TDFA backend specific 'Regex' type, used by this module's 'RegexOptions' and 'RegexMaker'. data Regex = Regex { regex_dfa :: DFA -- ^ starting DFA state , regex_init :: Index -- ^ index of starting state@@ -161,10 +172,10 @@ | WinTest WhichTest (Maybe WinEmpty) (Maybe WinEmpty) deriving Show --- | Internal NFA node type+-- | Internal NFA node type. data QNFA = QNFA {q_id :: Index, q_qt :: QT} --- | Internal to QNFA type.+-- | Internal to 'QNFA' type. data QT = Simple { qt_win :: WinTags -- ^ empty transitions to the virtual winning state , qt_trans :: CharMap QTrans -- ^ all ways to leave this QNFA to other or the same QNFA , qt_other :: QTrans -- ^ default ways to leave this QNFA to other or the same QNFA@@ -182,29 +193,38 @@ -- Also support for GNU extensions is being added: \\\` beginning of -- buffer, \\\' end of buffer, \\\< and \\\> for begin and end of words, \\b -- and \\B for word boundary and not word boundary.-data WhichTest = Test_BOL | Test_EOL -- '^' and '$' (affected by multiline option)- | Test_BOB | Test_EOB -- \` and \' begin and end buffer- | Test_BOW | Test_EOW -- \< and \> begin and end word- | Test_EdgeWord | Test_NotEdgeWord -- \b and \B word boundaries+data WhichTest+ = Test_BOL -- ^ @^@ (affected by multiline option)+ | Test_EOL -- ^ @$@ (affected by multiline option)+ | Test_BOB -- ^ @\\`@ beginning of buffer+ | Test_EOB -- ^ @\\'@ end ofbuffer+ | Test_BOW -- ^ @\\<@ beginning of word+ | Test_EOW -- ^ @\\>@ end of word+ | Test_EdgeWord -- ^ @\\b@ word boundary+ | Test_NotEdgeWord -- ^ @\\B@ not word boundary deriving (Show,Eq,Ord,Enum) --- | The things that can be done with a Tag. TagTask and--- ResetGroupStopTask are for tags with Maximize or Minimize OP--- values. ResetOrbitTask and EnterOrbitTask and LeaveOrbitTask are+-- | The things that can be done with a Tag. 'TagTask' and+-- 'ResetGroupStopTask' are for tags with Maximize or Minimize OP+-- values. 'ResetOrbitTask' and 'EnterOrbitTask' and 'LeaveOrbitTask' are -- for tags with Orbit OP value. data TagTask = TagTask | ResetGroupStopTask | SetGroupStopTask | ResetOrbitTask | EnterOrbitTask | LeaveOrbitTask deriving (Show,Eq) --- | Ordered list of tags and their associated Task+-- | Ordered list of tags and their associated Task. type TagTasks = [(Tag,TagTask)]+ -- | When attached to a QTrans the TagTask can be done before or after -- accepting the character. data TagUpdate = PreUpdate TagTask | PostUpdate TagTask deriving (Show,Eq)+ -- | Ordered list of tags and their associated update operation. type TagList = [(Tag,TagUpdate)]+ -- | A TagList and the location of the item in the original pattern -- that is being accepted. type TagCommand = (DoPa,TagList)+ -- | Ordered list of tags and their associated update operation to -- perform on an empty transition to the virtual winning state. type WinTags = TagList@@ -227,26 +247,25 @@ } -- | Internal type to represent the commands for the tagged transition.--- The outer IntMap is for the destination Index and the inner IntMap+-- The outer 'IntMap' is for the destination Index and the inner 'IntMap' -- is for the Source Index. This is convenient since all runtime data -- going to the same destination must be compared to find the best. ----- A Destination IntMap entry may have an empty Source IntMap if and--- only if the destination is the starting index and the NFA\/DFA.+-- A Destination 'IntMap' entry may have an empty Source 'IntMap' if and+-- only if the destination is the starting index and the NFA or DFA. -- This instructs the matching engine to spawn a new entry starting at -- the post-update position. type DTrans = IntMap {- Index of Destination -} (IntMap {- Index of Source -} (DoPa,Instructions)) -- type DTrans = IntMap {- Index of Destination -} (IntMap {- Index of Source -} (DoPa,RunState ()))--- | Internal convenience type for the text display code++-- | Internal convenience type for the text display code. type DTrans' = [(Index, [(Index, (DoPa, ([(Tag, (Position,Bool))],[String])))])] --- | Positions for which a * was re-started while looping. Need to+-- | Positions for which a @*@ was re-started while looping. Need to -- append locations at back but compare starting with front, so use--- Seq as a Queue. The initial position is saved in basePos (and a--- Maximize Tag), the middle positions in the Seq, and the final+-- 'Seq' as a queue. The initial position is saved in 'basePos' (and a+-- Maximize Tag), the middle positions in the 'Seq', and the final -- position is NOT saved in the Orbits (only in a Maximize Tag).------ The original code is being written XXX TODO document it. data Orbits = Orbits { inOrbit :: !Bool -- True if enterOrbit, False if LeaveOrbit , basePos :: Position
lib/Text/Regex/TDFA/ReadRegex.hs view
@@ -1,24 +1,32 @@-{-# OPTIONS_GHC -fno-warn-missing-signatures #-} -- | This is a POSIX version of parseRegex that allows NUL characters. -- Lazy\/Possessive\/Backrefs are not recognized. Anchors \^ and \$ are -- recognized. ----- The PGroup returned always have (Maybe GroupIndex) set to (Just _)--- and never to Nothing.+-- A 'PGroup' returned always has @(Maybe 'GroupIndex')@ set to @(Just _)@+-- and never to @Nothing@.+ module Text.Regex.TDFA.ReadRegex (parseRegex) where {- By Chris Kuklewicz, 2007. BSD License, see the LICENSE file. -} import Text.Regex.TDFA.Pattern {- all -} import Text.ParserCombinators.Parsec((<|>), (<?>),- unexpected, try, runParser, many, getState, setState, CharParser, ParseError,+ try, runParser, many, getState, setState, CharParser, ParseError, sepBy1, option, notFollowedBy, many1, lookAhead, eof, between, string, noneOf, digit, char, anyChar)-import Control.Monad(liftM, when, guard)++import Control.Monad (liftM, guard)++import Data.Foldable (asum) import qualified Data.Set as Set(fromList) --- | BracketElement is internal to this module-data BracketElement = BEChar Char | BEChars String | BEColl String | BEEquiv String | BEClass String+-- | An element inside @[...]@, denoting a character class.+data BracketElement+ = BEChar Char -- ^ A single character.+ | BERange Char Char -- ^ A character range (e.g. @a-z@).+ | BEColl String -- ^ @foo@ in @[.foo.]@.+ | BEEquiv String -- ^ @bar@ in @[=bar=]@.+ | BEClass String -- ^ A POSIX character class (candidate), e.g. @alpha@ parsed from @[:alpha:]@. -- | Return either an error message or a tuple of the Pattern and the -- largest group index and the largest DoPa index (both have smallest@@ -30,37 +38,46 @@ (lastGroupIndex,lastDopa) <- getState return (pat,(lastGroupIndex,DoPa lastDopa))) (0,0) x x -p_regex :: CharParser (GroupIndex,Int) Pattern+type P = CharParser (GroupIndex, Int)++p_regex :: P Pattern p_regex = liftM POr $ sepBy1 p_branch (char '|') -- man re_format helps a lot, it says one-or-more pieces so this is -- many1 not many. Use "()" to indicate an empty piece.+p_branch :: P Pattern p_branch = liftM PConcat $ many1 p_piece +p_piece :: P Pattern p_piece = (p_anchor <|> p_atom) >>= p_post_atom -- correct specification +p_atom :: P Pattern p_atom = p_group <|> p_bracket <|> p_char <?> "an atom" -group_index :: CharParser (GroupIndex,Int) (Maybe GroupIndex)+group_index :: P (Maybe GroupIndex) group_index = do (gi,ci) <- getState let index = succ gi setState (index,ci) return (Just index) +p_group :: P Pattern p_group = lookAhead (char '(') >> do index <- group_index liftM (PGroup index) $ between (char '(') (char ')') p_regex -- p_post_atom takes the previous atom as a parameter+p_post_atom :: Pattern -> P Pattern p_post_atom atom = (char '?' >> return (PQuest atom)) <|> (char '+' >> return (PPlus atom)) <|> (char '*' >> return (PStar True atom)) <|> p_bound atom <|> return atom +p_bound :: Pattern -> P Pattern p_bound atom = try $ between (char '{') (char '}') (p_bound_spec atom) +p_bound_spec :: Pattern -> P Pattern p_bound_spec atom = do lowS <- many1 digit let lowI = read lowS highMI <- option (Just lowI) $ try $ do@@ -76,6 +93,7 @@ return (PBound lowI highMI atom) -- An anchor cannot be modified by a repetition specifier+p_anchor :: P Pattern p_anchor = (char '^' >> liftM PCarat char_index) <|> (char '$' >> liftM PDollar char_index) <|> try (do _ <- string "()"@@ -83,11 +101,13 @@ return $ PGroup index PEmpty) <?> "empty () or anchor ^ or $" +char_index :: P DoPa char_index = do (gi,ci) <- getState let ci' = succ ci setState (gi,ci') return (DoPa ci') +p_char :: P Pattern p_char = p_dot <|> p_left_brace <|> p_escaped <|> p_other_char where p_dot = char '.' >> char_index >>= return . PDot p_left_brace = try $ (char '{' >> notFollowedBy digit >> char_index >>= return . (`PChar` '{'))@@ -96,16 +116,18 @@ where specials = "^.[$()|*+?{\\" -- parse [bar] and [^bar] sets of characters+p_bracket :: P Pattern p_bracket = (char '[') >> ( (char '^' >> p_set True) <|> (p_set False) ) --- p_set :: Bool -> GenParser Char st Pattern+p_set :: Bool -> P Pattern p_set invert = do initial <- (option "" ((char ']' >> return "]") <|> (char '-' >> return "-"))) values <- if null initial then many1 p_set_elem else many p_set_elem _ <- char ']' ci <- char_index- let chars = maybe'set $ initial- ++ [c | BEChar c <- values ]- ++ concat [s | BEChars s <- values ]+ let chars = maybe'set $ concat $+ initial :+ [ c | BEChar c <- values ] :+ [ [start..end] | BERange start end <- values ] colls = maybe'set [PatternSetCollatingElement coll | BEColl coll <- values ] equivs = maybe'set [PatternSetEquivalenceClass equiv | BEEquiv equiv <- values] class's = maybe'set [PatternSetCharacterClass a'class | BEClass a'class <- values]@@ -115,31 +137,57 @@ -- From here down the code is the parser and functions for pattern [ ] set things -p_set_elem = p_set_elem_class <|> p_set_elem_equiv <|> p_set_elem_coll- <|> p_set_elem_range <|> p_set_elem_char <?> "Failed to parse bracketed string"+p_set_elem :: P BracketElement+p_set_elem = checkBracketElement =<< asum+ [ p_set_elem_class+ , p_set_elem_equiv+ , p_set_elem_coll+ , p_set_elem_range+ , p_set_elem_char+ , fail "Failed to parse bracketed string"+ ] +p_set_elem_class :: P BracketElement p_set_elem_class = liftM BEClass $ try (between (string "[:") (string ":]") (many1 $ noneOf ":]")) +p_set_elem_equiv :: P BracketElement p_set_elem_equiv = liftM BEEquiv $ try (between (string "[=") (string "=]") (many1 $ noneOf "=]")) +p_set_elem_coll :: P BracketElement p_set_elem_coll = liftM BEColl $ try (between (string "[.") (string ".]") (many1 $ noneOf ".]")) +p_set_elem_range :: P BracketElement p_set_elem_range = try $ do start <- noneOf "]-" _ <- char '-' end <- noneOf "]"- -- bug fix: check start <= end before "return (BEChars [start..end])"- if start <= end- then return (BEChars [start..end])- else unexpected "End point of dashed character range is less than starting point"+ return $ BERange start end +p_set_elem_char :: P BracketElement p_set_elem_char = do c <- noneOf "]"- when (c == '-') $ do- atEnd <- (lookAhead (char ']') >> return True) <|> (return False)- when (not atEnd) (unexpected "A dash is in the wrong place in a bracket") return (BEChar c) +-- | Fail when 'BracketElement' is invalid, e.g. empty range @1-0@.+-- This failure should not be caught.+--+checkBracketElement :: BracketElement -> P BracketElement+checkBracketElement e =+ case e of+ BERange start end+ | start > end -> fail $ unwords+ [ "End point"+ , show end+ , "of dashed character range is less than starting point"+ , show start+ ]+ | otherwise -> ok+ BEChar _ -> ok+ BEClass _ -> ok+ BEColl _ -> ok+ BEEquiv _ -> ok+ where+ ok = return e
regex-tdfa.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: regex-tdfa-version: 1.3.1.3+version: 1.3.1.4 build-Type: Simple license: BSD3@@ -46,7 +46,7 @@ source-repository this type: git location: https://github.com/haskell-hvr/regex-tdfa.git- tag: v1.3.1.3+ tag: v1.3.1.4 flag force-O2 default: False@@ -173,3 +173,16 @@ if flag(force-O2) ghc-options: -O2++test-suite doc-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: DocTestMain.hs++ build-depends:+ base+ , regex-tdfa+ , doctest-parallel >= 0.2.2+ -- doctest-parallel-0.2.2 is the first to filter out autogen-modules++ default-language: Haskell2010
+ test/DocTestMain.hs view
@@ -0,0 +1,16 @@+module Main where++import System.Environment+ ( getArgs )+import Test.DocTest+ ( mainFromLibrary )+import Test.DocTest.Helpers+ ( extractSpecificCabalLibrary, findCabalPackage )++main :: IO ()+main = do+ args <- getArgs+ pkg <- findCabalPackage "regex-tdfa"+ -- Need to give the library name, otherwise the parser does not find it.+ lib <- extractSpecificCabalLibrary Nothing pkg+ mainFromLibrary lib args