regexdot 0.11.1.0 → 0.11.1.1
raw patch · 17 files changed
+263/−323 lines, 17 filesdep ~parallelsetup-changedPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: parallel
API changes (from Hackage documentation)
Files
- Setup.hs +2/−2
- changelog +5/−0
- makefile +3/−3
- regexdot.cabal +8/−27
- src/RegExDot/Anchor.hs +8/−13
- src/RegExDot/BracketExpressionMember.hs +8/−14
- src/RegExDot/Consumer.hs +1/−1
- src/RegExDot/ConsumptionProfile.hs +10/−9
- src/RegExDot/DSL.hs +1/−1
- src/RegExDot/DataSpanTree.hs +3/−4
- src/RegExDot/ExecutionOptions.hs +9/−9
- src/RegExDot/Meta.hs +12/−18
- src/RegExDot/RegEx.hs +165/−178
- src/RegExDot/Repeatable.hs +17/−22
- src/RegExDot/ShowablePredicate.hs +4/−9
- src/RegExDot/Span.hs +2/−2
- src/RegExDot/Tree.hs +5/−11
Setup.hs view
@@ -1,5 +1,5 @@ #!/usr/bin/env runhaskell -import qualified Distribution.Simple+import qualified Distribution.Simple -main = Distribution.Simple.defaultMain+main = Distribution.Simple.defaultMain
changelog view
@@ -40,3 +40,8 @@ * Removed 'Show' from the context of functions in "RegExDot.RegEx" * Exported a new constant 'RegExDot.Anchor.unanchored'. * Refactored 'RegExDot.ConsumptionProfile.withinConsumptionBounds'.+0.11.1.1+ * Tested with 'haskell-platform-2013.2.0.0'.+ * Replaced preprocessor-directives with 'build-depends' constraints in 'regexdot.cabal'.+ * In function 'RegExDot.RegEx.findMatch.findMatchSlave.matchPairList', changed 'fromIntegral' (which required a type-signature) to 'toRational'.+ * Either replaced instances of '(<$>)' with 'fmap' to avoid ambiguity between "Control.Applicative" & "Prelude" which (from 'base-4.8') also exports this symbol, or hid the symbol when importing the "Prelude"..
makefile view
@@ -1,4 +1,4 @@-# Copyright (C) 2010 Dr. Alistair Ward+# Copyright (C) 2010-2014 Dr. Alistair Ward # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by@@ -40,10 +40,10 @@ PATH=~/.cabal/bin:$$PATH runhaskell Setup $@ --hyperlink-source #Amend path to find 'HsColour', as required for 'hyperlink-source'. hlint:- @$@ -i 'Use &&' src/ -i 'Use ||'+ @$@ -i 'Use &&' src/ -i 'Use ||' +RTS -N sdist:- runhaskell Setup $@+ TAR_OPTIONS='--format=ustar' runhaskell Setup $@ check: sdist cabal upload --check --verbose=3 dist/*.tar.gz;
regexdot.cabal view
@@ -1,8 +1,8 @@---Package-properties+-- Package-properties Name: regexdot-Version: 0.11.1.0+Version: 0.11.1.1 Cabal-Version: >= 1.6-Copyright: (C) 2010 Dr. Alistair Ward+Copyright: (C) 2010-2015 Dr. Alistair Ward License: GPL License-file: LICENSE Author: Dr. Alistair Ward@@ -11,25 +11,18 @@ Build-Type: Simple Description: Provides a portable, POSIX, extended regex-engine, designed to process a list of /arbitrary/ objects. Category: Search, Regex-Tested-With: GHC == 6.10, GHC == 6.12, GHC == 7.0, GHC == 7.4+Tested-With: GHC == 6.10, GHC == 6.12, GHC == 7.0, GHC == 7.4, GHC == 7.6, GHC == 7.10 Homepage: http://functionalley.eu Maintainer: regexdot <at> functionalley <dot> eu Bug-reports: regexdot <at> functionalley <dot> eu Extra-Source-Files: changelog, copyright, makefile -flag haveDeepSeq- Description: Import the type-class 'NFData' from module 'Control.DeepSeq' rather than 'Control.Parallel.Strategies'.- Default: True-+-- Turn on using: 'runhaskell ./Setup.hs configure -f llvm'. flag llvm Description: Whether the 'llvm' compiler-backend has been installed and is required for code-generation. manual: True default: False -flag threaded- Description: Enable parallelized code.- default: True- Library hs-source-dirs: src @@ -57,29 +50,17 @@ Build-depends: base == 4.*,+ deepseq >= 1.1,+ parallel >= 3.0, parsec == 3.*, toolshed >= 0.13 - GHC-options: -Wall -O2+ GHC-options: -Wall -O2 -fno-warn-tabs if impl(ghc >= 7.4.1) GHC-prof-options: -prof -fprof-auto -fprof-cafs else GHC-prof-options: -prof -auto-all -caf-all-- if flag(haveDeepSeq)- Build-depends: deepseq >= 1.1- CPP-options: -DHAVE_DEEPSEQ- else- Build-depends: parallel == 1.*-- if flag(threaded)- Build-depends: parallel >= 3.0-- if impl(ghc >= 6.12)- GHC-options: -feager-blackholing- else- Build-depends: parallel if impl(ghc >= 7.0) && flag(llvm) GHC-options: -fllvm
src/RegExDot/Anchor.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2010 Dr. Alistair Ward @@ -43,11 +42,7 @@ unanchored ) where -#ifdef HAVE_DEEPSEQ-import Control.DeepSeq(NFData, rnf)-#else-import Control.Parallel.Strategies(NFData, rnf)-#endif+import qualified Control.DeepSeq -- | Defines the types on /anchor/ by which a /regex/ can be moored to a part of the input-data. data Anchor =@@ -55,8 +50,8 @@ | Stern -- ^ Matches only if no input data remains to be consumed. Can only exist at the end of the entire regex, or (in theory) the end of any /alternative/. deriving ( Eq--- Read, --See specialisation below.--- Show --See specialisation below.+-- Read, -- See specialisation below.+-- Show -- See specialisation below. ) instance Show Anchor where@@ -64,14 +59,14 @@ showsPrec _ Stern = showChar sternToken instance Read Anchor where- readsPrec _ [] = [] --No parse.- readsPrec _ (' ' : s) = reads s --Consume white-space.- readsPrec _ ('\t' : s) = reads s --Consume white-space.+ readsPrec _ [] = [] -- No parse.+ readsPrec _ (' ' : s) = reads s -- Consume white-space.+ readsPrec _ ('\t' : s) = reads s -- Consume white-space. readsPrec _ (c : s) = case c `lookup` [(bowToken, Bow), (sternToken, Stern)] of Just anchor -> [(anchor, s)]- _ -> [] --No parse.+ _ -> [] -- No parse. -instance NFData Anchor where+instance Control.DeepSeq.NFData Anchor where rnf _ = () -- | The conventional token used to denote a 'Bow'-anchor, when in 'String'-form.
src/RegExDot/BracketExpressionMember.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2010 Dr. Alistair Ward @@ -41,15 +40,10 @@ ) where import qualified Control.Arrow+import qualified Control.DeepSeq import qualified RegExDot.ShowablePredicate as ShowablePredicate -#ifdef HAVE_DEEPSEQ-import Control.DeepSeq(NFData, rnf)-#else-import Control.Parallel.Strategies(NFData, rnf)-#endif--infix 4 =~ --Same as (==).+infix 4 =~ -- Same as (==). {- | * The interface via which /Perl-style shortcut/s are expanded (when they occur within a /bracket-expression/), in a manner appropriate to the chosen type-parameter.@@ -77,17 +71,17 @@ showsPrec _ (Literal literal) = shows literal instance (ShortcutExpander m, Read m) => Read (Member m) where- readsPrec _ [] = [] --No parse.- readsPrec _ (' ' : s) = reads s --Consume white-space.- readsPrec _ ('\t' : s) = reads s --Consume white-space.+ readsPrec _ [] = [] -- No parse.+ readsPrec _ (' ' : s) = reads s -- Consume white-space.+ readsPrec _ ('\t' : s) = reads s -- Consume white-space. readsPrec _ ('\\' : shortcut : s) = case findPredicate shortcut of Just showablePredicate -> [(Predicate showablePredicate, s)] _ -> error $ "readsPrec RegExDot.BracketExpressionMember.Member:\tfindPredicate failed for shortcut " ++ show shortcut readsPrec _ literal = Control.Arrow.first Literal `map` reads literal -instance NFData m => NFData (Member m) where- rnf (Predicate showablePredicate) = rnf showablePredicate- rnf (Literal literal) = rnf literal+instance Control.DeepSeq.NFData m => Control.DeepSeq.NFData (Member m) where+ rnf (Predicate showablePredicate) = Control.DeepSeq.rnf showablePredicate+ rnf (Literal literal) = Control.DeepSeq.rnf literal -- | Match-operator. (=~) :: Eq m
src/RegExDot/Consumer.hs view
@@ -101,5 +101,5 @@ -- | Get the 'ConsumptionProfile.ConsumptionProfile' for the specified list of 'Consumer's, then accumulate them. accumulateConsumptionProfiles :: Consumer c => [c] -> ConsumptionProfile.AccumulatedConsumptionProfiles-accumulateConsumptionProfiles = {-init .-} accumulateConsumptionProfilesFrom ConsumptionProfile.zero --It's useful to leave the initial value at the end of the list.+accumulateConsumptionProfiles = {-init .-} accumulateConsumptionProfilesFrom ConsumptionProfile.zero -- It's useful to leave the initial value at the end of the list.
src/RegExDot/ConsumptionProfile.hs view
@@ -1,5 +1,5 @@ {-- Copyright (C) 2010 Dr. Alistair Ward+ Copyright (C) 2010-2015 Dr. Alistair Ward This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by@@ -42,6 +42,7 @@ withinConsumptionBounds ) where +import Prelude hiding ((<$>), (<*>)) -- The "Prelude" from 'base-4.8' exports this symbol. import Control.Applicative((<$>), (<*>)) import Control.Arrow((***)) import qualified Data.List@@ -49,8 +50,8 @@ import qualified RegExDot.ConsumptionBounds as ConsumptionBounds import qualified ToolShed.SelfValidate -infixr 5 |+| --Same as (++).-infixr 2 <> --Same as (||).+infixr 5 |+| -- Same as (++).+infixr 2 <> -- Same as (||). {- | * A 'Consumer' is considered to have a 'ConsumptionProfile' composed from both a capacity to consume, & an ability to discriminate.@@ -113,9 +114,9 @@ hasSpecificRequirement = rh, canConsumeAnything = rc } = MkConsumptionProfile {- consumptionBounds = (lf + rf, (+) <$> ls <*> rs), --The sum of those of the concatenation.- hasSpecificRequirement = lh || rh, --The concatenation mandates consumption of at least one specific input datum, if either 'ConsumptionProfile' does.- canConsumeAnything = lc || rc --The concatenation can consume at least one arbitrary input datum, if either 'ConsumptionProfile' can.+ consumptionBounds = (lf + rf, (+) <$> ls <*> rs), -- The sum of those of the concatenation.+ hasSpecificRequirement = lh || rh, -- The concatenation mandates consumption of at least one specific input datum, if either 'ConsumptionProfile' does.+ canConsumeAnything = lc || rc -- The concatenation can consume at least one arbitrary input datum, if either 'ConsumptionProfile' can. } -- | The net effect of two alternative 'ConsumptionProfile's.@@ -129,9 +130,9 @@ hasSpecificRequirement = rh, canConsumeAnything = rc } = MkConsumptionProfile {- consumptionBounds = (lf `min` rf, max <$> ls <*> rs), --Stretched to envelope alternatives.- hasSpecificRequirement = lh && rh, --The alternation mandates consumption of at least one specific input datum, if both 'ConsumptionProfile's do.- canConsumeAnything = lc || rc --The alternation can consume at least one arbitrary input datum, if either 'ConsumptionProfile' can.+ consumptionBounds = (lf `min` rf, max <$> ls <*> rs), -- Stretched to envelope alternatives.+ hasSpecificRequirement = lh && rh, -- The alternation mandates consumption of at least one specific input datum, if both 'ConsumptionProfile's do.+ canConsumeAnything = lc || rc -- The alternation can consume at least one arbitrary input datum, if either 'ConsumptionProfile' can. } -- | The aggregate of the specified concatenation of 'ConsumptionProfile's.
src/RegExDot/DSL.hs view
@@ -51,7 +51,7 @@ import qualified RegExDot.RegEx as RegEx import qualified RegExDot.Repeatable as Repeatable -infixr 5 -:, ?:, ??:, *:, *?:, +:, +?:,#->#:, #->#?:, #->:, #->?:, #:, <~> --Same as for ':', & lower than Repeatable's operators.+infixr 5 -:, ?:, ??:, *:, *?:, +:, +?:,#->#:, #->#?:, #->:, #->?:, #:, <~> -- Same as for ':', & lower than Repeatable's operators. -- | Prepend an unrepeated 'RegEx.Pattern', to the specified 'RegEx.Concatenation'. (-:) :: RegEx.Pattern a -> RegEx.Concatenation a -> RegEx.Concatenation a
src/RegExDot/DataSpanTree.hs view
@@ -1,5 +1,5 @@ {-- Copyright (C) 2010 Dr. Alistair Ward+ Copyright (C) 2010-2015 Dr. Alistair Ward This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by@@ -31,7 +31,6 @@ toTreeList ) where -import Control.Applicative((<$>)) import qualified Data.Foldable import qualified RegExDot.ConsumptionBounds as ConsumptionBounds import qualified RegExDot.DataSpan as DataSpan@@ -48,7 +47,7 @@ toTreeList :: RegEx.MatchList a -> DataSpanTreeList a toTreeList = map toTree where toTree :: RegEx.Match a -> DataSpanTree a- toTree = (toDataSpan <$>) where+ toTree = fmap toDataSpan where toDataSpan :: RegEx.MatchedData a -> DataSpan.DataSpan a toDataSpan (_, inputDataOffset, inputData) = (inputData, (inputDataOffset, length inputData)) @@ -99,7 +98,7 @@ recurseHorizontallyFrom = (`extractCaptureGroups'` treeList) in case tree of Tree.Leaf dataSpan -> recurseHorizontallyFrom $ DataSpan.after dataSpan- Tree.Node [] -> DataSpan.empty (if complyStrictlyWithPosix then -1 else offset) : recurseHorizontallyFrom offset --POSIX specifies an Span-offset of -1, for sub-expressions which match 0 times; cf sub-expressions which consumes nothing, once.+ Tree.Node [] -> DataSpan.empty (if complyStrictlyWithPosix then -1 else offset) : recurseHorizontallyFrom offset -- POSIX specifies an Span-offset of -1, for sub-expressions which match 0 times; cf sub-expressions which consumes nothing, once. Tree.Node treeLists -> joinedFlattenedTreeList : (extractCaptureGroups' offset lastMatch {-recurse vertically-} ++ recurseHorizontallyFrom (DataSpan.after joinedFlattenedTreeList)) where -- lastMatch :: DataSpanTreeList a lastMatch = last treeLists -- <http://www.opengroup.org/onlinepubs/009695399/functions/regcomp.html>.
src/RegExDot/ExecutionOptions.hs view
@@ -59,17 +59,17 @@ instance ToolShed.Defaultable.Defaultable ExecutionOptions where defaultValue = setVerbose False $ ToolShed.Options.blankValue {- abortTrialRepetitionsOnInherentFailure = True, --Regrettably, this slightly reduces performance for most non-pathological patterns.+ abortTrialRepetitionsOnInherentFailure = True, -- Regrettably, this slightly reduces performance for most non-pathological patterns. catchIncompatibleAnchors = True, checkExistenceOfInelasticTail = True,- checkForUnconsumableData = True, --Expensive, particularly when (not requireMatchList), & only typically useful in failure-scenarios.- moderateGreed = True, --Cost may exceed benefit. TODO: confirm.+ checkForUnconsumableData = True, -- Expensive, particularly when (not requireMatchList), & only typically useful in failure-scenarios.+ moderateGreed = True, -- Cost may exceed benefit. TODO: confirm. preferAlternativesWhichFeedTheGreedy = True, preferAlternativesWhichMimickUnrolling = True, preferFewerRepeatedAlternatives = True,- unrollRepeatedSingletonAlternative = True, --Affects only efficiency, not the result.- useFirstMatchAmongAlternatives = False, --Perl-style matching may be faster, but may also yield a sub-optimal Match.- validateMinConsumptionOfAlternatives = False --The cost outweighs the small infrequent dividend.+ unrollRepeatedSingletonAlternative = True, -- Affects only efficiency, not the result.+ useFirstMatchAmongAlternatives = False, -- Perl-style matching may be faster, but may also yield a sub-optimal Match.+ validateMinConsumptionOfAlternatives = False -- The cost outweighs the small infrequent dividend. } instance ToolShed.Options.Options ExecutionOptions where@@ -94,9 +94,9 @@ -- | Sets those fields which depend crucially on whether the caller wants to retrieve any /RegExDot.RegEx.MatchList/ from the /RegExDot.RegEx.Result/, or just query whether there is one. setVerbose :: Bool -> ExecutionOptions -> ExecutionOptions setVerbose verbose e = e {- abortTrialRepetitionsOnZeroConsumption = verbose, --The corresponding check, involves evaluation of a /RegExDot.RegEx.MatchList/, which is too expensive if the /RegExDot.RegEx.Matchlist/ isn't otherwise required.- bypassInputDataForLiberalConsumer = not verbose, --Potentially bypasses reading of /RegExDot.RegEx.InputData/, which is inappropriate if the mapping into a /RegExDot.RegEx.Result/ is required.- permitReorderingOfAlternatives = not verbose, --Doesn't help when 'requireMatchList', since an exhaustive search of /RegExDot.RegEx.Alternatives/, for the optimal solution, is performed.+ abortTrialRepetitionsOnZeroConsumption = verbose, -- The corresponding check, involves evaluation of a /RegExDot.RegEx.MatchList/, which is too expensive if the /RegExDot.RegEx.Matchlist/ isn't otherwise required.+ bypassInputDataForLiberalConsumer = not verbose, -- Potentially bypasses reading of /RegExDot.RegEx.InputData/, which is inappropriate if the mapping into a /RegExDot.RegEx.Result/ is required.+ permitReorderingOfAlternatives = not verbose, -- Doesn't help when 'requireMatchList', since an exhaustive search of /RegExDot.RegEx.Alternatives/, for the optimal solution, is performed. requireMatchList = verbose }
src/RegExDot/Meta.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2010 Dr. Alistair Ward @@ -48,6 +47,7 @@ ) where import qualified Control.Arrow+import qualified Control.DeepSeq import qualified RegExDot.BracketExpression as BracketExpression import qualified RegExDot.BracketExpressionMember as BracketExpressionMember import qualified RegExDot.Consumer as Consumer@@ -55,12 +55,6 @@ import qualified RegExDot.ShowablePredicate as ShowablePredicate import qualified ToolShed.SelfValidate -#ifdef HAVE_DEEPSEQ-import Control.DeepSeq(NFData, rnf)-#else-import Control.Parallel.Strategies(NFData, rnf)-#endif- {- | * The interface via which /Perl-style shortcut/s are expanded, in a manner appropriate to the chosen type-parameter. @@ -79,8 +73,8 @@ | Predicate (ShowablePredicate.ShowablePredicate m) -- ^ The datum matches if 'ShowablePredicate.ShowablePredicate'. deriving ( Eq--- Read, --Specialised below.--- Show --Specialised below.+-- Read, -- Specialised below.+-- Show -- Specialised below. ) instance ToolShed.SelfValidate.SelfValidator (Meta m) where@@ -94,9 +88,9 @@ showsPrec _ (Predicate showablePredicate) = shows showablePredicate instance (ShortcutExpander m, Read m) => Read (Meta m) where- readsPrec _ [] = [] --No parse.- readsPrec _ (' ' : s) = reads s --Consume white-space.- readsPrec _ ('\t' : s) = reads s --Consume white-space.+ readsPrec _ [] = [] -- No parse.+ readsPrec _ (' ' : s) = reads s -- Consume white-space.+ readsPrec _ ('\t' : s) = reads s -- Consume white-space. readsPrec _ ('.' : s) = [(Any, s)] readsPrec _ ('[' : '^' : noneOf) = Control.Arrow.first NoneOf `map` reads (fst BracketExpression.delimiterTokens : noneOf) {-Reconstruct without negation, & recurse-} readsPrec _ anyOf@('[' : _) = Control.Arrow.first AnyOf `map` reads anyOf {-singleton-}@@ -118,12 +112,12 @@ starHeight _ = 0 -instance NFData m => NFData (Meta m) where+instance Control.DeepSeq.NFData m => Control.DeepSeq.NFData (Meta m) where rnf Any = ()- rnf (Literal m) = rnf m- rnf (AnyOf bracketExpression) = rnf bracketExpression- rnf (NoneOf bracketExpression) = rnf bracketExpression- rnf (Predicate showablePredicate) = rnf showablePredicate+ rnf (Literal m) = Control.DeepSeq.rnf m+ rnf (AnyOf bracketExpression) = Control.DeepSeq.rnf bracketExpression+ rnf (NoneOf bracketExpression) = Control.DeepSeq.rnf bracketExpression+ rnf (Predicate showablePredicate) = Control.DeepSeq.rnf showablePredicate -- | True if the specified datum matches. isMatch :: Eq m@@ -133,7 +127,7 @@ isMatch _ Any = True isMatch datum (Literal literal) = datum == literal isMatch datum (AnyOf bracketExpression) = datum `BracketExpression.containsMatch` bracketExpression-isMatch datum (NoneOf bracketExpression) = not $ datum `isMatch` AnyOf bracketExpression --This implementation leverages future enhancements to 'AnyOf'.+isMatch datum (NoneOf bracketExpression) = not $ datum `isMatch` AnyOf bracketExpression -- This implementation leverages future enhancements to 'AnyOf'. isMatch datum (Predicate showablePredicate) = ShowablePredicate.predicate showablePredicate datum -- | The token used to precede a /Perl-style shortcut/, when in the 'String'-form.
src/RegExDot/RegEx.hs view
@@ -1,6 +1,5 @@-{-# LANGUAGE CPP #-} {-- Copyright (C) 2010 Dr. Alistair Ward+ Copyright (C) 2010-2015 Dr. Alistair Ward This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by@@ -86,7 +85,7 @@ * Test parallel-operation, on a 3 or more processor machine. If 'rnf' is less effective than 'rwhnf',- then the 'NFData' context can be removed,+ then the 'Control.DeepSeq.NFData' context can be removed, reducing the requirements imposed on the type-parameter 'a'. * Try 'Data.List.Stream' (stream-fusion), a faster drop-in replacement for 'Data.List'; possibly integrated in GHC-6.12.@@ -178,9 +177,10 @@ extractDataFromMatchList ) where -import Control.Applicative((<$>)) import Control.Arrow((&&&)) import qualified Control.Arrow+import qualified Control.DeepSeq+import qualified Control.Parallel.Strategies import qualified Data.Char import qualified Data.Foldable import qualified Data.List@@ -200,17 +200,7 @@ import qualified ToolShed.Data.List.Splits import qualified ToolShed.SelfValidate -#if MIN_VERSION_parallel(3,0,0)-import qualified Control.Parallel.Strategies-#endif--#ifdef HAVE_DEEPSEQ-import Control.DeepSeq(NFData, rnf)-#else-import Control.Parallel.Strategies(NFData, rnf)-#endif--infix 4 +~, =~, /~ --Same as (==) & (/=).+infix 4 +~, =~, /~ -- Same as (==) & (/=). -- | The type of a /regex/, in which there's no provision for either 'Alternatives' or 'Anchor.Anchor's. type BasicRegEx m = [Repeatable.Repeatable (Meta.Meta m)]@@ -247,26 +237,26 @@ Eq m, Read m ) => Read (Alternatives m) where- readsPrec _ (' ' : s) = reads s --Consume white-space.- readsPrec _ ('\t' : s) = reads s --Consume white-space.+ readsPrec _ (' ' : s) = reads s -- Consume white-space.+ readsPrec _ ('\t' : s) = reads s -- Consume white-space. readsPrec _ s = case reads s of [(extendedRegEx, s1)] -> case dropWhile Data.Char.isSpace s1 of ('|' : s2) -> Control.Arrow.first (transformAlternatives (extendedRegEx :)) `map` reads s2 {-singleton-} _ -> [(MkAlternatives [extendedRegEx], s1)]- _ -> [] --No parse.+ _ -> [] -- No parse. instance Show m => Show (Alternatives m) where- showsPrec _ = foldl (.) (showString "") . Data.List.intersperse (showChar alternativeExtendedRegExSeparatorToken) . map shows . deconstructAlternatives --Replace the default list-format, with 'egrep'-syntax.+ showsPrec _ = foldl (.) (showString "") . Data.List.intersperse (showChar alternativeExtendedRegExSeparatorToken) . map shows . deconstructAlternatives -- Replace the default list-format, with 'egrep'-syntax. instance Consumer.Consumer (Alternatives m) where consumptionProfile = Consumer.aggregateConsumptionProfilesFromAlternatives . deconstructAlternatives- starHeight = Consumer.starHeight . deconstructAlternatives --Must evaluate all Alternatives to determine best.+ starHeight = Consumer.starHeight . deconstructAlternatives -- Must evaluate all Alternatives to determine best. instance ToolShed.SelfValidate.SelfValidator (Alternatives m) where getErrors = ToolShed.SelfValidate.getErrors . deconstructAlternatives -instance NFData m => NFData (Alternatives m) where- rnf = rnf . deconstructAlternatives+instance Control.DeepSeq.NFData m => Control.DeepSeq.NFData (Alternatives m) where+ rnf = Control.DeepSeq.rnf . deconstructAlternatives -- | 'Alternatives' can be employed as a simple /capture-group/ as well as a switch, under which circumstances there's no choice amongst multiple 'Alternatives'. isSingletonAlternatives :: Alternatives m -> Bool@@ -303,16 +293,16 @@ Read m, ShortcutExpander m ) => Read (Pattern m) where- readsPrec _ (' ' : s) = reads s --Consume white-space.- readsPrec _ ('\t' : s) = reads s --Consume white-space.+ readsPrec _ (' ' : s) = reads s -- Consume white-space.+ readsPrec _ ('\t' : s) = reads s -- Consume white-space. readsPrec _ ('(' : s) = case {-Alternatives.-} reads s of [(alternatives, s1)] -> case dropWhile Data.Char.isSpace s1 of (')' : s2) -> [(CaptureGroup alternatives, s2)]- _ -> [] --No parse.- _ -> [] --No parse.+ _ -> [] -- No parse.+ _ -> [] -- No parse. readsPrec _ s = case reads s of [pair] -> [Control.Arrow.first Require pair]- _ -> [] --No parse.+ _ -> [] -- No parse. instance Show m => Show (Pattern m) where showsPrec _ (Require meta) = shows meta@@ -329,9 +319,9 @@ getErrors (Require meta) = ToolShed.SelfValidate.getErrors meta getErrors (CaptureGroup alternatives) = ToolShed.SelfValidate.getErrors alternatives -instance NFData m => NFData (Pattern m) where- rnf (Require meta) = rnf meta- rnf (CaptureGroup alternatives) = rnf alternatives+instance Control.DeepSeq.NFData m => Control.DeepSeq.NFData (Pattern m) where+ rnf (Require meta) = Control.DeepSeq.rnf meta+ rnf (CaptureGroup alternatives) = Control.DeepSeq.rnf alternatives -- | Convenience-function to build a 'CaptureGroup' from a list of alternative 'ExtendedRegEx's. captureGroup :: [ExtendedRegEx m] -> Pattern m@@ -425,14 +415,14 @@ ShortcutExpander m ) => Read (ExtendedRegEx m) where readsPrec _ [] = []- readsPrec _ (' ' : s) = reads s --Consume white-space.- readsPrec _ ('\t' : s) = reads s --Consume white-space.+ readsPrec _ (' ' : s) = reads s -- Consume white-space.+ readsPrec _ ('\t' : s) = reads s -- Consume white-space. readsPrec _ ('\\' : c : s) = [(expand c, s)] readsPrec _ s = case singleton of [(extendedRegEx, _)] | ToolShed.SelfValidate.isValid extendedRegEx -> singleton- | otherwise -> error $ ToolShed.SelfValidate.getFirstError extendedRegEx --Parsed OK, but invalid.- _ -> [] --No parse.+ | otherwise -> error $ ToolShed.SelfValidate.getFirstError extendedRegEx -- Parsed OK, but invalid.+ _ -> [] -- No parse. where -- singleton :: (Eq m, Meta.ShortcutExpander m, Read m, ShortcutExpander m) => [(ExtendedRegEx m, String)] singleton = [@@ -461,9 +451,9 @@ instance Show m => Show (ExtendedRegEx m) where showsPrec _ MkExtendedRegEx {- bowAnchor = maybeBowAnchor, --CAVEAT: this could be 'Nothing' or perversely an 'Anchor.Stern'.+ bowAnchor = maybeBowAnchor, -- CAVEAT: this could be 'Nothing' or perversely an 'Anchor.Stern'. concatenation = concatenation',- sternAnchor = maybeSternAnchor --CAVEAT: this could be 'Nothing' or perversely an 'Anchor.Bow'.+ sternAnchor = maybeSternAnchor -- CAVEAT: this could be 'Nothing' or perversely an 'Anchor.Bow'. } = showsMaybeAnchor maybeBowAnchor . shows concatenation' . showsMaybeAnchor maybeSternAnchor instance Consumer.Consumer (ExtendedRegEx m) where@@ -473,12 +463,12 @@ instance ToolShed.SelfValidate.SelfValidator (ExtendedRegEx m) where getErrors = ToolShed.SelfValidate.getErrors . concatenation -instance NFData m => NFData (ExtendedRegEx m) where+instance Control.DeepSeq.NFData m => Control.DeepSeq.NFData (ExtendedRegEx m) where rnf MkExtendedRegEx { bowAnchor = maybeBowAnchor, concatenation = concatenation', sternAnchor = maybeSternAnchor- } = rnf (maybeBowAnchor, concatenation', maybeSternAnchor)+ } = Control.DeepSeq.rnf (maybeBowAnchor, concatenation', maybeSternAnchor) -- | Drop 'Anchor.Anchor's at both bow & stern of the specified 'ExtendedRegEx'. dock :: Transformation m@@ -551,11 +541,11 @@ :: ConsumptionBounds.DataLength -- ^ The offset by which to shift the position into the input-data at which a match occurred. -> Match m -- ^ The match-structure whose offset is to be shifted. -> Match m-shiftMatch i = (shiftMatchedData i <$>)+shiftMatch i = (shiftMatchedData i `fmap`) -- | Extract & concatenate, the 'InputData' from a 'Match'. extractDataFromMatch :: Match m -> InputData m-extractDataFromMatch = Data.Foldable.foldMap getInputData --Uses the List-monoid's associative binary operator (++), to concatenate the values returned by the specified function.+extractDataFromMatch = Data.Foldable.foldMap getInputData -- Uses the List-monoid's associative binary operator (++), to concatenate the values returned by the specified function. -- | Extract & concatenate, the 'InputData' from a 'Match'; null if it didn't match any. extractDataFromMatch' :: Maybe (Match m) -> InputData m@@ -574,7 +564,7 @@ -- | Extract & concatenate, the 'InputData', from the 'MatchList'. extractDataFromMatchList :: MatchList m -> InputData m-extractDataFromMatchList = concatMap extractDataFromMatch --CAVEAT: too fine-grain for effective data-parallelism.+extractDataFromMatchList = concatMap extractDataFromMatch -- CAVEAT: too fine-grain for effective data-parallelism. -- | At the top-level of an 'ExtendedRegEx', the lack of an 'Anchor.Anchor' allows the 'ExtendedRegEx' to drift away from the corresponding end of the input-data; this data-gap is captured here. type ExternalMatch m = Maybe (Match m)@@ -596,7 +586,7 @@ * One could waste a lot of time trying to consume 'InputData' from the head of a high-'Consumer.starHeight' 'ExtendedRegEx', only to find that there's a low-'Consumer.starHeight' tail that can't ever match the 'InputData'; checks this first before delegating. -}-findMatch :: (Eq m, NFData m)+findMatch :: (Eq m, Control.DeepSeq.NFData m) => RegExOpts.RegExOpts (ExtendedRegEx m) -- ^ The match-options parameterised by the regex against which to match the input data. -> InputData m -- ^ The input data within which to locate a match. -> Maybe (MatchList m)@@ -615,19 +605,19 @@ CaptureGroup alternatives | isSingletonAlternatives alternatives -> extractLowStarHeightTail {-recurse-} . head $ deconstructAlternatives alternatives | otherwise -> {-non-singleton-} []- _ -> [] --Zero 'Consumer.StarHeight' would have been detected by 'fromConcatenation'.+ _ -> [] -- Zero 'Consumer.StarHeight' would have been detected by 'fromConcatenation'. | otherwise = [] -- lowStarHeightTail :: Concatenation a lowStarHeightTail = extractLowStarHeightTail extendedRegEx in and [ ExecutionOptions.checkExistenceOfInelasticTail executionOptions,- not $ null lowStarHeightTail, --Prevent infinite recursion.+ not $ null lowStarHeightTail, -- Prevent infinite recursion. reverse originalInputData /~ RegExOpts.mkRegEx MkExtendedRegEx { bowAnchor = Just Anchor.Bow, concatenation = lowStarHeightTail, sternAnchor = Nothing- } --Check for mismatch with the corresponding tail of 'InputData'.+ } -- Check for mismatch with the corresponding tail of 'InputData'. ] = Nothing | otherwise = findMatchSlave originalConcatenation ( Consumer.accumulateConsumptionProfiles originalConcatenation@@ -647,28 +637,28 @@ Whilst the only strictly necessary parameters are the lists 'Concatenation' & 'InputData', many ancillary lists derived from them, are also passed by parameter. These are proportionally reduced on recursion, to avoid the requirement to regenerate them each time they're required. -}- findMatchSlave :: (Eq m, NFData m)- => Concatenation m --The list of 'RepeatablePattern's from which the regex is constructed.- -> ConsumptionProfile.AccumulatedConsumptionProfiles --The capacity-bounds for the consumption of 'InputData', that the 'Concatenation' extending right from any given 'RepeatablePattern', can consume.- -> [MetaDataList m] --The set of distinct 'Meta.Meta'-data, in the 'Concatenation extending right from any given 'RepeatablePattern'.- -> InputData m --The input data, which will be fed to the 'Concatenation'.- -> ConsumptionBounds.DataLength --The length of the previously specified 'InputData'.- -> [InputData m] --The set of distinct input data, extending right from any given point.+ findMatchSlave :: (Eq m, Control.DeepSeq.NFData m)+ => Concatenation m -- The list of 'RepeatablePattern's from which the regex is constructed.+ -> ConsumptionProfile.AccumulatedConsumptionProfiles -- The capacity-bounds for the consumption of 'InputData', that the 'Concatenation' extending right from any given 'RepeatablePattern', can consume.+ -> [MetaDataList m] -- The set of distinct 'Meta.Meta'-data, in the 'Concatenation extending right from any given 'RepeatablePattern'.+ -> InputData m -- The input data, which will be fed to the 'Concatenation'.+ -> ConsumptionBounds.DataLength -- The length of the previously specified 'InputData'.+ -> [InputData m] -- The set of distinct input data, extending right from any given point. -> Maybe (MatchList m)- findMatchSlave [] _ _ [] _ _ = Just [] --Simultaneous exhaustion of the 'Concatenation' of 'RepeatablePattern's & the 'InputData' => success.+ findMatchSlave [] _ _ [] _ _ = Just [] -- Simultaneous exhaustion of the 'Concatenation' of 'RepeatablePattern's & the 'InputData' => success. findMatchSlave [] _ _ _ _ _ = Nothing findMatchSlave concatenation'@(repeatablePatternHead : concatenationTail) (accumulatedConsumptionProfileHead : accumulatedConsumptionProfilesTail) (distinctMetaDataHead : distinctMetaDataTail) inputData inputDataLength distinctInputData@(distinctInputDataHead : _) | not $ inputDataLength `ConsumptionProfile.withinConsumptionBounds` accumulatedConsumptionProfileHead = Nothing- | null inputData = Just $ mkNullMatchFromConcatenation inputDataOffset concatenation' --Build a 'Match', of null 'InputData'.+ | null inputData = Just $ mkNullMatchFromConcatenation inputDataOffset concatenation' -- Build a 'Match', of null 'InputData'. | and [- ExecutionOptions.bypassInputDataForLiberalConsumer executionOptions, --We may be able to establish success, without evaluating 'inputData' any further than required to determine its length.- not $ ExecutionOptions.requireMatchList executionOptions, --Otherwise the precise mapping of the 'inputData' to 'RepeatablePattern's must be determined.- not $ ConsumptionProfile.hasSpecificRequirement accumulatedConsumptionProfileHead --Otherwise a match for the specific 'Meta'-data must be found.+ ExecutionOptions.bypassInputDataForLiberalConsumer executionOptions, -- We may be able to establish success, without evaluating 'inputData' any further than required to determine its length.+ not $ ExecutionOptions.requireMatchList executionOptions, -- Otherwise the precise mapping of the 'inputData' to 'RepeatablePattern's must be determined.+ not $ ConsumptionProfile.hasSpecificRequirement accumulatedConsumptionProfileHead -- Otherwise a match for the specific 'Meta'-data must be found. ] = Just undefined {-shouldn't be evaluated according to 'ExecutionOptions.requireMatchList'-} | and [ ExecutionOptions.checkForUnconsumableData executionOptions,- not $ ConsumptionProfile.canConsumeAnything accumulatedConsumptionProfileHead, --Otherwise the subsequent test will always fail.- (`isUnconsumableByAnyOf` distinctMetaDataHead) `any` distinctInputDataHead --Occasionally failure is both inevitable & obvious.+ not $ ConsumptionProfile.canConsumeAnything accumulatedConsumptionProfileHead, -- Otherwise the subsequent test will always fail.+ (`isUnconsumableByAnyOf` distinctMetaDataHead) `any` distinctInputDataHead -- Occasionally failure is both inevitable & obvious. ] = Nothing | otherwise = {-#SCC "findMatchSlave" #-} let tailConsumptionProfile :: ConsumptionProfile.ConsumptionProfile@@ -676,10 +666,10 @@ ConsumptionProfile.MkConsumptionProfile { ConsumptionProfile.consumptionBounds = (minConsumptionConcatenationTail, maybeMaxConsumptionConcatenationTail) }- ) = head accumulatedConsumptionProfilesTail --Extract the aggregate consumption-profile, of the tail of the 'Concatenation'.+ ) = head accumulatedConsumptionProfilesTail -- Extract the aggregate consumption-profile, of the tail of the 'Concatenation'. maxDataAvailable :: ConsumptionBounds.DataLength- maxDataAvailable = inputDataLength - minConsumptionConcatenationTail --The maximum data available to match 'repeatablePatternHead'.+ maxDataAvailable = inputDataLength - minConsumptionConcatenationTail -- The maximum data available to match 'repeatablePatternHead'. in if maxDataAvailable < 0 then Nothing else {-inputData is sufficient for concatenationTail-} let@@ -687,7 +677,7 @@ Repeatable.base = base, Repeatable.repetitionBounds = (fewest, most), Repeatable.isGreedy = isGreedy- } = repeatablePatternHead --Completely deconstruct the 'Repeatable' at the head of the 'Concatenation'.+ } = repeatablePatternHead -- Completely deconstruct the 'Repeatable' at the head of the 'Concatenation'. {- Find the maximum sequence of inputData, preceding the first of the mandatory requirements of 'concatenationTail'. This enables one to more tightly constrain the maximum number of repetitions of a 'RepeatablePattern',@@ -716,14 +706,14 @@ Repeatable.repetitionBounds = (fewestPeg, _) } : pegListTail ) inputData'- | null remainingInputData && length candidateMatchedInputData < fewestPeg = Nothing --Insufficient data to ever match.- | fewestPeg == 1 || (`Meta.isMatch` metaPeg) `all` tail candidateMatchedInputData = pegListTail `maximumDataAfterPegs` remainingInputData --Success => recurse.- | otherwise = pegList `maximumDataAfterPegs` tail candidateInputData --Failed candidate => recurse.+ | null remainingInputData && length candidateMatchedInputData < fewestPeg = Nothing -- Insufficient data to ever match.+ | fewestPeg == 1 || (`Meta.isMatch` metaPeg) `all` tail candidateMatchedInputData = pegListTail `maximumDataAfterPegs` remainingInputData -- Success => recurse.+ | otherwise = pegList `maximumDataAfterPegs` tail candidateInputData -- Failed candidate => recurse. where -- candidateInputData, candidateMatchedInputData, remainingInputData :: InputData a candidateInputData = dropWhile (not . (`Meta.isMatch` metaPeg)) inputData' (candidateMatchedInputData, remainingInputData) = fewestPeg `splitAt` candidateInputData- maximumDataAfterPegs [] inputData' = Just inputData' --All the pegs have been matched.+ maximumDataAfterPegs [] inputData' = Just inputData' -- All the pegs have been matched. {- Each 'repeatablePatternHead' can either be a 'Require' or a 'CaptureGroup'. The former case needs further reduction & we can proceed to construct a 'Tree.Leaf' from any matching 'inputData'.@@ -746,29 +736,29 @@ consumedInputDataLength = length consumedInputData in ( Tree.Leaf (repeatablePatternHead, inputDataOffset, consumedInputData) :- ) <$> {-apply to Maybe Functor-} findMatchSlave concatenationTail accumulatedConsumptionProfilesTail distinctMetaDataTail unconsumedInputData (+ ) `fmap` {-apply to Maybe Functor-} findMatchSlave concatenationTail accumulatedConsumptionProfilesTail distinctMetaDataTail unconsumedInputData ( inputDataLength - consumedInputDataLength ) ( consumedInputDataLength `drop` distinctInputData- ) --Recurse, to check whether the 'unconsumedInputData' tail also matches.+ ) -- Recurse, to check whether the 'unconsumedInputData' tail also matches. ) $ let fewestData, mostData, mostData' :: Repeatable.Repetitions fewestData = {-#SCC "fewestData" #-} case maybeMaxConsumptionConcatenationTail of- Just m -> (inputDataLength - m) {- :: ConsumptionBounds.DataLength-} `max` fewest {- :: Repeatable.Repetitions-} --CAVEAT: conceptually different types.+ Just m -> (inputDataLength - m) {- :: ConsumptionBounds.DataLength-} `max` fewest {- :: Repeatable.Repetitions-} -- CAVEAT: conceptually different types. _ -> fewest --- mostData = length . takeWhile (~= meta) $ (`take` inputData) maxData --As slow as it is concise.+-- mostData = length . takeWhile (~= meta) $ (`take` inputData) maxData -- As slow as it is concise. mostData = {-#SCC "mostData" #-} maxData - measureUnmatchableTail inputData maxData where maxData :: ConsumptionBounds.DataLength maxData = case most of- Just cap -> cap {- :: Repeatable.Repetitions-} `min` maxDataAvailable {- :: ConsumptionBounds.DataLength-} --CAVEAT: conceptually different types.+ Just cap -> cap {- :: Repeatable.Repetitions-} `min` maxDataAvailable {- :: ConsumptionBounds.DataLength-} -- CAVEAT: conceptually different types. _ -> maxDataAvailable -- measureUnmatchableTail :: InputData m -> ConsumptionBounds.DataLength -> ConsumptionBounds.DataLength- measureUnmatchableTail _ 0 = 0 --Have matched all the data.+ measureUnmatchableTail _ 0 = 0 -- Have matched all the data. measureUnmatchableTail (a : as) unmatched- | a `Meta.isMatch` meta = measureUnmatchableTail as $ pred unmatched --Recurse.- | otherwise = unmatched --Return the unmatchable tail-length.+ | a `Meta.isMatch` meta = measureUnmatchableTail as $ pred unmatched -- Recurse.+ | otherwise = unmatched -- Return the unmatchable tail-length. measureUnmatchableTail [] _ = error "RegExDot.RegEx.findMatch.findMatchSlave.maybeMatchList.mostData.measureUnmatchableTail:\tdata unexpectedly exhausted." {- 'most' has been extracted from 'repeatablePatternHead',@@ -779,14 +769,14 @@ mostData' | and [ ExecutionOptions.moderateGreed executionOptions,- isGreedy, --Otherwise, since the search proceeds from 'fewest' to 'most', the optimal solution is located before backtracking.- mostData > fewestData --Otherwise, there's no unbridled greed to moderate.+ isGreedy, -- Otherwise, since the search proceeds from 'fewest' to 'most', the optimal solution is located before backtracking.+ mostData > fewestData -- Otherwise, there's no unbridled greed to moderate. ] = case maximumDataBeforePegs of- Just maximumDataBeforePegs' -> mostData `min` length maximumDataBeforePegs' --Cap upper bound.- _ -> negate 1 --Guaranteed to be < 'fewestData'.+ Just maximumDataBeforePegs' -> mostData `min` length maximumDataBeforePegs' -- Cap upper bound.+ _ -> negate 1 -- Guaranteed to be < 'fewestData'. | otherwise {-no requirement for this optimisation-} = mostData in (- succ {-fence-post-} mostData' - fewestData --CAVEAT: possibly <= 0.+ succ {-fence-post-} mostData' - fewestData -- CAVEAT: possibly <= 0. ) `take` ( if isGreedy then ToolShed.Data.List.Splits.splitsLeftFrom mostData'@@ -796,15 +786,15 @@ CaptureGroup alternatives | and [ not isGreedy,- fewest <= 0, --Zero repetitions permissible.+ fewest <= 0, -- Zero repetitions permissible. Data.Maybe.isJust tailMatch- ] -> zeroRepetitions --Zero repetitions is the optimal solution, rendering the choice of Alternative irrelevant.+ ] -> zeroRepetitions -- Zero repetitions is the optimal solution, rendering the choice of Alternative irrelevant. | and [ ExecutionOptions.catchIncompatibleAnchors executionOptions,- fewest > 1, --Multiple repetitions.- minConsumptionAlternatives > 0, --InputData required.+ fewest > 1, -- Multiple repetitions.+ minConsumptionAlternatives > 0, -- InputData required. ($ extendedRegExAlternatives) `any` [(hasBowAnchor `all`), (hasSternAnchor `all`)]- ] -> Nothing --'extendedRegExFromAlternative' requires 'InputData', therefore 'Anchor.Bow' can only pass on the 1st repetition & 'Anchor.Stern' can only pass on the last.+ ] -> Nothing -- 'extendedRegExFromAlternative' requires 'InputData', therefore 'Anchor.Bow' can only pass on the 1st repetition & 'Anchor.Stern' can only pass on the last. | otherwise -> let {- We're about to try all repetitions of one Alternative before progressing to the next.@@ -812,13 +802,7 @@ Either way, if the user requires data-capture, then for POSIX-compliance we must perform an exhaustive search of the O(Alternatives ^ Repetitions) permutations for the optimal solution; though the search may be narrowed as we proceed. -} -- matchPairList :: [(Match m, MatchList m)]- matchPairList = {-#SCC "matchPairList" #-} Data.Maybe.catMaybes .-#if MIN_VERSION_parallel(3,0,0)- concat . Control.Parallel.Strategies.parMap Control.Parallel.Strategies.rseq --Particularly effective when 'not ExecutionOptions.requireMatchList'.-#else- concatMap-#endif- (+ matchPairList = {-#SCC "matchPairList" #-} Data.Maybe.catMaybes . concat . Control.Parallel.Strategies.parMap Control.Parallel.Strategies.rseq {-Particularly effective when 'not ExecutionOptions.requireMatchList' -} ( -- :: ExtendedRegEx m -> [Maybe (Match m, MatchList m)] \extendedRegExFromAlternative@MkExtendedRegEx { concatenation = concatenationFromAlternative@@ -836,10 +820,10 @@ if ExecutionOptions.abortTrialRepetitionsOnZeroConsumption executionOptions && Data.Maybe.isNothing most {-constrained only by 'inputDataLength'-} then {-#SCC "abortTrialRepetitionsOnZeroConsumption" #-} ToolShed.Data.List.takeUntil $ \maybeMatchPair -> case maybeMatchPair of Just (match, _) -> ($ Tree.pop match) `all` [- (>= fewest) . length, --Must achieve 'Repeatable.getFewest', regardless of data-consumption.- null . extractDataFromMatchList . last --If the n-th repetition consumed nothing, so will the (n + 1)-th.+ (>= fewest) . length, -- Must achieve 'Repeatable.getFewest', regardless of data-consumption.+ null . extractDataFromMatchList . last -- If the n-th repetition consumed nothing, so will the (n + 1)-th. ]- _ -> False --Failure with n repetitions, doesn't preclude success with n + 1.+ _ -> False -- Failure with n repetitions, doesn't preclude success with n + 1. else {-optimisation not required-} id ) . ( -- :: Maybe (Match m, MatchList m) -> Maybe (Match m, MatchList m)@@ -853,14 +837,14 @@ -} then {-#SCC "abortTrialRepetitionsOnInherentFailure" #-} case maybeMatchPairList of (Nothing {-failed attempt-} : _ {-subsequent attempt worth bypassing-} : _) -> if (- minConsumptionConcatenationFromAlternative == 0 --Can delegate consumption of unconsumable data to the infallible tail => unprovable culpability.+ minConsumptionConcatenationFromAlternative == 0 -- Can delegate consumption of unconsumable data to the infallible tail => unprovable culpability. ) || inputData =~ RegExOpts.mkRegEx MkExtendedRegEx { bowAnchor = Just Anchor.Bow,- concatenation = concatenationFromAlternative ++ [anyDatum ^#-> minConsumptionConcatenationTail], --Infallible tail.+ concatenation = concatenationFromAlternative ++ [anyDatum ^#-> minConsumptionConcatenationTail], -- Infallible tail. sternAnchor = Just Anchor.Stern } then maybeMatchPairList- else [] --Abandon further repetitions of 'Alternatives'.+ else [] -- Abandon further repetitions of 'Alternatives'. _ {-Alternative is OK, or there's no subsequent attempt to bypass-} -> maybeMatchPairList else {-optimisation not required-} maybeMatchPairList ) . map (@@ -870,12 +854,12 @@ then ( shiftMatch inputDataOffset . Tree.Node . ( : replicate (- pred repetitions --Typically degenerates to zero, since anchored sub-expressions aren't normally repeatable.+ pred repetitions -- Typically degenerates to zero, since anchored sub-expressions aren't normally repeatable. ) (- mkNullMatchFromExtendedRegEx 0 extendedRegExFromAlternative --Other Alternatives may be available & suitable.- ) --Repeated null match may, lacking other suitable Alternatives, correspond to this stern-anchored ExtendedRegEx, so data must be consumed before them.+ mkNullMatchFromExtendedRegEx 0 extendedRegExFromAlternative -- Other Alternatives may be available & suitable.+ ) -- Repeated null match may, lacking other suitable Alternatives, correspond to this stern-anchored ExtendedRegEx, so data must be consumed before them. ) &&& const (mkNullMatchFromConcatenation inputDataOffset concatenationTail)- ) <$> findMatch regExOpts { RegExOpts.regEx = extendedRegExFromAlternative } inputData --Recurse, either consuming all inputData or failing.+ ) `fmap` findMatch regExOpts { RegExOpts.regEx = extendedRegExFromAlternative } inputData -- Recurse, either consuming all inputData or failing. else Nothing else {-no Anchor.Stern-} let {-@@ -896,10 +880,10 @@ | repetitions == 1 = ( Control.Arrow.first ( Tree.Node . return {-to List-monad-}- ) . splitAt components, --Bisect the 'MatchList', into the part resulting from the Alternative, & that for 'concatenationTail'.+ ) . splitAt components, -- Bisect the 'MatchList', into the part resulting from the Alternative, & that for 'concatenationTail'. consumptionProfileConcatenationFromAlternative, concatenationFromAlternative- ) --Both tuples below, can degenerate to this simple case; it isn't a fundamentally different algorithm.+ ) -- Both tuples below, can degenerate to this simple case; it isn't a fundamentally different algorithm. | and [ ExecutionOptions.unrollRepeatedSingletonAlternative executionOptions, isSingletonAlternative,@@ -909,37 +893,37 @@ Tree.Node . ToolShed.Data.List.chunk components ) . splitAt ( components * repetitions- ), --Bisect the 'MatchList', into the part resulting from (Alternative){n}, & that for 'concatenationTail'.+ ), -- Bisect the 'MatchList', into the part resulting from (Alternative){n}, & that for 'concatenationTail'. concat $ replicate repetitions consumptionProfileConcatenationFromAlternative,- concat $ replicate repetitions concatenationFromAlternative --Expand all repetitions of the single alternative.+ concat $ replicate repetitions concatenationFromAlternative -- Expand all repetitions of the single alternative. ) | otherwise {-choice of Alternatives or has Anchor.Bow-} = let remainingRepetitions :: Repeatable.Repetitions- remainingRepetitions = pred repetitions --Expand just the first repetition of the set of 'Alternatives'.+ remainingRepetitions = pred repetitions -- Expand just the first repetition of the set of 'Alternatives'. -- singletonRepeatable :: RepeatablePattern a singletonRepeatable = Repeatable.toSingleton repeatablePatternHead in ( Control.Arrow.first ( Tree.Node . uncurry (:) . Control.Arrow.second (- concatMap Tree.pop --Amalgamate the repeated singleton 'MatchList's.- ) . splitAt components --Bisect first 'MatchList', into the part resulting from 'concatenationFromAlternative', & that for 'replicate remainingRepetitions'.+ concatMap Tree.pop -- Amalgamate the repeated singleton 'MatchList's.+ ) . splitAt components -- Bisect first 'MatchList', into the part resulting from 'concatenationFromAlternative', & that for 'replicate remainingRepetitions'. ) . splitAt (- components + remainingRepetitions --Bisect the 'MatchList', into the part resulting from (Alternatives){n}, & that for 'concatenationTail'.+ components + remainingRepetitions -- Bisect the 'MatchList', into the part resulting from (Alternatives){n}, & that for 'concatenationTail'. ), consumptionProfileConcatenationFromAlternative ++ replicate remainingRepetitions (Consumer.consumptionProfile singletonRepeatable),- concatenationFromAlternative {-expand 1st repetition-} ++ replicate remainingRepetitions {-potentially zero-} singletonRepeatable --Enumerate all remaining repetitions of ANY Alternative; a different Alternative can match for each repetition.+ concatenationFromAlternative {-expand 1st repetition-} ++ replicate remainingRepetitions {-potentially zero-} singletonRepeatable -- Enumerate all remaining repetitions of ANY Alternative; a different Alternative can match for each repetition. )- in {-#SCC "collater" #-} collater <$> {-apply to Maybe Functor-} findMatchSlave (+ in {-#SCC "collater" #-} collater `fmap` {-apply to Maybe Functor-} findMatchSlave ( expandedConcatenationPrefix ++ concatenationTail ) ( ConsumptionProfile.accumulateFrom tailConsumptionProfile {-initial value-} consumptionProfileExpandedConcatenationPrefix ++ tail accumulatedConsumptionProfilesTail ) ( accumulateDistinctMetaDataFrom (head distinctMetaDataTail) {-initial value-} expandedConcatenationPrefix ++ tail distinctMetaDataTail- ) inputData inputDataLength distinctInputData --Recurse to get 'Maybe (MatchList a)'.- ) $ if Repeatable.isPrecise repeatablePatternHead --These are frequently generated by the previous recursion, as a trial expansion of an Alternative.+ ) inputData inputDataLength distinctInputData -- Recurse to get 'Maybe (MatchList a)'.+ ) $ if Repeatable.isPrecise repeatablePatternHead -- These are frequently generated by the previous recursion, as a trial expansion of an Alternative. then if ExecutionOptions.validateMinConsumptionOfAlternatives executionOptions && maxDataAvailable < fewest * minConsumptionAlternatives- then [] --Failure is inevitable.+ then [] -- Failure is inevitable. else [fewest] else {-imprecise range-} let {-@@ -953,48 +937,48 @@ then fewest else {-no unlimited capacities-} let minDataAvailable, maxConsumptionAlternatives :: ConsumptionBounds.DataLength- minDataAvailable = inputDataLength - Data.Maybe.fromJust maybeMaxConsumptionConcatenationTail --CAVEAT: can be negative.+ minDataAvailable = inputDataLength - Data.Maybe.fromJust maybeMaxConsumptionConcatenationTail -- CAVEAT: can be negative. maxConsumptionAlternatives = Data.Maybe.fromJust maybeMaxConsumptionAlternatives in if isSingletonAlternative- then if maxConsumptionAlternatives == 0 --Denominator.- then {-sole Alternative can't consume anything ?!-} if minDataAvailable <= 0 --Numerator.- then {-tail may consume all data-} fewest --Repeat to meet the minimum requirement.- else {-unconsumable data-} maxBound --Failure is inevitable.+ then if maxConsumptionAlternatives == 0 -- Denominator.+ then {-sole Alternative can't consume anything ?!-} if minDataAvailable <= 0 -- Numerator.+ then {-tail may consume all data-} fewest -- Repeat to meet the minimum requirement.+ else {-unconsumable data-} maxBound -- Failure is inevitable. else {-non-zero => can divide-} max fewest $ minDataAvailable /+ maxConsumptionAlternatives else {-choice of Alternatives-} let minDataAvailable' :: ConsumptionBounds.DataLength- minDataAvailable' = minDataAvailable - Data.Maybe.fromJust maybeMaxConsumptionConcatenationFromAlternative --CAVEAT: potentially negative.- in if maxConsumptionAlternatives == 0 --Denominator.- then {-no Alternative can consume anything-} if minDataAvailable' <= 0 --Numerator.- then {-zero unconsumable data-} fewest --Repeat to meet the minimum requirement.- else {-unconsumable data-} maxBound --Failure is inevitable.+ minDataAvailable' = minDataAvailable - Data.Maybe.fromJust maybeMaxConsumptionConcatenationFromAlternative -- CAVEAT: potentially negative.+ in if maxConsumptionAlternatives == 0 -- Denominator.+ then {-no Alternative can consume anything-} if minDataAvailable' <= 0 -- Numerator.+ then {-zero unconsumable data-} fewest -- Repeat to meet the minimum requirement.+ else {-unconsumable data-} maxBound -- Failure is inevitable. else {-non-zero => can divide-} max fewest . succ {-account for expanded instance-} $ minDataAvailable' /+ maxConsumptionAlternatives mostAlternatives = {-#SCC "mostAlternatives" #-} case most of- Just cap -> cap `min` mostPermissibleRepetitions --Create a ceiling above which the calculated number of permissible repetitions can't rise.+ Just cap -> cap `min` mostPermissibleRepetitions -- Create a ceiling above which the calculated number of permissible repetitions can't rise. _ -> mostPermissibleRepetitions where mostPermissibleRepetitions :: Repeatable.Repetitions mostPermissibleRepetitions- | isSingletonAlternative = if minConsumptionAlternatives == 0 --Denominator.- then {-sole Alternative can consume zero data-} if maxDataAvailable == 0 --Numerator.- then {-zero data available-} fewest --Repeat to meet the minimum requirement.- else {-data available-} maxDataAvailable --Either each repetition consumes something, or (n - 1) repetitions is a better solution.- else {-non-zero => can divide-} maxDataAvailable `div` minConsumptionAlternatives --Divide & round down.+ | isSingletonAlternative = if minConsumptionAlternatives == 0 -- Denominator.+ then {-sole Alternative can consume zero data-} if maxDataAvailable == 0 -- Numerator.+ then {-zero data available-} fewest -- Repeat to meet the minimum requirement.+ else {-data available-} maxDataAvailable -- Either each repetition consumes something, or (n - 1) repetitions is a better solution.+ else {-non-zero => can divide-} maxDataAvailable `div` minConsumptionAlternatives -- Divide & round down. | otherwise {-choice of Alternatives-} = 1 {-account for instance expanded as 'concatenationFromAlternative'-} + let maxDataAvailable' :: ConsumptionBounds.DataLength- maxDataAvailable' = maxDataAvailable - minConsumptionConcatenationFromAlternative --CAVEAT: potentially negative.- in if minConsumptionAlternatives == 0 --Denominator.- then {-@ least one Alternative can consume zero-} if maxDataAvailable' == 0 --Numerator.- then {-zero data available $-} pred fewestAlternatives --Repeat as required. CAVEAT: an annoying dependency, which prevents parallel-evaluation.+ maxDataAvailable' = maxDataAvailable - minConsumptionConcatenationFromAlternative -- CAVEAT: potentially negative.+ in if minConsumptionAlternatives == 0 -- Denominator.+ then {-@ least one Alternative can consume zero-} if maxDataAvailable' == 0 -- Numerator.+ then {-zero data available $-} pred fewestAlternatives -- Repeat as required. CAVEAT: an annoying dependency, which prevents parallel-evaluation. else {-data available-} if and [- False, --The cost outweighs the small infrequent dividend.+ False, -- The cost outweighs the small infrequent dividend. minConsumptionConcatenationFromAlternative == 0, maxDataAvailable > fewest- ] --If 'fewest' can be met, without unconsuming repetitions of 'concatenationFromAlternative', then stop short of permitting it.- then pred maxDataAvailable --Any greater, & one repetition (possibly that currently expanded) must needlessly consume nothing.- else maxDataAvailable' --Either all n repetitions consumes something, or (n - 1) is a better solution.- else {-non-zero => can divide-} maxDataAvailable' `div` minConsumptionAlternatives --Divide & round down.+ ] -- If 'fewest' can be met, without unconsuming repetitions of 'concatenationFromAlternative', then stop short of permitting it.+ then pred maxDataAvailable -- Any greater, & one repetition (possibly that currently expanded) must needlessly consume nothing.+ else maxDataAvailable' -- Either all n repetitions consumes something, or (n - 1) is a better solution.+ else {-non-zero => can divide-} maxDataAvailable' `div` minConsumptionAlternatives -- Divide & round down. {- 'most' has been extracted from 'repeatablePatternHead', & reduced according to the number of times it can fit into the maximum available data, to form 'mostAlternatives',@@ -1004,16 +988,16 @@ -} mostAlternatives' = {-#SCC "mostAlternatives'" #-} if and [ ExecutionOptions.moderateGreed executionOptions,- mostAlternatives > fewestAlternatives, --Otherwise, there's no unbridled greed to moderate.- minConsumptionAlternatives > 0 --Otherwise, any number of repetitions can occur without necessarily triggering back-tracking.+ mostAlternatives > fewestAlternatives, -- Otherwise, there's no unbridled greed to moderate.+ minConsumptionAlternatives > 0 -- Otherwise, any number of repetitions can occur without necessarily triggering back-tracking. ] then case maximumDataBeforePegs of Just maximumDataBeforePegs' -> mostAlternatives `min` ( length maximumDataBeforePegs' `div` minConsumptionAlternatives- ) --Cap upper bound.- _ -> negate 1 --Guaranteed to be < 'fewestAlternatives'.+ ) -- Cap upper bound.+ _ -> negate 1 -- Guaranteed to be < 'fewestAlternatives'. else {-no requirement for this optimisation-} mostAlternatives- in [fewestAlternatives .. mostAlternatives'] --The permissible repetition-range of any Alternative, constrained by the amount of data available, after subtracting fixed consumption-requirements.+ in [fewestAlternatives .. mostAlternatives'] -- The permissible repetition-range of any Alternative, constrained by the amount of data available, after subtracting fixed consumption-requirements. ) . ( if ExecutionOptions.permitReorderingOfAlternatives executionOptions {-@@ -1025,18 +1009,18 @@ -} then Data.List.sortBy $ Data.Ord.comparing ( Consumer.starHeight &&& safeReciprocal . (fromIntegral :: ConsumptionBounds.DataLength -> Rational) . Consumer.getFewest- ) --Firstly increasing complexity, then decreasing minimum data-capacity, otherwise stable.+ ) -- Firstly increasing complexity, then decreasing minimum data-capacity, otherwise stable. else id ) $ filter ( \e -> (- not (hasBowAnchor e) || inputDataOffset == 0 --Necessary & sufficient.+ not (hasBowAnchor e) || inputDataOffset == 0 -- Necessary & sufficient. ) && (- not (hasSternAnchor e) || minConsumptionConcatenationTail == 0 --Necessary but insufficient, since though minimum consumption is zero, maximum isn't necessarily.+ not (hasSternAnchor e) || minConsumptionConcatenationTail == 0 -- Necessary but insufficient, since though minimum consumption is zero, maximum isn't necessarily. ) ) extendedRegExAlternatives in if null matchPairList then if fewest <= 0- then zeroRepetitions --Which might still fail, depending on 'tailMatch'.+ then zeroRepetitions -- Which might still fail, depending on 'tailMatch'. else {-zero repetitions isn't permissible-} Nothing else {-at least one Alternative matched-} {-#SCC "selectAlternative" #-} Just . uncurry (:) {-re-join head & tail-} $ ( {-@@ -1048,27 +1032,28 @@ if ExecutionOptions.useFirstMatchAmongAlternatives executionOptions || length matchPairList == 1 then head else snd {-remove prepended selection-criterion-} . Data.List.maximumBy {-select the best match-} (- Data.Ord.comparing fst --Compare using only the criterion, not the result from which it was derived.+ Data.Ord.comparing fst -- Compare using only the criterion, not the result from which it was derived. ) . map ( ( {- If the primary selection-criterion doesn't resolve the choice between candidate 'Match'es, I employ these ad-hoc criteria.-* Fewer repetitions are preferred, which discourages the capture of null lists of 'InputData'. -* Within the 'MatchedData', from which a candidate 'Match' is ultimately composed, consumption of 'InputData' beyond 'Repeatable.getFewest' by 'Repeatable.isGreedy' 'RepeatablePattern's, is preferred to non-greedy ones.+ * Fewer repetitions are preferred, which discourages the capture of null lists of 'InputData'. -* The consumption on each successive repetition is compared between candidate 'Match'es (which are now known to have used an equal number of repetitions);-this causes the data-consumption to flow towards earlier repetitions for greedy capture-groups, & towards later repetitions in non-greedy ones,-thus mimicking the behaviour of the unrolled repetition.+ * Within the 'MatchedData', from which a candidate 'Match' is ultimately composed, consumption of 'InputData' beyond 'Repeatable.getFewest' by 'Repeatable.isGreedy' 'RepeatablePattern's, is preferred to non-greedy ones. -* PS: more precise criteria are defined in <http://www2.research.att.com/~gsf/testregex/re-interpretation.html>.+ * The consumption on each successive repetition is compared between candidate 'Match'es (which are now known to have used an equal number of repetitions);+ this causes the data-consumption to flow towards earlier repetitions for greedy capture-groups, & towards later repetitions in non-greedy ones,+ thus mimicking the behaviour of the unrolled repetition.++ * PS: more precise criteria are defined in <http://www2.research.att.com/~gsf/testregex/re-interpretation.html>. -} \match -> let dataLengthCriterion :: InputData m -> Rational dataLengthCriterion = ( if isGreedy then id- else safeReciprocal --Prefer less data.+ else safeReciprocal -- Prefer less data. ) . fromIntegral . length -- matchLists :: [MatchList m]@@ -1076,7 +1061,7 @@ in ( dataLengthCriterion $ extractDataFromMatch match, if ExecutionOptions.preferFewerRepeatedAlternatives executionOptions- then safeReciprocal . fromIntegral $ length matchLists :: Rational+ then safeReciprocal . toRational $ length matchLists else 0, if ExecutionOptions.preferAlternativesWhichFeedTheGreedy executionOptions then let@@ -1099,14 +1084,14 @@ if ExecutionOptions.preferAlternativesWhichMimickUnrolling executionOptions then map (dataLengthCriterion . extractDataFromMatchList) matchLists else []- ) --Create a tuple of selection-criteria, for simultaneous assessment.- ) . fst {-focus the choice on the Alternatives-} &&& id --Prepend a selection-criterion to each result.+ ) -- Create a tuple of selection-criteria, for simultaneous assessment.+ ) . fst {-focus the choice on the Alternatives-} &&& id -- Prepend a selection-criterion to each result. ) ) matchPairList where -- tailMatch, zeroRepetitions :: Maybe (MatchList m)- tailMatch = findMatchSlave concatenationTail accumulatedConsumptionProfilesTail distinctMetaDataTail inputData inputDataLength distinctInputData --Recurse.- zeroRepetitions = (Tree.Node [] :) <$> {-apply to Maybe Functor-} tailMatch --Prepend a null 'MatchList'.+ tailMatch = findMatchSlave concatenationTail accumulatedConsumptionProfilesTail distinctMetaDataTail inputData inputDataLength distinctInputData -- Recurse.+ zeroRepetitions = (Tree.Node [] :) `fmap` {-apply to Maybe Functor-} tailMatch -- Prepend a null 'MatchList'. -- extendedRegExAlternatives :: [ExtendedRegEx m] extendedRegExAlternatives = Data.List.nub $ deconstructAlternatives alternatives@@ -1116,7 +1101,7 @@ minConsumptionAlternatives :: ConsumptionBounds.DataLength maybeMaxConsumptionAlternatives :: Maybe ConsumptionBounds.DataLength- (minConsumptionAlternatives, maybeMaxConsumptionAlternatives) = Consumer.getConsumptionBounds alternatives --Independent of the choice of Alternative.+ (minConsumptionAlternatives, maybeMaxConsumptionAlternatives) = Consumer.getConsumptionBounds alternatives -- Independent of the choice of Alternative. where inputDataOffset :: ConsumptionBounds.DataLength inputDataOffset = originalInputDataLength - inputDataLength@@ -1128,18 +1113,20 @@ * CAVEAT: much more expensive then '=~': in /ghci/, 'Just' can be observed to be printed /long/ before the 'MatchList' from which 'Result' is constructed, as the lazy algorithm finds the first solution, but not yet necessarily the optimal solution, amongst 'Alternatives'. -}-(+~) :: (Eq m, NFData m)+(+~) :: (Eq m, Control.DeepSeq.NFData m) => InputData m -- ^ The input data within which to locate a match. -> RegExOpts.RegExOpts (ExtendedRegEx m) -- ^ The match-options parameterised by the regex against which to match the input data. -> Result m inputData +~ regExOpts = (- if hasBowAnchor' then Nothing else head <$> maybeMatchList, --Record the first 'Match', consumed in the absence of a top-level 'Anchor.Bow'.- (- if hasBowAnchor' then id else tail --Remove the first 'Match', since this wasn't consumed by the 'Concatenation'.- ) . (- if hasSternAnchor' then id else init --Remove the last 'Match', since this wasn't consumed by the 'Concatenation'.- ) <$> maybeMatchList,- if hasSternAnchor' then Nothing else last <$> maybeMatchList --Record the last 'Match', consumed in the absence of a top-level 'Anchor.Stern'.+ if hasBowAnchor' then Nothing else fmap head maybeMatchList, -- Record the first 'Match', consumed in the absence of a top-level 'Anchor.Bow'.+ fmap (+ (+ if hasBowAnchor' then id else tail -- Remove the first 'Match', since this wasn't consumed by the 'Concatenation'.+ ) . (+ if hasSternAnchor' then id else init -- Remove the last 'Match', since this wasn't consumed by the 'Concatenation'.+ )+ ) maybeMatchList,+ if hasSternAnchor' then Nothing else fmap last maybeMatchList -- Record the last 'Match', consumed in the absence of a top-level 'Anchor.Stern'. ) where -- extendedRegEx :: ExtendedRegEx a extendedRegEx = RegExOpts.regEx regExOpts@@ -1160,14 +1147,14 @@ the discovery of /any/ solution is sufficient to generate the return-value; lazy-evaluation avoids the requirement to identify the irrelevant optimal solution. -}-(=~) :: (Eq m, NFData m)+(=~) :: (Eq m, Control.DeepSeq.NFData m) => InputData m -- ^ The input data within which to locate a match. -> RegExOpts.RegExOpts (ExtendedRegEx m) -- ^ The match-options parameterised by the regex against which to match the input data. -> Bool inputData =~ regExOpts = Data.Maybe.isJust $ fmap drift (RegExOpts.setVerbose False regExOpts) `findMatch` inputData -- | Pattern-mismatch operator.-(/~) :: (Eq m, NFData m)+(/~) :: (Eq m, Control.DeepSeq.NFData m) => InputData m -- ^ The input data within which to locate a match. -> RegExOpts.RegExOpts (ExtendedRegEx m) -- ^ The match-options parameterised by the regex against which to match the input data. -> Bool@@ -1191,21 +1178,21 @@ * CAVEAT: this is an awful concept, and therefore intended for internal use only. -} safeReciprocal :: (Eq f, Fractional f) => f -> f-safeReciprocal 0 = fromIntegral (maxBound :: Int) --Handle divide-by-zero error.+safeReciprocal 0 = fromIntegral (maxBound :: Int) -- Handle divide-by-zero error. safeReciprocal f = recip f -infixl 7 /+ --Same as (/).+infixl 7 /+ -- Same as (/). {- | * Integral division, with any fractional remainder rounded-up. * A rather dubious requirement, so internal use only. -}---(/+) :: Integral i => i -> i -> i+-- (/+) :: Integral i => i -> i -> i (/+) :: Int -- ^ Numerator. -> Int -- ^ Denominator.- -> Int --10% faster in unoptimised code, & more in optimised.+ -> Int -- 10% faster in unoptimised code, & more in optimised. _ /+ 0 = error "RegExDot.RegEx.(/+):\tzero denominator => infinity"---numerator /+ denominator = ceiling ((fromIntegral numerator / fromIntegral denominator) :: Double)-numerator /+ denominator = uncurry (+) . Control.Arrow.second signum $ quotRem numerator denominator --Slightly faster.+-- numerator /+ denominator = ceiling ((fromIntegral numerator / fromIntegral denominator) :: Double)+numerator /+ denominator = uncurry (+) . Control.Arrow.second signum $ quotRem numerator denominator -- Slightly faster.
src/RegExDot/Repeatable.hs view
@@ -1,6 +1,5 @@-{-# LANGUAGE CPP #-} {-- Copyright (C) 2010 Dr. Alistair Ward+ Copyright (C) 2010-2015 Dr. Alistair Ward This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by@@ -80,8 +79,10 @@ hasPreciseBounds ) where +import Prelude hiding ((<$>), (<*>)) -- The "Prelude" from 'base-4.8' exports this symbol. import Control.Applicative((<$>), (<*>)) import Control.Arrow((***))+import qualified Control.DeepSeq import qualified Data.List import qualified RegExDot.Consumer as Consumer import qualified RegExDot.ConsumptionProfile as ConsumptionProfile@@ -90,13 +91,7 @@ import qualified ToolShed.Data.Pair import qualified ToolShed.SelfValidate -#ifdef HAVE_DEEPSEQ-import Control.DeepSeq(NFData, rnf)-#else-import Control.Parallel.Strategies(NFData, rnf)-#endif--infix 6 ^#->#, ^#->#?, ^#->, ^#->?, ^# --A notch tighter than "DSL"s binary operators.+infix 6 ^#->#, ^#->#?, ^#->, ^#->?, ^# -- A notch tighter than "DSL"s binary operators. -- | A number of repetitions. type Repetitions = Int@@ -129,7 +124,7 @@ -- | Builds a parser for a specification of the number of permissible instances of the specified polymorphic parameter. repeatableParser :: a -> Parsec.Parser (Repeatable a) repeatableParser b = Parsec.option (- one b --The default; there's no concept of greediness here.+ one b -- The default; there's no concept of greediness here. ) $ do repeatable <- Parsec.choice [ (Parsec.char oneOrMoreToken <?> "Repeatable.oneOrMoreToken " ++ show oneOrMoreToken) >> return {-to ParsecT-monad-} (oneOrMore b),@@ -139,7 +134,7 @@ do fewest <- Parsec.spaces >> (read <$> Parsec.many1 Parsec.digit <?> "Repetition-range minimum") most <- Parsec.spaces >> Parsec.option (- Just fewest --The default.+ Just fewest -- The default. ) ( do i <- (@@ -157,12 +152,12 @@ g <- Parsec.option True {-the default-} $ (Parsec.char nonGreedyToken <?> "Repeatable.nonGreedyToken " ++ show nonGreedyToken) >> return {-to ParsecT-monad-} False - return {-to ParsecT-monad-} repeatable { isGreedy = g } --Correct prior assumption.+ return {-to ParsecT-monad-} repeatable { isGreedy = g } -- Correct prior assumption. instance Read a => Read (Repeatable a) where readsPrec _ s = case reads s {-first, read the base-type-} of [(base', s1)] -> (error . ("readsPrec Repeatable:\tparse-error; " ++) . show) `either` return $ Parsec.parse ((,) <$> repeatableParser base' <*> Parsec.getInput) "Repeatable" s1- _ -> [] --No parse.+ _ -> [] -- No parse. {- | * A 'ShowS'-function for the suffix, denoting the permissible repetitions, of 'base'.@@ -179,15 +174,15 @@ (1, Nothing) -> showChar oneOrMoreToken (fewest, Nothing) -> showRange $ shows fewest . showChar rangeSeparatorToken (0, Just 1) -> showChar zeroOrOneToken- (1, Just 1) -> id --CAVEAT: since there's no explicit repetition-operator, the non-greedy modifier can't be appended.+ (1, Just 1) -> id -- CAVEAT: since there's no explicit repetition-operator, the non-greedy modifier can't be appended. (fewest, Just most) -> showRange $ if fewest == most- then shows fewest --Single-valued range.+ then shows fewest -- Single-valued range. else shows fewest . showChar rangeSeparatorToken . shows most ) . if ($ repeatable) `any` [isGreedy, isPrecise] {-without a range of possibilities, non-greediness is irrelevant-} then id- else showChar nonGreedyToken --This can only be appended, if there a previous repetition-operator for it to modify.+ else showChar nonGreedyToken -- This can only be appended, if there a previous repetition-operator for it to modify. ---Replicate the syntax, for repetition, as used in a POSIX-standard /regex/.+-- Replicate the syntax, for repetition, as used in a POSIX-standard /regex/. instance Show a => Show (Repeatable a) where showsPrec _ repeatable = shows (base repeatable) . showSuffix repeatable @@ -196,7 +191,7 @@ base = b, repetitionBounds = (fewest, most) } = baseConsumptionProfile {- ConsumptionProfile.consumptionBounds = (fewest *) *** ((*) <$> most <*>) $ ConsumptionProfile.consumptionBounds baseConsumptionProfile --CAVEAT: special cases exist, where one or both halves of this calculation degenerate to a simpler form, but special treatment, in an attempt to improve performance, proved counterproductive.+ ConsumptionProfile.consumptionBounds = (fewest *) *** ((*) <$> most <*>) $ ConsumptionProfile.consumptionBounds baseConsumptionProfile -- CAVEAT: special cases exist, where one or both halves of this calculation degenerate to a simpler form, but special treatment, in an attempt to improve performance, proved counterproductive. } where baseConsumptionProfile :: ConsumptionProfile.ConsumptionProfile baseConsumptionProfile = Consumer.consumptionProfile b@@ -212,7 +207,7 @@ repetitionBounds = (fewest, most), isGreedy = g }- | not $ ToolShed.SelfValidate.isValid b = ToolShed.SelfValidate.getErrors b --Delegate.+ | not $ ToolShed.SelfValidate.isValid b = ToolShed.SelfValidate.getErrors b -- Delegate. | otherwise = ToolShed.SelfValidate.extractErrors [ (fewest < 0, "Negative fewest=" ++ show fewest ++ "."), (@@ -222,18 +217,18 @@ "Invalid repetition-range; '" ++ show (fewest, most) ++ "'." ), ( not g && case most of- Just m -> fewest >= m --There ought to be potential for non-greediness, where specified: the converse isn't true, since greediness isn't explicit, & may not have been wanted.+ Just m -> fewest >= m -- There ought to be potential for non-greediness, where specified: the converse isn't true, since greediness isn't explicit, & may not have been wanted. _ -> False, "Invalid non-greedy repetition-range; '" ++ show (fewest, most) ++ "'." ) ] -instance NFData a => NFData (Repeatable a) where+instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Repeatable a) where rnf MkRepeatable { base = b, repetitionBounds = r, isGreedy = g- } = rnf (b, r, g)+ } = Control.DeepSeq.rnf (b, r, g) -- | Mutator. setNonGreedy :: Repeatable a -> Repeatable a
src/RegExDot/ShowablePredicate.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2010 Dr. Alistair Ward @@ -32,11 +31,7 @@ ) ) where -#ifdef HAVE_DEEPSEQ-import Control.DeepSeq(NFData, rnf)-#else-import Control.Parallel.Strategies(NFData, rnf)-#endif+import qualified Control.DeepSeq -- | An arbitrary polymorphic predicate function. type Predicate a = a -> Bool@@ -51,8 +46,8 @@ showsPrec _ = showString . name instance Eq (ShowablePredicate a) where- l == r = name l == name r --Ignore 'predicate'.+ l == r = name l == name r -- Ignore 'predicate'. -instance NFData (ShowablePredicate a) where- rnf = rnf . name --Ignore 'predicate'.+instance Control.DeepSeq.NFData (ShowablePredicate a) where+ rnf = Control.DeepSeq.rnf . name -- Ignore 'predicate'.
src/RegExDot/Span.hs view
@@ -57,8 +57,8 @@ :: ConsumptionBounds.DataLength -- ^ The offset into the list of input-data to use when a null list of spans is received. -> [Span] -> Span-join offset [] = empty offset --The offset can't be deduced from a null list, so use the value provided.-join _ [singleton] = singleton --Merely for efficiency.+join offset [] = empty offset -- The offset can't be deduced from a null list, so use the value provided.+join _ [singleton] = singleton -- Merely for efficiency. join _ spanList = head *** sum $ unzip spanList
src/RegExDot/Tree.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2010 Dr. Alistair Ward @@ -38,16 +37,11 @@ ) where import qualified Control.Arrow+import qualified Control.DeepSeq import qualified Data.Foldable import qualified Data.List import qualified Data.Monoid -#ifdef HAVE_DEEPSEQ-import Control.DeepSeq(NFData, rnf)-#else-import Control.Parallel.Strategies(NFData, rnf)-#endif- -- | A general purpose tree-type structure. data Tree a = Leaf a -- ^ The payload.@@ -65,16 +59,16 @@ readsPrec _ node@('[' : _) = Control.Arrow.first Node `map` readList node {-singleton-} readsPrec _ leaf = Control.Arrow.first Leaf `map` reads leaf {-singleton-} -instance NFData a => NFData (Tree a) where- rnf (Leaf a) = rnf a- rnf (Node l) = rnf l+instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Tree a) where+ rnf (Leaf a) = Control.DeepSeq.rnf a+ rnf (Node l) = Control.DeepSeq.rnf l instance Functor Tree where fmap f (Leaf a) = Leaf $ f a fmap f (Node treeLists) = Node $ map (fmap {-recurse-} f `map`) treeLists instance Data.Foldable.Foldable Tree where- foldMap f (Leaf a) = f a --CAVEAT: 'f' should be Associative, as required by a Monoid.+ foldMap f (Leaf a) = f a -- CAVEAT: 'f' should be Associative, as required by a Monoid. foldMap f (Node treeLists) = Data.List.foldl' (Data.List.foldl' (\monoid -> (monoid `Data.Monoid.mappend`) . Data.Foldable.foldMap f)) Data.Monoid.mempty treeLists -- | Deconstruct the specified 'Node'; i.e. lop the apex from the 'Tree', leaving a flat top.