packages feed

regexchar 0.9.0.7 → 0.9.0.8

raw patch · 26 files changed

+1188/−1175 lines, 26 filesdep ~toolshed

Dependency ranges changed: toolshed

Files

changelog view
@@ -36,4 +36,9 @@ 	* Changed identifier for type-parameters, to better reflect its role. 	* Removed dependency on archaic module "ToolShed.Arithmetic". 	* Reacted to the creation of module "ToolShed.Defaultable".-+	* Uploaded to <http://hackage.haskell.org/packages/hackage.html>.+0.9.0.8+	* Amended 'regexchar.cabal' to more correctly specify dependency on package 'toolshed'.+	* Used new module "ToolShed.Pair" from package toolshed-0.12.0.0.+	* Relocated modules "Grecce.Assert", "Grecce.Performance" and "Grecce.QC", into new layer "Test", in module-hierarchy.+	* Guarded 'eager-blackholing' flag in cabal file.
makefile view
@@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program.  If not, see <http://www.gnu.org/licenses/>.  -.PHONY: all build clean clobber configure copy deb haddock help hlint install lintian prof rpm rpmlint sdist+.PHONY: all build check clean clobber configure copy deb haddock help hlint install lintian prof rpm rpmlint sdist  all: install @@ -45,6 +45,9 @@ sdist: configure 	runhaskell Setup.hs $@ +check: sdist+	cabal upload --check --verbose=3 dist/*.tar.gz;+ rpm: regexchar.spec 	rpmbuild -bb -- $^ 	mv -- `find /usr/src/packages/ -type f -name 'regexchar*.rpm' -mtime 0 -print` ./@@ -67,6 +70,7 @@ clean: 	runhaskell Setup.hs $@ 	rm -rf 'debian/usr/' 'debian/DEBIAN/md5sums'+	find src -type f \( -name '*.o' -o -name '*.hi' \) -delete  clobber: clean 	rm -f -- *.rpm *.deb
regexchar.cabal view
@@ -1,15 +1,15 @@ --Package-properties Name:			regexchar-Version:		0.9.0.7+Version:		0.9.0.8 Cabal-Version:		>= 1.6 Copyright:		(C) 2010 Dr. Alistair Ward License:		GPL License-file:		LICENSE Author:			Dr. Alistair Ward Stability:		Stable interface, incomplete features.-Synopsis:		A POSIX extended regular-expression engine.+Synopsis:		A POSIX, extended regex-engine. Build-Type:		Simple-Description:		Provides a POSIX, extended regex-engine, specialised from the underlying polymorphic engine /regexdot/, to merely process character-lists, as is typically required.+Description:		Provides a POSIX, extended regex-engine, specialised from the underlying /polymorphic/ package /regexdot/, to merely process the traditional character-lists. Category:		Regex, Text Tested-With:		GHC == 6.10, GHC == 6.12, GHC == 7.0 Homepage:		http://functionalley.eu@@ -23,7 +23,7 @@     default:		True  flag llvm-    Description:	Whether the 'llvm' backend has been installed and is required for code-generation.+    Description:	Whether the 'llvm' compiler-backend has been installed and is required for code-generation.     manual:		True     default:		False @@ -41,7 +41,7 @@         haskell98,         parsec == 3.*,         regexdot == 0.10.*,-        toolshed == 0.11.*+        toolshed >= 0.12      GHC-options:	-Wall     GHC-prof-options:	-prof -auto-all -caf-all@@ -53,17 +53,17 @@     hs-source-dirs:	src     Main-Is:		Main.hs     Other-modules:-        Grecce.Assert.RegExOptsChar         Grecce.CommandOptions         Grecce.Grep-        Grecce.Performance.ExtendedRegEx-        Grecce.Performance.ExtendedRegExTest-        Grecce.Performance.ExtendedRegExTestsNegative-        Grecce.Performance.ExtendedRegExTestsPositive-        Grecce.QC.ExtendedRegExChar-        Grecce.QC.MetaChar-        Grecce.QC.QuickChecks-        Grecce.QC.RepeatableMetaChar+        Grecce.Test.Assert.RegExOptsChar+        Grecce.Test.Performance.ExtendedRegEx+        Grecce.Test.Performance.ExtendedRegExTest+        Grecce.Test.Performance.ExtendedRegExTestsNegative+        Grecce.Test.Performance.ExtendedRegExTestsPositive+        Grecce.Test.QC.ExtendedRegExChar+        Grecce.Test.QC.MetaChar+        Grecce.Test.QC.QuickChecks+        Grecce.Test.QC.RepeatableMetaChar      Build-depends:         array,@@ -77,7 +77,10 @@      if flag(threaded)         Build-depends:	parallel >= 3.0-        GHC-options:	-threaded -feager-blackholing+        GHC-options:	-threaded++        if impl(ghc >= 6.12)+            GHC-options:	-feager-blackholing     else         Build-depends:	parallel 
regexchar.spec view
@@ -8,7 +8,7 @@  Summary: 	A re-implementation of egrep, using a specialisation of a polymorphic regex-engine. Name:		regexchar-Version:	0.9.0.7+Version:	0.9.0.8 Release:	1 License:	GPLv3 #From '/usr/share/doc/packages/rpm/GROUPS'.
− src/Grecce/Assert/RegExOptsChar.hs
@@ -1,92 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]--	* Reads lines from the specified file.--	* Each line describes a 'Test'.--	* Each input-data string should match the /regex/ in the specified way.--	* Permits comparison with "Text.Regex.Posix.String".--}--module Grecce.Assert.RegExOptsChar(--- * Types--- ** Type-synonyms---	Test,---	TestDataAndResult,---	TestFilter,--- * Functions-	findFailures,-	findFailuresPosix,-	readTests--- ** Predicates---	isMatch-) where--import			Control.Applicative((<$>))-import			Text.Regex.Posix()-import qualified	Control.Arrow-import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar-import qualified	RegExChar.RegExOptsChar		as RegExOptsChar	--CAVEAT: beware of the similar name.-import qualified	RegExDot.CompilationOptions	as CompilationOptions-import qualified	RegExDot.ExecutionOptions	as ExecutionOptions-import qualified	Text.Regex.Base.RegexLike	as RegexLike-import qualified	Text.Regex.Posix.Wrap---- | Composed input data & list of captured 'RegExOptsChar.MatchSpan'.-type TestDataAndResult	= (ExtendedRegExChar.InputData, [RegExOptsChar.MatchSpan])---- | Composed of the 'String' from which an unspecified type of regex is read, & a list of input data & results, to which it should respectively be applied & compared.-type Test		= (String {-regex-source-}, [TestDataAndResult])---- | Filters a list of 'Test's, & returns a sub-set.-type TestFilter		= [Test] -> [Test]---- | 'True' if the specified 'ExtendedRegExChar.InputData', is a member of the set defined by the polymorphic 'Text.Regex.Base.RegexLike.RegexLike' parameter.-isMatch :: RegexLike.RegexLike r ExtendedRegExChar.InputData => r -> TestDataAndResult -> Bool-isMatch regex (inputData, matchSpanList)	= RegexLike.matchOnce regex inputData == Just (RegExOptsChar.toZeroIndexedArray matchSpanList)---- | Returns those 'Test's, which 'RegExOptsChar.RegExOptsChar' fails.-findFailures :: CompilationOptions.CompilationOptions -> ExecutionOptions.ExecutionOptions -> TestFilter-findFailures compilationOptions executionOptions	= filter (not . uncurry all . Control.Arrow.first (isMatch . RegexLike.makeRegexOpts compilationOptions executionOptions))---- | Returns those 'Test's, which 'Text.Regex.Posix.Wrap.Regex' fails.-findFailuresPosix :: TestFilter-findFailuresPosix	= filter (not . uncurry all . Control.Arrow.first ((isMatch :: Text.Regex.Posix.Wrap.Regex -> TestDataAndResult -> Bool) . RegexLike.makeRegex))--{- |-	* Read 'Test's from file, ignoring blank lines & comments.--	* To facilitate parsing, each line in the file has the format of @show Test@.--}-readTests :: String -> IO [Test]-readTests fileName	= map (-	\line	-> case reads line of-		[(test, _)]	-> test-		_		-> error $ "Grecce.Assert.RegExOptsChar.readTests:\tfailed to read 'Test' from '" ++ line ++ "'"- ) . filter (-	(/= '#') . head	--Remove comments.- ) . filter (-	not . null	--Remove blank lines.- ) . lines <$> readFile fileName-
src/Grecce/Grep.hs view
@@ -37,12 +37,12 @@ import qualified	Data.List import qualified	Grecce.CommandOptions		as CommandOptions import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar-import			RegExChar.ExtendedRegExChar	as ExtendedRegExChar((+~), (=~)) import qualified	RegExDot.RegEx			as RegEx import qualified	RegExDot.RegExOpts		as RegExOpts import qualified	RegExDot.Result			as Result import qualified	System import qualified	System.IO+import			RegExChar.ExtendedRegExChar	as ExtendedRegExChar((+~), (=~))  #if MIN_VERSION_parallel(3,0,0) import qualified	Control.Parallel.Strategies
− src/Grecce/Performance/ExtendedRegEx.hs
@@ -1,144 +0,0 @@-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]--	* CPU-times the specified stress-test(s), over a hard-coded list of /regex/-engines,-	providing each combination with a varied list of 'Performance.ExtendedRegExTest.TestGenerator's,-	& a level of 'Performance.ExtendedRegExTest.TestComplexity' which increases linearly to the specified cap.--	* Either a simple 'Bool' result, or the full data-capture, can be requested.-- [@CAVEATS@]--	* For compatibility with the other regex-engines, uses the specialised instance 'ExtendedRegExChar.ExtendedRegExChar',-	rather than the underlying polymorphic 'RegEx.ExtendedRegEx'.--	* "Text.Regex.Posix" stalls forever on 'Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES',-	with 'Performance.ExtendedRegExTest.TestComplexity'=3 & data-capture requested.-- [@TODO@]--	* Utilise the standard interface in "RegExOptsChar", to permit identical treatment of different regex-engines.--}--module Grecce.Performance.ExtendedRegEx(--- * Types--- ** Type-synonyms---	GenerateAndRunTest,---	GetAndRunTestRange,--- * Constants---	solitary,--- * Functions-	run---	tailorTest-) where--import			Control.Applicative((<$>), (<*>))-import			Control.Arrow((&&&))-import qualified	Control.Arrow-import qualified	Data.Maybe-import qualified	Grecce.Performance.ExtendedRegExTest		as Performance.ExtendedRegExTest-import qualified	Grecce.Performance.ExtendedRegExTestsNegative	as Performance.ExtendedRegExTestsNegative-import qualified	Grecce.Performance.ExtendedRegExTestsPositive	as Performance.ExtendedRegExTestsPositive-import qualified	RegExChar.ExtendedRegExChar			as ExtendedRegExChar-import qualified	RegExDot.ExecutionOptions			as ExecutionOptions-import qualified	RegExDot.RegEx					as RegEx-import qualified	RegExDot.RegExOpts				as RegExOpts-import qualified	Text.Regex.Posix-import qualified	ToolShed.Defaultable				as Defaultable-import qualified	ToolShed.TimePure				as TimePure--solitary :: Bool-solitary	= True	--Currently required because of the disastrous performance of "Text.Regex.Posix" on 'Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES'.--type GetAndRunTestRange a	= [a] -> IO ()-type GenerateAndRunTest		= Performance.ExtendedRegExTest.TestGenerator Char -> Performance.ExtendedRegExTest.TestComplexity -> IO (ExtendedRegExChar.InputData, [(Double, String)])--{- |-	* Print the CPU-seconds, required to run the range of 'Performance.ExtendedRegExTest.TestGenerator's corresponding to the specified test-names & a linearly increasing 'Performance.ExtendedRegExTest.TestComplexity'.--	* If the specified maximum 'Performance.ExtendedRegExTest.TestComplexity' is set to the special value '0', then it is increased linearly, without limit.--}-run :: ExecutionOptions.ExecutionOptions -> Performance.ExtendedRegExTest.TestComplexity -> Either [Performance.ExtendedRegExTestsNegative.TestName] [Performance.ExtendedRegExTestsPositive.TestName] -> IO ()-run executionOptions 0 testRange					= run executionOptions maxBound testRange	--Run the specified test-range, without any upper bound to 'Performance.ExtendedRegExTest.TestComplexity'.-run executionOptions maxTestComplexity (Left negativeTestRange)		= runNegativeTestRange negativeTestRange	where-	runNegativeTestRange :: GetAndRunTestRange Performance.ExtendedRegExTestsNegative.TestName-	runNegativeTestRange []		= runNegativeTestRange [minBound .. maxBound]	--Run all the tests, to the specified maximum 'Performance.ExtendedRegExTest.TestComplexity'.-	runNegativeTestRange testRange	= sequence_ $ (-		\complexity testGenerator	-> cpuSecondsFor testGenerator complexity >>= print-	 ) <$> [1 .. maxTestComplexity] <*> Data.Maybe.mapMaybe Performance.ExtendedRegExTest.query testRange	where-		cpuSecondsFor :: GenerateAndRunTest-		cpuSecondsFor testGenerator	= (-			\(inputData, (isMismatch, extendedRegExCharString))	-> (,) extendedRegExCharString <$> mapM (-				TimePure.getCPUSeconds . ($ inputData) . (show .)-			 ) [-				isMismatch,-				if solitary-					then const True	--CAVEAT: should be 'undefined'.-					else not . (Text.Regex.Posix.=~ extendedRegExCharString) :: String -> Bool	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-			]-		 ) . Control.Arrow.second (-			(-				\extendedRegEx -> (-					RegEx./~ RegExOpts.MkRegExOpts {	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-						RegExOpts.compilationOptions	= Defaultable.defaultValue,-						RegExOpts.executionOptions	= executionOptions,-						RegExOpts.regEx			= extendedRegEx-					}-				)-			) &&& show . ExtendedRegExChar.MkExtendedRegExChar False {-hasNonCapturingTopLevelAlternatives-}-		 ) . testGenerator--run executionOptions maxTestComplexity (Right positiveTestRange)	= runPositiveTestRange positiveTestRange	where-	runPositiveTestRange :: GetAndRunTestRange Performance.ExtendedRegExTestsPositive.TestName-	runPositiveTestRange []		= runPositiveTestRange [minBound .. maxBound]	--Run all the tests, to the specified maximum 'Performance.ExtendedRegExTest.TestComplexity'.-	runPositiveTestRange testRange	= sequence_ $ (-		\complexity testGenerator	-> cpuSecondsFor testGenerator complexity >>= print-	 ) <$> [1 .. maxTestComplexity] <*> Data.Maybe.mapMaybe Performance.ExtendedRegExTest.query testRange	where-		cpuSecondsFor :: GenerateAndRunTest-		cpuSecondsFor testGenerator	= (-			\(inputData, (showMatch, extendedRegExCharString))	-> (,) extendedRegExCharString <$> (-				(TimePure.getCPUSeconds . ($ inputData)) `mapM` [-					showMatch,-					if ExecutionOptions.requireMatchList executionOptions-						then if solitary-							then const "<untested>"---							else (Text.Regex.Posix.=~ extendedRegExCharString) :: String -> String	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-							else (\(_, _, _, s) -> show s) . ((Text.Regex.Posix.=~ extendedRegExCharString) :: String -> (String, String, String, [String]))	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-						else show . if solitary-							then const True	--CAVEAT: should be 'undefined'.-							else (Text.Regex.Posix.=~ extendedRegExCharString) :: String -> Bool	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-				]-			)-		 ) . Control.Arrow.second (-			(-				\extendedRegEx -> let-					regExOpts :: RegExOpts.RegExOpts (RegEx.ExtendedRegEx Char)-					regExOpts	= RegExOpts.MkRegExOpts {-						RegExOpts.compilationOptions	= Defaultable.defaultValue,-						RegExOpts.executionOptions	= executionOptions,-						RegExOpts.regEx			= extendedRegEx-					} --Similar to 'RegexLike.makeRegexOpts', but without the requirement to read the regex.-				in if ExecutionOptions.requireMatchList executionOptions-					then show . (RegEx.+~ regExOpts)	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-					else show . (RegEx.=~ regExOpts)	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-			) &&& show . ExtendedRegExChar.MkExtendedRegExChar False {-hasNonCapturingTopLevelAlternatives-}-		 ) . testGenerator-
− src/Grecce/Performance/ExtendedRegExTest.hs
@@ -1,51 +0,0 @@-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]--	* Defines the types used for performance-testing.--	* Defines an interface to permit queries on repositories of 'TestGenerator's.--}--module Grecce.Performance.ExtendedRegExTest(--- * Type-classes-	TestGeneratorRepository(..),--- * Types--- ** Type-synonyms-	TestComplexity,-	Test,-	TestGenerator-) where--import qualified	RegExDot.RegEx	as RegEx---- | Used to specify the level of complexity of /regex/ to generate.-type TestComplexity	= Int---- | A pair defining the data & the /regex/ to which it should be fed.-type Test a	= (RegEx.InputData a, RegEx.ExtendedRegEx a)---- | The type of a function, which accepts a 'TestComplexity', & returns a 'Test'.-type TestGenerator a	= TestComplexity -> Test a---- | Implementer contracts to generate an appropriate 'Test'.-class TestGeneratorRepository a	where-	query	:: a -> Maybe (TestGenerator Char)	--CAVEAT: polymorphism reduced, to avoid requirement for non-portable Haskell-extensions.-
− src/Grecce/Performance/ExtendedRegExTestsNegative.hs
@@ -1,85 +0,0 @@-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]--	* Defines 'Performance.ExtendedRegExTest.TestGenerator's, for 'Performance.ExtendedRegExTest.Test's, which should fail.--	* Implements 'Performance.ExtendedRegExTest.TestGeneratorRepository'.--}--module Grecce.Performance.ExtendedRegExTestsNegative(--- * Types--- ** Data-types-	TestName-) where--import qualified	Control.Arrow-import qualified	Data.Maybe-import qualified	Grecce.Performance.ExtendedRegExTest		as Performance.ExtendedRegExTest-import qualified	Grecce.Performance.ExtendedRegExTestsPositive	as Performance.ExtendedRegExTestsPositive---- | Defines an enumeration of keys, by which to reference 'Performance.ExtendedRegExTest.TestGenerator's.-data TestName	=-	INTERLEAVED_GREEDY_STAR_VS_MANDATORY-	| LINEAR_FRACTAL_NONGREEDY_STAR-	| OVERLAPPING_ALTERNATIVES-	deriving (-		Bounded,-		Enum,-		Eq,-		Read,-		Show-	)--instance Performance.ExtendedRegExTest.TestGeneratorRepository TestName	where-	query	= (-		`lookup` [-{-- Explanation:	based on 'Performance.ExtendedRegExTestsPositive.INTERLEAVED_GREEDY_STAR_VS_MANDATORY', but with twice the input data following by a mismatch.- Performance:	vastly better performance than "Text.Regex.Posix", benefiting from 'ExecutionOptions.checkExistenceOfInelasticTail'.--}-			(-				INTERLEAVED_GREEDY_STAR_VS_MANDATORY,-				Control.Arrow.first ((++ "!") . concat . replicate 2) . Data.Maybe.fromJust (-					Performance.ExtendedRegExTest.query Performance.ExtendedRegExTestsPositive.INTERLEAVED_GREEDY_STAR_VS_MANDATORY-				)-			),-{-- Explanation:	based on 'Performance.ExtendedRegExTestsPositive.LINEAR_FRACTAL_NONGREEDY_STAR', but with mismatching input data, which causes the time-complexity explodes to O(n!).- Performance:	vastly better performance than "Text.Regex.Posix", benefiting from 'ExecutionOptions.checkForUnconsumableData'.--}-			(-				LINEAR_FRACTAL_NONGREEDY_STAR,-				Control.Arrow.first (++ "!") . Data.Maybe.fromJust (-					Performance.ExtendedRegExTest.query Performance.ExtendedRegExTestsPositive.LINEAR_FRACTAL_NONGREEDY_STAR-				)-			),-{-- Explanation:	based on 'Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES', but with mismatching input data.- Performance:	marginally better performance than "Text.Regex.Posix", benefiting from 'ExecutionOptions.checkForUnconsumableData' & 'ExecutionOptions.permitReorderingOfAlternatives'.--}-			(-				OVERLAPPING_ALTERNATIVES,-				Control.Arrow.first (++ "!") . Data.Maybe.fromJust (-					Performance.ExtendedRegExTest.query Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES-				)-			)-		]-	 )
− src/Grecce/Performance/ExtendedRegExTestsPositive.hs
@@ -1,329 +0,0 @@-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]--	* Defines 'Performance.ExtendedRegExTest.TestGenerator's, for 'Performance.ExtendedRegExTest.Test's, which should pass.--	* Implements 'Performance.ExtendedRegExTest.TestGeneratorRepository'.--}--module Grecce.Performance.ExtendedRegExTestsPositive(--- * Types--- ** Data-types-	TestName(..)--- * Functions---	triangularSeries-) where--import			Control.Arrow((&&&))-import			RegExDot.DSL((-:), (?:), (*:), (<~>))-import			RegExDot.RegEx((.*), (.*?))-import			RegExDot.Repeatable((^#->#), (^#->), (^#))-import qualified	Data.Char-import qualified	Grecce.Performance.ExtendedRegExTest	as Performance.ExtendedRegExTest-import qualified	RegExDot.Anchor				as Anchor-import qualified	RegExDot.BracketExpressionMember	as BracketExpressionMember-import qualified	RegExDot.Meta				as Meta-import qualified	RegExDot.RegEx				as RegEx-import qualified	RegExDot.Repeatable			as Repeatable---- | Defines an enumeration of keys, by which to reference 'Performance.ExtendedRegExTest.TestGenerator's.-data TestName	=-	BIPOLAR_GREEDY_OPTIONAL_VS_MANDATORY-	| INTERLEAVED_GREEDY_STAR_VS_MANDATORY-	| TRIANGULAR_CONSUMPTION-	| BINARY_TREE-	| REPEATABLE_ALTERNATIVES-	| REPEATED_ALTERNATIVES-	| LINEAR_FRACTAL_RANGES-	| LINEAR_FRACTAL_NONGREEDY_STAR-	| BINARY_TREE_FRACTAL-	| FUTILE_REPEATABLE_ALTERNATIVES-	| OVERLAPPING_ALTERNATIVES-	| UNBRIDLED_GREED-	| MULTIPLE_CHOICE-	deriving (-		Bounded,-		Enum,-		Eq,-		Read,-		Show-	)--instance Performance.ExtendedRegExTest.TestGeneratorRepository TestName	where-	query	= (-		`lookup` [-{-- "^(<testChar>?){<complexity>}(<testChar>){<complexity>}$".- Explanation:	each of the optional meta-data in the first half of the expression can capture data, but in doing so starves a mandatory meta-datum in the second half of the expression,-		presenting the opportunity for O(2^n) time-complexity backtracking.- Performance:	vastly better Boolean-result performance than "Text.Regex.Posix". Looks like O(n^2) time-complexity.--}-			(-				BIPOLAR_GREEDY_OPTIONAL_VS_MANDATORY,-				(`replicate` testChar) &&& let-					exactly :: Performance.ExtendedRegExTest.TestComplexity -> (RegEx.Pattern Char -> RegEx.RepeatablePattern Char) -> RegEx.RepeatablePattern Char-					exactly n f	= (RegEx.captureGroup . map ((Nothing, Nothing) <~>) . return {-to List-monad-} . return {-to List-monad-} $ f testRequirement) ^# n-				in ((Just Anchor.Bow, Just Anchor.Stern) <~>) . (`map` [Repeatable.zeroOrOne, Repeatable.one]) . exactly-			),-{-- "^(.*z){<complexity>}$".- Explanation:	each '.*' can consume all the remaining data, starving the interspersed mandatory meta data, presenting the opportunity for O(2^n) time-complexity backtracking.- Performance:	marginally better Boolean-result & data-capture performance than "Text.Regex.Posix" with 'ExecutionOptions.moderateGreed'. Empirically O(n^3) time-complexity.--}-			(-				INTERLEAVED_GREEDY_STAR_VS_MANDATORY,-				concat . (`replicate` (testChar : "z")) &&& RegEx.dock . (-					`mkExtendedRegExFromRepeatableSingletonAlternative` ((Nothing, Nothing) <~>) [-						(.*),-						RegEx.simply $ Meta.Literal 'z'-					]-				) . flip (^#)-			),-{-- "^<testChar>*<testChar>+<testChar>{2,}<testChar>{3,} ... a{<complexity>,}$".- Explanation:	each term greedily consumes all the data, starving all the remaining terms, until after much back-tracking, it consumes the just the minimum permissible.-		The correct consumption-pattern is triangular, starting at the apex & spreading into a delta.- Performance:	vastly better Boolean-result & data-capture performance than "Text.Regex.Posix".--}--			(-				TRIANGULAR_CONSUMPTION,-				(`replicate` testChar) . triangularSeries &&& ((Just Anchor.Bow, Just Anchor.Stern) <~>) . (`take` map (testRequirement ^#->) [0 ..]) . succ-			),-{-- "(<testChar>|<testChar>{2})*c".- Explanation:	from <http://www.haskell.org/pipermail/libraries/2009-March/011379.html>- Performance:	disastrous performance.--}-			(-				BINARY_TREE,-				(++ "bc") . (`replicate` testChar) . (2 ^) &&& const (-					(Nothing, Nothing) <~> RegEx.captureGroup (-						map (-							((Nothing, Nothing) <~>) . return {-to List-monad-} . (testRequirement ^#) . (2 ^)-						) [0 :: Int .. 1]-					) *: RegEx.Require (Meta.Literal 'c') -: []-				)-			),-{-- "^(<testChar>?|<testChar>{2}|<testChar>{4}|<testChar>{8}| ... |<testChar>{2^<complexity>})*$".- Explanation:	all but one of the 'Alternatives' must be used, one on each successive repetition, in order to consume all the 'InputData'.-		A correct implementation will match against the longest possible Alternative on each successive repetition, just as if the repetition were unrolled; see 'REPEATED_ALTERNATIVES'.- Performance:	vastly worse Boolean-result performance (even with 'ExecutionOptions.permitReorderingOfAlternatives'),-		& worse data-capture performance (even with 'ExecutionOptions.useFirstMatchAmongAlternatives'), than "Text.Regex.Posix".--}-			(-				REPEATABLE_ALTERNATIVES,-				(`replicate` testChar) . pred {-requires several different Alternatives-} . (2 ^) &&& (-					\i -> ((Just Anchor.Bow, Just Anchor.Stern) <~>) . return {-to List-monad-} . Repeatable.zeroOrMore . RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ [Repeatable.zeroOrOne testRequirement] : map (-						return {-to List-monad-} . (testRequirement ^#) . (2 ^)-					) [1 .. i]-				)-			),-{-- "^(<testChar>?|<testChar>{2}|<testChar>{4}| ... |<testChar>{2^<complexity>})(<testChar>?|<testChar>{2}|<testChar>{4}| ... |<testChar>{2^<complexity>})(<testChar>?|<testChar>{2}|<testChar>{4}| ... |<testChar>{2^<complexity>})$".- Explanation:	'REPEATABLE_ALTERNATIVES' with the repetition unrolled, to permit inspection of individual capture-groups,-		revealing the use by "Text.Regex.Posix", of Perl-style "1st-past-the-post" selection between Alternatives.- Performance:	much faster than 'REPEATABLE_ALTERNATIVES'. Vastly better Boolean-result & data-capture performance than both 'REPEATABLE_ALTERNATIVES' & "Text.Regex.Posix".--}-			(-				REPEATED_ALTERNATIVES,-				(`replicate` testChar) . pred {-requires several different Alternatives-} . (2 ^) &&& (-					\i -> ((Just Anchor.Bow, Just Anchor.Stern) <~>) . replicate i . Repeatable.one . RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ [Repeatable.zeroOrOne testRequirement] : map (-						return {-to List-monad-} . (testRequirement ^#) . (2 ^)-					) [1 .. i]-				)-			),-{-- "^((((<testChar>{0,2}){0,2}){0,2}){0,2}){0,2} ... $".- Explanation:- Performance:	vastly better Boolean-result performance than "Text.Regex.Posix", which exhausts memory at n==10. Better data-capture performance too.-		Stack-overflow at 'Performance.ExtendedRegExTest.TestComplexity'=14.--}-			(-				LINEAR_FRACTAL_RANGES,-				let-					base :: Repeatable.Repetitions-					base	= 2	--Arbitrarily.--					bounds :: Repeatable.RepetitionBounds-					bounds	= (0, Just base)-				in (`replicate` testChar) . (base ^) &&& RegEx.dock . (-					(-						mkExtendedRegExFromRepeatableSingletonAlternative (^#-># bounds) `iterate` ((Nothing, Nothing) <~>) [testRequirement ^#-># bounds] {-initial value-}-					) !!-				) . pred-			),-{-- "^((((((((((((((<testChar>*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*? ... $".- Explanation:	interesting because all 'RegEx.Alternatives' are expanded before the first comparison against input data, & the number possible repetitions of each expansion is very vague.- Performance:	vastly better Boolean-result performance than "Text.Regex.Posix", but inferior data-capture performance.--}-			(-				LINEAR_FRACTAL_NONGREEDY_STAR,-				const (replicate 8 {-arbitrary-} testChar) &&& RegEx.dock . (-					(-						mkExtendedRegExFromRepeatableSingletonAlternative Repeatable.zeroOrMore' `iterate` ((Nothing, Nothing) <~>) [Repeatable.zeroOrMore' testRequirement] {-initial value-}-					) !!-				)-			),-{-- "^((([^<testChar>]|<testChar>)|(<testChar>|[^<testChar>]))|((<testChar>|[^<testChar>])|([^<testChar>]|<testChar>)))$".- Explanation:	exhibits symmetry in the left & right branches of the binary tree of RegEx.Alternatives, & so the exponentially expanding set of leaves are equivalent & all match the data.- Performance:	vastly better Boolean-result & comparable data.capture performance to "Text.Regex.Posix", which exhausts memory at complexity 5 to 6, & to egrep which lasts until complexity==6.--}-			(-				BINARY_TREE_FRACTAL,-				let-					base :: Repeatable.Repetitions-					base	= 2	--Arbitrarily.-				in (`replicate` testChar) . (base ^) &&& RegEx.dock . head . (-					(-						iterate (-							\extendedRegExList -> (-								((Nothing, Nothing) <~>) . return {-to List-monad-} . (^# base) . RegEx.captureGroup-							) `map` [extendedRegExList, reverse extendedRegExList]-						) $ map (-							((Nothing, Nothing) <~>) . return {-to List-monad-} . ($ RegEx.Require $ Meta.Literal testChar)-						) [Repeatable.one, Repeatable.zeroOrOne]-					) !!-				)-			),-{-- "^(<testChar>1|<testChar>{2}2|<testChar>{3}3| ... |<testChar>{<complexity>}<complexity>)*<testChar>*$".- Explanation:	none of the Alternatives can match, & consequently the group must match zero times, presenting the opportunity for many wasted trial repetitions.- Performance:	comparable Boolean-result performance to "Text.Regex.Posix", & marginally superior data-capture performance.--}-			(-				FUTILE_REPEATABLE_ALTERNATIVES,-				\alternatives	-> (-					replicate 1024 {-arbitrarily-} testChar,-					((Just Anchor.Bow, Just Anchor.Stern) <~>) $ map Repeatable.zeroOrMore [-						RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ (-							\i -> ($ i) `map` [-								(testRequirement ^#),-								RegEx.simply . Meta.Literal . Data.Char.chr . (Data.Char.ord '0' +) . (`mod` 10)-							]-						) `map` [1 .. alternatives],-						testRequirement-					]-				)-			),-{-- "^a?((ab?)*|(bc?)*|(cd?)*| ...)*$".- Explanation:	the zeroeth term matches greedily, consuming the datum mandated by the 1st Alternative, so the 2nd Alternative greedily consumes two data, including the datum mandated by the 3rd, ...-		If there're an even number of Alternatives, then n/2 repetitions (one for each), will consume all the input data, but otherwise the final input datum isn't consumed.-		The consumption back-tracks rapidly until the zeroeth term yields-up the initial datum, after which the odd Alternatives match consuming all the input data, in (n/2 + 1) repetitions.-		This suggests a very tractable O(n) time-complexity, but Posix requires that we select the combination of Alternatives which consume most data,-		& since there are two terms in the regex that can consume each input datum, it looks like there should be 2^n candidate solutions; in fact there's just one.-		So, all O(Alternatives ^ repetitions) permutations may be searched in vain for a superior solution.- Performance:	vastly worse Boolean-result performance than "Text.Regex.Posix", but the latter then stalls indefinitely (CPU-bound) at complexity=[13 (not verbose), 4 (verbose)].--}-			(-				OVERLAPPING_ALTERNATIVES,-				let-					bracket :: a -> [a] -> [a]-					bracket terminal	= (terminal :) . (++ [terminal])--					zeroOrMoreAlternatives :: [RegEx.Concatenation Char] -> RegEx.Concatenation Char-					zeroOrMoreAlternatives	= return {-to List-monad-} . Repeatable.zeroOrMore . RegEx.captureGroup . map ((Nothing, Nothing) <~>)-				in (-					id &&& (-						((Just Anchor.Bow, Just Anchor.Stern) <~>) . (RegEx.Require (Meta.Literal testChar) ?:) . zeroOrMoreAlternatives . map (-							\(a, b)	-> zeroOrMoreAlternatives $ return {-to List-monad-} [a, b]-						) . init . tail . uncurry zip . (-							map Repeatable.one . init &&& map Repeatable.zeroOrOne . tail-						) . bracket undefined . map (-							RegEx.Require . Meta.Literal-						)-					)-				) . (`take` (filter Data.Char.isAlphaNum $ filter Data.Char.isAscii [minBound .. maxBound])) . succ-			),-{-- "^(a|b|c)*(a.*?c){3}$".- Explanation:	zero repetitions of the set of Alternatives on the LHS is the only solution, but because the greedy star, within which they're grouped, permits many more,-		& because the RHS's requirement for all the input-data, isn't explicit, there's a temptation to over-consume.- Performance:	empirically O(2^n) time-complexity, but linearised by 'ExecutionOptions.moderateGreed'.-		Better Boolean-result & data-capture performance than "Text.Regex.Posix".--}-			(-				UNBRIDLED_GREED,-				\complexity	-> let-					complexity' :: Performance.ExtendedRegExTest.TestComplexity-					complexity'	= 1 + complexity--					testSet :: String-					testSet	= take complexity' . filter Data.Char.isAlphaNum $ filter Data.Char.isAscii [minBound .. maxBound]-				in (-					concat $ replicate complexity' testSet,-					((Just Anchor.Bow, Just Anchor.Stern) <~>) $ (-						RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ map (-							return {-to List-monad-} . RegEx.simply . Meta.Literal-						) testSet-					) *: [-						(-							RegEx.captureGroup . map ((Nothing, Nothing) <~>) . return {-to List-monad-} $ RegEx.Require (Meta.Literal $ head testSet) -: (.*?) : RegEx.Require (Meta.Literal $ last testSet) -: []-						) ^# complexity'-					]-				)-			),-{-- "^(a*[^a]|[^b]|[^c]| ... |[^z])*$"- Explanation:	The first alternative greedily consumes all the input data until finding a mismatch on the last, whilst all the remaining alternatives successfully consume a single input datum.-		The same occurs on each successive repetition of the alternatives, of which there are as many as input data,-		leading to a lot of wasted time with O(<alternatives> ^ <input data>) time-complexity.- Performance:	poor Boolean-result & worse data-capture performance (benefiting from 'ExecutionOptions.useFirstMatchAmongAlternatives'), compared to "Text.Regex.Posix".--}-			(-				MULTIPLE_CHOICE,-				const (replicate 8 {-arbitrary-} testChar) &&& (-					((Just Anchor.Bow, Just Anchor.Stern) <~>) . return {-to List-monad-} . Repeatable.zeroOrMore . RegEx.captureGroup . map ((Nothing, Nothing) <~>) . (-						[-							Repeatable.zeroOrMore testRequirement,-							RegEx.simply . Meta.NoneOf $ map BracketExpressionMember.Literal [testChar]-						] :-					) . map (-						return {-to List-monad-} . RegEx.simply . Meta.NoneOf . return {-to List-monad-} . BracketExpressionMember.Literal-					) . (-						`take` tail [testChar ..]-					)-				)-			)-		]-	 ) where-		testChar :: Char-		testChar	= 'a'--		testRequirement :: RegEx.Pattern Char-		testRequirement	= RegEx.Require $ Meta.Literal testChar--		mkExtendedRegExFromRepeatableSingletonAlternative :: (RegEx.Pattern Char -> RegEx.RepeatablePattern Char) -> RegEx.ExtendedRegEx Char -> RegEx.ExtendedRegEx Char-		mkExtendedRegExFromRepeatableSingletonAlternative makeRepetitions	= ((Nothing, Nothing) <~>) . return {-to List-monad-} . makeRepetitions . RegEx.captureGroup . return {-to List-monad-}--{- |-	* The sum of the sequence descending from the specified integer; @n + (n - 1) + (n - 2) + ... + 2 + 1 + 0@.--	* <http://en.wikipedia.org/wiki/Triangular_number>.--	* <http://mathworld.wolfram.com/TriangularNumber.html>.--}-triangularSeries :: Integral i => i -> i-triangularSeries i	= i * (i + 1) `div` 2
− src/Grecce/QC/ExtendedRegExChar.hs
@@ -1,205 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' & defines tests based on it.--}--module Grecce.QC.ExtendedRegExChar(--- * Types--- ** Data-types---	AlternativesChar(..),---	PatternChar(..),---	RepeatablePatternChar(..),--- ** Type-synonyms---	Testable,--- * Functions---	deconstructAlternativesChar,---	deconstructPatternChar,---	deconstructRepeatablePatternChar,-	quickChecks-) where--import			Control.Applicative((<$>))-import			Grecce.QC.MetaChar()-import			RegExDot.DSL((-:), (?:), (+:), (<~>))-import			RegExDot.RegEx((+~))-import			Test.QuickCheck((==>))-import qualified	RegExChar.ExtendedRegExChar		as ExtendedRegExChar	--CAVEAT: beware of the similar name.-import qualified	RegExChar.MetaChar			as MetaChar-import qualified	RegExDot.Anchor				as Anchor-import qualified	RegExDot.BracketExpressionMember	as BracketExpressionMember-import qualified	RegExDot.Consumer			as Consumer-import qualified	RegExDot.ConsumptionBounds		as ConsumptionBounds-import qualified	RegExDot.ConsumptionProfile		as ConsumptionProfile-import qualified	RegExDot.Meta				as Meta-import qualified	RegExDot.RegEx				as RegEx-import qualified	RegExDot.RegExOpts			as RegExOpts-import qualified	RegExDot.Repeatable			as Repeatable-import qualified	RegExDot.Result				as Result-import qualified	Test.QuickCheck-import qualified	ToolShed.SelfValidate			as SelfValidate---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype AlternativesChar	= MkAlternativesChar (RegEx.Alternatives Char) deriving (Eq, Read, Show)---- | Accessor.-deconstructAlternativesChar :: AlternativesChar -> RegEx.Alternatives Char-deconstructAlternativesChar (MkAlternativesChar a)	= a--instance SelfValidate.SelfValidator AlternativesChar where-	isValid	= SelfValidate.isValid . deconstructAlternativesChar--instance Consumer.Consumer AlternativesChar where-	consumptionProfile	= Consumer.consumptionProfile . deconstructAlternativesChar-	starHeight		= Consumer.starHeight . deconstructAlternativesChar--instance Test.QuickCheck.Arbitrary AlternativesChar	where-	arbitrary	= MkAlternativesChar . RegEx.MkAlternatives . map ExtendedRegExChar.extendedRegEx <$> (-		Test.QuickCheck.elements [1, 2]	>>= Test.QuickCheck.vector {-[ExtendedRegExChar]-}-	 ) --TODO: permit zero alternatives.-#if !(MIN_VERSION_QuickCheck(2,1,0))-	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.-#endif---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype PatternChar	= MkPatternChar (RegEx.Pattern Char) deriving (Eq, Read, Show)---- | Accessor.-deconstructPatternChar :: PatternChar -> RegEx.Pattern Char-deconstructPatternChar (MkPatternChar pattern)	= pattern--instance SelfValidate.SelfValidator PatternChar	where-	isValid	= SelfValidate.isValid . deconstructPatternChar--instance Consumer.Consumer PatternChar	where-	consumptionProfile	= Consumer.consumptionProfile . deconstructPatternChar-	starHeight		= Consumer.starHeight . deconstructPatternChar--instance Test.QuickCheck.Arbitrary PatternChar	where-	arbitrary	= MkPatternChar <$> Test.QuickCheck.frequency [-		(4,	RegEx.Require . MetaChar.deconstruct <$> Test.QuickCheck.arbitrary {-MetaChar-}),-		(1,	RegEx.CaptureGroup . deconstructAlternativesChar <$> Test.QuickCheck.arbitrary {-AlternativesChar-})-	 ] --CAVEAT: may recurse forever if 'RegEx.CaptureGroup / RegEx.Require' is too high.-#if ! (MIN_VERSION_QuickCheck(2,1,0))-	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.-#endif---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype RepeatablePatternChar	= MkRepeatablePatternChar (Repeatable.Repeatable PatternChar)	deriving (Eq, Read, Show)---- | Accessor.-deconstructRepeatablePatternChar :: RepeatablePatternChar -> Repeatable.Repeatable PatternChar-deconstructRepeatablePatternChar (MkRepeatablePatternChar repeatable)	= repeatable--instance SelfValidate.SelfValidator RepeatablePatternChar	where-	isValid	= SelfValidate.isValid . deconstructRepeatablePatternChar--instance Consumer.Consumer RepeatablePatternChar	where-	consumptionProfile	= Consumer.consumptionProfile . deconstructRepeatablePatternChar-	starHeight		= Consumer.starHeight . deconstructRepeatablePatternChar--instance Test.QuickCheck.Arbitrary RepeatablePatternChar	where-	arbitrary	= do-		patternChar	<- Test.QuickCheck.arbitrary-		fewest		<- Test.QuickCheck.elements [0 .. 9]	--Could be more, but this is an adequate test.-		most		<- Test.QuickCheck.oneof [return {-to Gen-monad-} Nothing, Just <$> Test.QuickCheck.elements [max fewest 1 .. 9]]-		isGreedy	<- Test.QuickCheck.arbitrary {-Bool-}--		let-			repetitionBounds :: Repeatable.RepetitionBounds-			repetitionBounds	= (fewest, most)--		return {-to Gen-monad-} $ MkRepeatablePatternChar Repeatable.MkRepeatable {-			Repeatable.base			= patternChar,-			Repeatable.repetitionBounds	= repetitionBounds,-			Repeatable.isGreedy		= Repeatable.hasPreciseBounds repetitionBounds || isGreedy	--Only specify non-greedy where space exists.-		}-#if ! (MIN_VERSION_QuickCheck(2,1,0))-	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.-#endif--instance Test.QuickCheck.Arbitrary ExtendedRegExChar.ExtendedRegExChar	where-	arbitrary	= do-		hasBowAnchor	<- Test.QuickCheck.arbitrary {-Bool-}-		concatenation	<- map ((deconstructPatternChar <$> {-replace base-}) . deconstructRepeatablePatternChar {-Repeatable.Repeatable PatternChar-}) <$> Test.QuickCheck.vector 2 {-[RepeatablePatternChar]-}-		hasSternAnchor	<- Test.QuickCheck.arbitrary {-Bool-}--		return {-to Gen-monad-} $ ExtendedRegExChar.MkExtendedRegExChar False RegEx.MkExtendedRegEx {-			RegEx.bowAnchor		= if hasBowAnchor then Just Anchor.Bow else Nothing,-			RegEx.concatenation	= concatenation,-			RegEx.sternAnchor	= if hasSternAnchor then Just Anchor.Stern else Nothing-		}--#if ! (MIN_VERSION_QuickCheck(2,1,0))-	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.-#endif--type Testable	= ExtendedRegExChar.ExtendedRegExChar -> Test.QuickCheck.Property---- | Defines invariant properties, which must hold for any 'ExtendedRegExChar.ExtendedRegExChar'.-quickChecks :: (Testable -> IO ()) -> IO ()-quickChecks checker	= quickChecks1 >> quickChecks2	where-	quickChecks1	= checker `mapM_` [prop_consumptionProfile, prop_consumptionProfile2, prop_io, prop_io', prop_isValid, prop_starHeight]	where-		prop_consumptionProfile, prop_consumptionProfile2, prop_io, prop_io', prop_isValid, prop_starHeight :: Testable-		prop_consumptionProfile r	= Test.QuickCheck.label "prop_consumptionProfile" $ (-			case maybeMaxData of-				Nothing	-> True-				Just m	-> m >= minData-		 ) && (-			not b == all (not . Consumer.getHasSpecificRequirement) (RegEx.concatenation $ ExtendedRegExChar.extendedRegEx r)-		 )-			where-				ConsumptionProfile.MkConsumptionProfile {-					ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),-					ConsumptionProfile.hasSpecificRequirement	= b-				} = Consumer.consumptionProfile r--		prop_consumptionProfile2 r	= RegEx.isDefined (ExtendedRegExChar.extendedRegEx r)	==> Test.QuickCheck.label "prop_consumptionProfile2" $ or [hasSpecificRequirement, canConsumeAnything]	--There's either; a requirement for at least one specific, or we can consume at least one arbitrary; input datum.-			where-				ConsumptionProfile.MkConsumptionProfile {-					ConsumptionProfile.hasSpecificRequirement	= hasSpecificRequirement,-					ConsumptionProfile.canConsumeAnything		= canConsumeAnything-				} = Consumer.consumptionProfile r--		prop_io r		= Test.QuickCheck.label "prop_io" $ read (show r) == r-		prop_io' r		= Test.QuickCheck.label "prop_io'" $ read (show r') == r'	where r' = ExtendedRegExChar.extendedRegEx r	--Check "RegEx.ExtendedRegEx Char" too.-		prop_isValid r		= Test.QuickCheck.label "prop_isValid" $ SelfValidate.isValid r-		prop_starHeight r	= Test.QuickCheck.label "prop_starHeight" $ (Consumer.starHeight r == 0) == ConsumptionBounds.isPrecise (Consumer.getConsumptionBounds r)--	quickChecks2	= Test.QuickCheck.quickCheck {-'checker' is technically the wrong type-} `mapM_` [prop_double]	where-		prop_double :: Double -> Test.QuickCheck.Property-		prop_double d	= Test.QuickCheck.label "prop_double" $ RegEx.extractDataFromMatchList `fmap` Result.getMatchList result == Just s	where-			s :: String-			s	= show $ d * 1e6	--Implementation of show, uses exponential notation, when the number is large.--			result :: RegEx.Result Char-			result = s +~ RegExOpts.mkRegEx (-				(Just Anchor.Bow, Just Anchor.Stern) <~> sign ?: digits +: map (-					Repeatable.zeroOrOne . RegEx.captureGroup . map ((Nothing, Nothing) <~>) . return {-to List-monad-}-				) [-					RegEx.Require (Meta.Literal '.') -: digits +: [],-					RegEx.Require (Meta.AnyOf $ map BracketExpressionMember.Literal "eE") -: sign ?: digits +: []-				]-			 ) where-				sign, digits :: RegEx.Pattern Char-				sign	= RegEx.Require . Meta.AnyOf $ map BracketExpressionMember.Literal "+-"-				digits	= RegEx.Require . Meta.AnyOf $ map BracketExpressionMember.Literal ['0' .. '9']-
− src/Grecce/QC/MetaChar.hs
@@ -1,78 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' & defines tests based on it.-- [@TODO@]	Test /Perl-style shortcuts/ & /Posix Character-classes/.--}--module Grecce.QC.MetaChar(--- * Types--- ** Type-synonyms---	Testable,--- * Constants---	testCharacters,--- * Functions-	quickChecks-) where--import			Control.Applicative((<$>))-import qualified	Data.List-import qualified	RegExChar.MetaChar			as MetaChar	--CAVEAT: beware of the similar name.-import qualified	RegExDot.BracketExpression		as BracketExpression-import qualified	RegExDot.BracketExpressionMember	as BracketExpressionMember-import qualified	RegExDot.Meta				as Meta-import qualified	Test.QuickCheck---- CAVEAT: module "Test.QuickCheck.Arbitrary" defines an instance of this from package "Quickcheck-2.1.0.1".-#if !(MIN_VERSION_QuickCheck(2,1,0))-instance Test.QuickCheck.Arbitrary Char	where-	arbitrary	= Test.QuickCheck.elements testCharacters-	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.-#endif--testCharacters :: String-testCharacters	= filter (`notElem` [Meta.shortcutToken, BracketExpression.negationToken]) [' ' .. '~']	--TODO: permit all characters.--instance Test.QuickCheck.Arbitrary MetaChar.MetaChar	where-	arbitrary	= Test.QuickCheck.oneof $ map (MetaChar.MkMetaChar <$>) [-		return {-to Gen-monad-} Meta.Any,-		Meta.Literal <$> Test.QuickCheck.elements testCharacters,-		Meta.AnyOf . map BracketExpressionMember.Literal . Data.List.nub <$> arbitraryCharList 1 16,	--Test.QuickCheck.vector 16 {-Char-},-		Meta.NoneOf . map BracketExpressionMember.Literal . Data.List.nub <$> arbitraryCharList 1 4-	 ] where-		arbitraryCharList :: Int -> Int -> Test.QuickCheck.Gen String-		arbitraryCharList i j	= do-			l	<- Test.QuickCheck.arbitrary {-Int-}--			take (min j $ i `max` l) . Data.List.nub . Data.List.filter (`elem` testCharacters) <$> Test.QuickCheck.vector maxBound {-Char-}-#if ! (MIN_VERSION_QuickCheck(2,1,0))-	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.-#endif--type Testable	= MetaChar.MetaChar -> Test.QuickCheck.Property---- | Defines invariant properties, which must hold for any 'MetaChar.MetaChar'.-quickChecks :: (Testable -> IO ()) -> IO ()-quickChecks checker	= checker `mapM_` [prop_io]	where-	prop_io :: Testable-	prop_io m	= Test.QuickCheck.label "prop_io" $ read (show m) == m-
− src/Grecce/QC/QuickChecks.hs
@@ -1,52 +0,0 @@-{-# LANGUAGE CPP #-}-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]	Calls the /quickChecks/-functions for modules supporting this feature.--}--module Grecce.QC.QuickChecks(--- * Functions-	run-) where--import qualified	Grecce.QC.ExtendedRegExChar	as QC.ExtendedRegExChar-import qualified	Grecce.QC.MetaChar		as QC.MetaChar-import qualified	Grecce.QC.RepeatableMetaChar	as QC.RepeatableMetaChar-import qualified	Test.QuickCheck--{- |	Run the /quickChecks/-functions for modules supporting this feature.-	The single Boolean flag enables verbose output.--}-run :: Bool -> IO ()-run isVerbose	=-	putStrLn "MetaChar"			>> QC.MetaChar.quickChecks checker-	>> putStrLn "RepeatableMetaChar"	>> QC.RepeatableMetaChar.quickChecks checker-	>> putStrLn "ExtendedRegExChar"		>> QC.ExtendedRegExChar.quickChecks checker-	where-		checker :: Test.QuickCheck.Testable t => t -> IO ()-		checker-			| isVerbose	=-#if MIN_VERSION_QuickCheck(2,4,0)-				Test.QuickCheck.verboseCheck-#else-				error "Grecce.QC.QuickChecks:\t'Test.QuickCheck.verboseCheck' is only available as of 'QuickCheck-2.4'."-#endif-			| otherwise	= Test.QuickCheck.quickCheck-
− src/Grecce/QC/RepeatableMetaChar.hs
@@ -1,98 +0,0 @@-{-# LANGUAGE CPP #-}-{--	Copyright (C) 2010 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-	the Free Software Foundation, either version 3 of the License, or-	(at your option) any later version.--	This program is distributed in the hope that it will be useful,-	but WITHOUT ANY WARRANTY; without even the implied warranty of-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-	GNU General Public License for more details.--	You should have received a copy of the GNU General Public License-	along with this program.  If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@]	Dr. Alistair Ward-- [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' & defines tests based on it.--}--module Grecce.QC.RepeatableMetaChar(--- * Types--- ** Data-types---	RepeatableMetaChar,--- ** Type-synonyms---	Testable,--- * Functions---	deconstruct,-	quickChecks-) where--import			Control.Applicative((<$>))-import			Grecce.QC.MetaChar()-import qualified	RegExChar.MetaChar		as MetaChar-import qualified	RegExDot.Consumer		as Consumer-import qualified	RegExDot.ConsumptionBounds	as ConsumptionBounds-import qualified	RegExDot.ConsumptionProfile	as ConsumptionProfile-import qualified	RegExDot.Repeatable		as Repeatable-import qualified	Test.QuickCheck-import qualified	ToolShed.SelfValidate		as SelfValidate---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype RepeatableMetaChar	= MkRepeatableMetaChar (Repeatable.Repeatable MetaChar.MetaChar)	deriving (Eq, Read, Show)---- | Accessor.-deconstruct :: RepeatableMetaChar -> Repeatable.Repeatable MetaChar.MetaChar-deconstruct (MkRepeatableMetaChar repeatableMetaChar)	= repeatableMetaChar--instance SelfValidate.SelfValidator RepeatableMetaChar	where-	isValid	= SelfValidate.isValid . deconstruct--instance Consumer.Consumer RepeatableMetaChar	where-	consumptionProfile	= Consumer.consumptionProfile . deconstruct-	starHeight		= Consumer.starHeight . deconstruct--instance Test.QuickCheck.Arbitrary RepeatableMetaChar	where-	arbitrary	= do-		metaChar	<- Test.QuickCheck.arbitrary-		fewest		<- Test.QuickCheck.elements [0 .. 9]	--Could be more, but this is an adequate test.-		most		<- Test.QuickCheck.oneof [return Nothing, Just <$> Test.QuickCheck.elements [max fewest 1 .. 9]]-		isGreedy	<- Test.QuickCheck.arbitrary--		let-			repetitionBounds :: Repeatable.RepetitionBounds-			repetitionBounds	= (fewest, most)--		return {-to Gen-monad-} . MkRepeatableMetaChar $ Repeatable.MkRepeatable {-			Repeatable.base			= metaChar,-			Repeatable.repetitionBounds	= repetitionBounds,-			Repeatable.isGreedy		= Repeatable.hasPreciseBounds repetitionBounds || isGreedy	--Only specify 'non-greedy' where space exists.-		}-#if !(MIN_VERSION_QuickCheck(2,1,0))-	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.-#endif--type Testable	= RepeatableMetaChar -> Test.QuickCheck.Property---- | Defines invariant properties, which must hold for any 'RepeatableMetaChar'.-quickChecks :: (Testable -> IO ()) -> IO ()-quickChecks checker	= checker `mapM_` [prop_consumptionProfile, prop_io, prop_isValid, prop_starHeight]	where-	prop_consumptionProfile, prop_io, prop_isValid, prop_starHeight :: Testable-	prop_consumptionProfile r	= Test.QuickCheck.label "prop_consumptionProfile" $ (-		case maybeMaxData of-			Nothing	-> True-			Just m	-> m >= minData-	 ) && (-		b == Consumer.getHasSpecificRequirement (Repeatable.base $ deconstruct r)-	 ) where ConsumptionProfile.MkConsumptionProfile {-		ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),-		ConsumptionProfile.hasSpecificRequirement	= b-	 } = Consumer.consumptionProfile r-	prop_io (MkRepeatableMetaChar r)		= Test.QuickCheck.label "prop_io" $ read (show r) == r-	prop_isValid r					= Test.QuickCheck.label "prop_isValid" $ SelfValidate.isValid r-	prop_starHeight (MkRepeatableMetaChar r)	= Test.QuickCheck.label "prop_starHeight" $ Consumer.starHeight r == if ConsumptionBounds.isPrecise (Consumer.getConsumptionBounds r) then 0 else 1-
+ src/Grecce/Test/Assert/RegExOptsChar.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE FlexibleContexts #-}+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]++	* Reads lines from the specified file.++	* Each line describes a 'Test'.++	* Each input-data string should match the /regex/ in the specified way.++	* Permits comparison with "Text.Regex.Posix.String".+-}++module Grecce.Test.Assert.RegExOptsChar(+-- * Types+-- ** Type-synonyms+--	Test,+--	TestDataAndResult,+--	TestFilter,+-- * Functions+	findFailures,+	findFailuresPosix,+	readTests+-- ** Predicates+--	isMatch+) where++import			Control.Applicative((<$>))+import qualified	Control.Arrow+import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar+import qualified	RegExChar.RegExOptsChar		as RegExOptsChar	--CAVEAT: beware of the similar name.+import qualified	RegExDot.CompilationOptions	as CompilationOptions+import qualified	RegExDot.ExecutionOptions	as ExecutionOptions+import qualified	Text.Regex.Base.RegexLike	as RegexLike+import qualified	Text.Regex.Posix.Wrap+import			Text.Regex.Posix()++-- | Composed input data & list of captured 'RegExOptsChar.MatchSpan'.+type TestDataAndResult	= (ExtendedRegExChar.InputData, [RegExOptsChar.MatchSpan])++-- | Composed of the 'String' from which an unspecified type of regex is read, & a list of input data & results, to which it should respectively be applied & compared.+type Test		= (String {-regex-source-}, [TestDataAndResult])++-- | Filters a list of 'Test's, & returns a sub-set.+type TestFilter		= [Test] -> [Test]++-- | 'True' if the specified 'ExtendedRegExChar.InputData', is a member of the set defined by the polymorphic 'Text.Regex.Base.RegexLike.RegexLike' parameter.+isMatch :: RegexLike.RegexLike r ExtendedRegExChar.InputData => r -> TestDataAndResult -> Bool+isMatch regex (inputData, matchSpanList)	= RegexLike.matchOnce regex inputData == Just (RegExOptsChar.toZeroIndexedArray matchSpanList)++-- | Returns those 'Test's, which 'RegExOptsChar.RegExOptsChar' fails.+findFailures :: CompilationOptions.CompilationOptions -> ExecutionOptions.ExecutionOptions -> TestFilter+findFailures compilationOptions executionOptions	= filter (not . uncurry all . Control.Arrow.first (isMatch . RegexLike.makeRegexOpts compilationOptions executionOptions))++-- | Returns those 'Test's, which 'Text.Regex.Posix.Wrap.Regex' fails.+findFailuresPosix :: TestFilter+findFailuresPosix	= filter (not . uncurry all . Control.Arrow.first ((isMatch :: Text.Regex.Posix.Wrap.Regex -> TestDataAndResult -> Bool) . RegexLike.makeRegex))++{- |+	* Read 'Test's from file, ignoring blank lines & comments.++	* To facilitate parsing, each line in the file has the format of @show Test@.+-}+readTests :: String -> IO [Test]+readTests fileName	= map (+	\line	-> case reads line of+		[(test, _)]	-> test+		_		-> error $ "Grecce.Test.Assert.RegExOptsChar.readTests:\tfailed to read 'Test' from '" ++ line ++ "'"+ ) . filter (+	(/= '#') . head	--Remove comments.+ ) . filter (+	not . null	--Remove blank lines.+ ) . lines <$> readFile fileName+
+ src/Grecce/Test/Performance/ExtendedRegEx.hs view
@@ -0,0 +1,144 @@+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]++	* CPU-times the specified stress-test(s), over a hard-coded list of /regex/-engines,+	providing each combination with a varied list of 'Performance.ExtendedRegExTest.TestGenerator's,+	& a level of 'Performance.ExtendedRegExTest.TestComplexity' which increases linearly to the specified cap.++	* Either a simple 'Bool' result, or the full data-capture, can be requested.++ [@CAVEATS@]++	* For compatibility with the other regex-engines, uses the specialised instance 'ExtendedRegExChar.ExtendedRegExChar',+	rather than the underlying polymorphic 'RegEx.ExtendedRegEx'.++	* "Text.Regex.Posix" stalls forever on 'Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES',+	with 'Performance.ExtendedRegExTest.TestComplexity'=3 & data-capture requested.++ [@TODO@]++	* Utilise the standard interface in "RegExOptsChar", to permit identical treatment of different regex-engines.+-}++module Grecce.Test.Performance.ExtendedRegEx(+-- * Types+-- ** Type-synonyms+--	GenerateAndRunTest,+--	GetAndRunTestRange,+-- * Constants+--	solitary,+-- * Functions+	run+--	tailorTest+) where++import			Control.Applicative((<$>), (<*>))+import			Control.Arrow((&&&))+import qualified	Control.Arrow+import qualified	Data.Maybe+import qualified	Grecce.Test.Performance.ExtendedRegExTest		as Test.Performance.ExtendedRegExTest+import qualified	Grecce.Test.Performance.ExtendedRegExTestsNegative	as Test.Performance.ExtendedRegExTestsNegative+import qualified	Grecce.Test.Performance.ExtendedRegExTestsPositive	as Test.Performance.ExtendedRegExTestsPositive+import qualified	RegExChar.ExtendedRegExChar				as ExtendedRegExChar+import qualified	RegExDot.ExecutionOptions				as ExecutionOptions+import qualified	RegExDot.RegEx						as RegEx+import qualified	RegExDot.RegExOpts					as RegExOpts+import qualified	Text.Regex.Posix+import qualified	ToolShed.Defaultable					as Defaultable+import qualified	ToolShed.TimePure					as TimePure++solitary :: Bool+solitary	= True	--Currently required because of the disastrous performance of "Text.Regex.Posix" on 'Test.Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES'.++type GetAndRunTestRange a	= [a] -> IO ()+type GenerateAndRunTest		= Test.Performance.ExtendedRegExTest.TestGenerator Char -> Test.Performance.ExtendedRegExTest.TestComplexity -> IO (ExtendedRegExChar.InputData, [(Double, String)])++{- |+	* Print the CPU-seconds, required to run the range of 'Test.Performance.ExtendedRegExTest.TestGenerator's corresponding to the specified test-names & a linearly increasing 'Test.Performance.ExtendedRegExTest.TestComplexity'.++	* If the specified maximum 'Test.Performance.ExtendedRegExTest.TestComplexity' is set to the special value '0', then it is increased linearly, without limit.+-}+run :: ExecutionOptions.ExecutionOptions -> Test.Performance.ExtendedRegExTest.TestComplexity -> Either [Test.Performance.ExtendedRegExTestsNegative.TestName] [Test.Performance.ExtendedRegExTestsPositive.TestName] -> IO ()+run executionOptions 0 testRange					= run executionOptions maxBound testRange	--Run the specified test-range, without any upper bound to 'Test.Performance.ExtendedRegExTest.TestComplexity'.+run executionOptions maxTestComplexity (Left negativeTestRange)		= runNegativeTestRange negativeTestRange	where+	runNegativeTestRange :: GetAndRunTestRange Test.Performance.ExtendedRegExTestsNegative.TestName+	runNegativeTestRange []		= runNegativeTestRange [minBound .. maxBound]	--Run all the tests, to the specified maximum 'Test.Performance.ExtendedRegExTest.TestComplexity'.+	runNegativeTestRange testRange	= sequence_ $ (+		\complexity testGenerator	-> cpuSecondsFor testGenerator complexity >>= print+	 ) <$> [1 .. maxTestComplexity] <*> Data.Maybe.mapMaybe Test.Performance.ExtendedRegExTest.query testRange	where+		cpuSecondsFor :: GenerateAndRunTest+		cpuSecondsFor testGenerator	= (+			\(inputData, (isMismatch, extendedRegExCharString))	-> (,) extendedRegExCharString <$> mapM (+				TimePure.getCPUSeconds . ($ inputData) . (show .)+			 ) [+				isMismatch,+				if solitary+					then const True	--CAVEAT: should be 'undefined'.+					else not . (Text.Regex.Posix.=~ extendedRegExCharString) :: String -> Bool	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+			]+		 ) . Control.Arrow.second (+			(+				\extendedRegEx -> (+					RegEx./~ RegExOpts.MkRegExOpts {	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+						RegExOpts.compilationOptions	= Defaultable.defaultValue,+						RegExOpts.executionOptions	= executionOptions,+						RegExOpts.regEx			= extendedRegEx+					}+				)+			) &&& show . ExtendedRegExChar.MkExtendedRegExChar False {-hasNonCapturingTopLevelAlternatives-}+		 ) . testGenerator++run executionOptions maxTestComplexity (Right positiveTestRange)	= runPositiveTestRange positiveTestRange	where+	runPositiveTestRange :: GetAndRunTestRange Test.Performance.ExtendedRegExTestsPositive.TestName+	runPositiveTestRange []		= runPositiveTestRange [minBound .. maxBound]	--Run all the tests, to the specified maximum 'Test.Performance.ExtendedRegExTest.TestComplexity'.+	runPositiveTestRange testRange	= sequence_ $ (+		\complexity testGenerator	-> cpuSecondsFor testGenerator complexity >>= print+	 ) <$> [1 .. maxTestComplexity] <*> Data.Maybe.mapMaybe Test.Performance.ExtendedRegExTest.query testRange	where+		cpuSecondsFor :: GenerateAndRunTest+		cpuSecondsFor testGenerator	= (+			\(inputData, (showMatch, extendedRegExCharString))	-> (,) extendedRegExCharString <$> (+				(TimePure.getCPUSeconds . ($ inputData)) `mapM` [+					showMatch,+					if ExecutionOptions.requireMatchList executionOptions+						then if solitary+							then const "<untested>"+--							else (Text.Regex.Posix.=~ extendedRegExCharString) :: String -> String	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+							else (\(_, _, _, s) -> show s) . ((Text.Regex.Posix.=~ extendedRegExCharString) :: String -> (String, String, String, [String]))	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+						else show . if solitary+							then const True	--CAVEAT: should be 'undefined'.+							else (Text.Regex.Posix.=~ extendedRegExCharString) :: String -> Bool	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+				]+			)+		 ) . Control.Arrow.second (+			(+				\extendedRegEx -> let+					regExOpts :: RegExOpts.RegExOpts (RegEx.ExtendedRegEx Char)+					regExOpts	= RegExOpts.MkRegExOpts {+						RegExOpts.compilationOptions	= Defaultable.defaultValue,+						RegExOpts.executionOptions	= executionOptions,+						RegExOpts.regEx			= extendedRegEx+					} --Similar to 'RegexLike.makeRegexOpts', but without the requirement to read the regex.+				in if ExecutionOptions.requireMatchList executionOptions+					then show . (RegEx.+~ regExOpts)	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+					else show . (RegEx.=~ regExOpts)	--CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+			) &&& show . ExtendedRegExChar.MkExtendedRegExChar False {-hasNonCapturingTopLevelAlternatives-}+		 ) . testGenerator+
+ src/Grecce/Test/Performance/ExtendedRegExTest.hs view
@@ -0,0 +1,51 @@+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]++	* Defines the types used for performance-testing.++	* Defines an interface to permit queries on repositories of 'TestGenerator's.+-}++module Grecce.Test.Performance.ExtendedRegExTest(+-- * Type-classes+	TestGeneratorRepository(..),+-- * Types+-- ** Type-synonyms+	TestComplexity,+	Test,+	TestGenerator+) where++import qualified	RegExDot.RegEx	as RegEx++-- | Used to specify the level of complexity of /regex/ to generate.+type TestComplexity	= Int++-- | A pair defining the data & the /regex/ to which it should be fed.+type Test a	= (RegEx.InputData a, RegEx.ExtendedRegEx a)++-- | The type of a function, which accepts a 'TestComplexity', & returns a 'Test'.+type TestGenerator a	= TestComplexity -> Test a++-- | Implementer contracts to generate an appropriate 'Test'.+class TestGeneratorRepository a	where+	query	:: a -> Maybe (TestGenerator Char)	--CAVEAT: polymorphism reduced, to avoid requirement for non-portable Haskell-extensions.+
+ src/Grecce/Test/Performance/ExtendedRegExTestsNegative.hs view
@@ -0,0 +1,85 @@+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]++	* Defines 'Performance.ExtendedRegExTest.TestGenerator's, for 'Performance.ExtendedRegExTest.Test's, which should fail.++	* Implements 'Performance.ExtendedRegExTest.TestGeneratorRepository'.+-}++module Grecce.Test.Performance.ExtendedRegExTestsNegative(+-- * Types+-- ** Data-types+	TestName+) where++import qualified	Control.Arrow+import qualified	Data.Maybe+import qualified	Grecce.Test.Performance.ExtendedRegExTest		as Test.Performance.ExtendedRegExTest+import qualified	Grecce.Test.Performance.ExtendedRegExTestsPositive	as Test.Performance.ExtendedRegExTestsPositive++-- | Defines an enumeration of keys, by which to reference 'Test.Performance.ExtendedRegExTest.TestGenerator's.+data TestName	=+	INTERLEAVED_GREEDY_STAR_VS_MANDATORY+	| LINEAR_FRACTAL_NONGREEDY_STAR+	| OVERLAPPING_ALTERNATIVES+	deriving (+		Bounded,+		Enum,+		Eq,+		Read,+		Show+	)++instance Test.Performance.ExtendedRegExTest.TestGeneratorRepository TestName	where+	query	= (+		`lookup` [+{-+ Explanation:	based on 'Test.Performance.ExtendedRegExTestsPositive.INTERLEAVED_GREEDY_STAR_VS_MANDATORY', but with twice the input data following by a mismatch.+ Performance:	vastly better performance than "Text.Regex.Posix", benefiting from 'ExecutionOptions.checkExistenceOfInelasticTail'.+-}+			(+				INTERLEAVED_GREEDY_STAR_VS_MANDATORY,+				Control.Arrow.first ((++ "!") . concat . replicate 2) . Data.Maybe.fromJust (+					Test.Performance.ExtendedRegExTest.query Test.Performance.ExtendedRegExTestsPositive.INTERLEAVED_GREEDY_STAR_VS_MANDATORY+				)+			),+{-+ Explanation:	based on 'Test.Performance.ExtendedRegExTestsPositive.LINEAR_FRACTAL_NONGREEDY_STAR', but with mismatching input data, which causes the time-complexity explodes to O(n!).+ Performance:	vastly better performance than "Text.Regex.Posix", benefiting from 'ExecutionOptions.checkForUnconsumableData'.+-}+			(+				LINEAR_FRACTAL_NONGREEDY_STAR,+				Control.Arrow.first (++ "!") . Data.Maybe.fromJust (+					Test.Performance.ExtendedRegExTest.query Test.Performance.ExtendedRegExTestsPositive.LINEAR_FRACTAL_NONGREEDY_STAR+				)+			),+{-+ Explanation:	based on 'Test.Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES', but with mismatching input data.+ Performance:	marginally better performance than "Text.Regex.Posix", benefiting from 'ExecutionOptions.checkForUnconsumableData' & 'ExecutionOptions.permitReorderingOfAlternatives'.+-}+			(+				OVERLAPPING_ALTERNATIVES,+				Control.Arrow.first (++ "!") . Data.Maybe.fromJust (+					Test.Performance.ExtendedRegExTest.query Test.Performance.ExtendedRegExTestsPositive.OVERLAPPING_ALTERNATIVES+				)+			)+		]+	 )
+ src/Grecce/Test/Performance/ExtendedRegExTestsPositive.hs view
@@ -0,0 +1,329 @@+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]++	* Defines 'Performance.ExtendedRegExTest.TestGenerator's, for 'Performance.ExtendedRegExTest.Test's, which should pass.++	* Implements 'Performance.ExtendedRegExTest.TestGeneratorRepository'.+-}++module Grecce.Test.Performance.ExtendedRegExTestsPositive(+-- * Types+-- ** Data-types+	TestName(..)+-- * Functions+--	triangularSeries+) where++import			Control.Arrow((&&&))+import qualified	Data.Char+import qualified	Grecce.Test.Performance.ExtendedRegExTest	as Test.Performance.ExtendedRegExTest+import qualified	RegExDot.Anchor					as Anchor+import qualified	RegExDot.BracketExpressionMember		as BracketExpressionMember+import qualified	RegExDot.Meta					as Meta+import qualified	RegExDot.RegEx					as RegEx+import qualified	RegExDot.Repeatable				as Repeatable+import			RegExDot.DSL((-:), (?:), (*:), (<~>))+import			RegExDot.RegEx((.*), (.*?))+import			RegExDot.Repeatable((^#->#), (^#->), (^#))++-- | Defines an enumeration of keys, by which to reference 'Test.Performance.ExtendedRegExTest.TestGenerator's.+data TestName	=+	BIPOLAR_GREEDY_OPTIONAL_VS_MANDATORY+	| INTERLEAVED_GREEDY_STAR_VS_MANDATORY+	| TRIANGULAR_CONSUMPTION+	| BINARY_TREE+	| REPEATABLE_ALTERNATIVES+	| REPEATED_ALTERNATIVES+	| LINEAR_FRACTAL_RANGES+	| LINEAR_FRACTAL_NONGREEDY_STAR+	| BINARY_TREE_FRACTAL+	| FUTILE_REPEATABLE_ALTERNATIVES+	| OVERLAPPING_ALTERNATIVES+	| UNBRIDLED_GREED+	| MULTIPLE_CHOICE+	deriving (+		Bounded,+		Enum,+		Eq,+		Read,+		Show+	)++instance Test.Performance.ExtendedRegExTest.TestGeneratorRepository TestName	where+	query	= (+		`lookup` [+{-+ "^(<testChar>?){<complexity>}(<testChar>){<complexity>}$".+ Explanation:	each of the optional meta-data in the first half of the expression can capture data, but in doing so starves a mandatory meta-datum in the second half of the expression,+		presenting the opportunity for O(2^n) time-complexity backtracking.+ Performance:	vastly better Boolean-result performance than "Text.Regex.Posix". Looks like O(n^2) time-complexity.+-}+			(+				BIPOLAR_GREEDY_OPTIONAL_VS_MANDATORY,+				(`replicate` testChar) &&& let+					exactly :: Test.Performance.ExtendedRegExTest.TestComplexity -> (RegEx.Pattern Char -> RegEx.RepeatablePattern Char) -> RegEx.RepeatablePattern Char+					exactly n f	= (RegEx.captureGroup . map ((Nothing, Nothing) <~>) . return {-to List-monad-} . return {-to List-monad-} $ f testRequirement) ^# n+				in ((Just Anchor.Bow, Just Anchor.Stern) <~>) . (`map` [Repeatable.zeroOrOne, Repeatable.one]) . exactly+			),+{-+ "^(.*z){<complexity>}$".+ Explanation:	each '.*' can consume all the remaining data, starving the interspersed mandatory meta data, presenting the opportunity for O(2^n) time-complexity backtracking.+ Performance:	marginally better Boolean-result & data-capture performance than "Text.Regex.Posix" with 'ExecutionOptions.moderateGreed'. Empirically O(n^3) time-complexity.+-}+			(+				INTERLEAVED_GREEDY_STAR_VS_MANDATORY,+				concat . (`replicate` (testChar : "z")) &&& RegEx.dock . (+					`mkExtendedRegExFromRepeatableSingletonAlternative` ((Nothing, Nothing) <~>) [+						(.*),+						RegEx.simply $ Meta.Literal 'z'+					]+				) . flip (^#)+			),+{-+ "^<testChar>*<testChar>+<testChar>{2,}<testChar>{3,} ... a{<complexity>,}$".+ Explanation:	each term greedily consumes all the data, starving all the remaining terms, until after much back-tracking, it consumes the just the minimum permissible.+		The correct consumption-pattern is triangular, starting at the apex & spreading into a delta.+ Performance:	vastly better Boolean-result & data-capture performance than "Text.Regex.Posix".+-}++			(+				TRIANGULAR_CONSUMPTION,+				(`replicate` testChar) . triangularSeries &&& ((Just Anchor.Bow, Just Anchor.Stern) <~>) . (`take` map (testRequirement ^#->) [0 ..]) . succ+			),+{-+ "(<testChar>|<testChar>{2})*c".+ Explanation:	from <http://www.haskell.org/pipermail/libraries/2009-March/011379.html>+ Performance:	disastrous performance.+-}+			(+				BINARY_TREE,+				(++ "bc") . (`replicate` testChar) . (2 ^) &&& const (+					(Nothing, Nothing) <~> RegEx.captureGroup (+						map (+							((Nothing, Nothing) <~>) . return {-to List-monad-} . (testRequirement ^#) . (2 ^)+						) [0 :: Int .. 1]+					) *: RegEx.Require (Meta.Literal 'c') -: []+				)+			),+{-+ "^(<testChar>?|<testChar>{2}|<testChar>{4}|<testChar>{8}| ... |<testChar>{2^<complexity>})*$".+ Explanation:	all but one of the 'Alternatives' must be used, one on each successive repetition, in order to consume all the 'InputData'.+		A correct implementation will match against the longest possible Alternative on each successive repetition, just as if the repetition were unrolled; see 'REPEATED_ALTERNATIVES'.+ Performance:	vastly worse Boolean-result performance (even with 'ExecutionOptions.permitReorderingOfAlternatives'),+		& worse data-capture performance (even with 'ExecutionOptions.useFirstMatchAmongAlternatives'), than "Text.Regex.Posix".+-}+			(+				REPEATABLE_ALTERNATIVES,+				(`replicate` testChar) . pred {-requires several different Alternatives-} . (2 ^) &&& (+					\i -> ((Just Anchor.Bow, Just Anchor.Stern) <~>) . return {-to List-monad-} . Repeatable.zeroOrMore . RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ [Repeatable.zeroOrOne testRequirement] : map (+						return {-to List-monad-} . (testRequirement ^#) . (2 ^)+					) [1 .. i]+				)+			),+{-+ "^(<testChar>?|<testChar>{2}|<testChar>{4}| ... |<testChar>{2^<complexity>})(<testChar>?|<testChar>{2}|<testChar>{4}| ... |<testChar>{2^<complexity>})(<testChar>?|<testChar>{2}|<testChar>{4}| ... |<testChar>{2^<complexity>})$".+ Explanation:	'REPEATABLE_ALTERNATIVES' with the repetition unrolled, to permit inspection of individual capture-groups,+		revealing the use by "Text.Regex.Posix", of Perl-style "1st-past-the-post" selection between Alternatives.+ Performance:	much faster than 'REPEATABLE_ALTERNATIVES'. Vastly better Boolean-result & data-capture performance than both 'REPEATABLE_ALTERNATIVES' & "Text.Regex.Posix".+-}+			(+				REPEATED_ALTERNATIVES,+				(`replicate` testChar) . pred {-requires several different Alternatives-} . (2 ^) &&& (+					\i -> ((Just Anchor.Bow, Just Anchor.Stern) <~>) . replicate i . Repeatable.one . RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ [Repeatable.zeroOrOne testRequirement] : map (+						return {-to List-monad-} . (testRequirement ^#) . (2 ^)+					) [1 .. i]+				)+			),+{-+ "^((((<testChar>{0,2}){0,2}){0,2}){0,2}){0,2} ... $".+ Explanation:+ Performance:	vastly better Boolean-result performance than "Text.Regex.Posix", which exhausts memory at n==10. Better data-capture performance too.+		Stack-overflow at 'Test.Performance.ExtendedRegExTest.TestComplexity'=14.+-}+			(+				LINEAR_FRACTAL_RANGES,+				let+					base :: Repeatable.Repetitions+					base	= 2	--Arbitrarily.++					bounds :: Repeatable.RepetitionBounds+					bounds	= (0, Just base)+				in (`replicate` testChar) . (base ^) &&& RegEx.dock . (+					(+						mkExtendedRegExFromRepeatableSingletonAlternative (^#-># bounds) `iterate` ((Nothing, Nothing) <~>) [testRequirement ^#-># bounds] {-initial value-}+					) !!+				) . pred+			),+{-+ "^((((((((((((((<testChar>*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*? ... $".+ Explanation:	interesting because all 'RegEx.Alternatives' are expanded before the first comparison against input data, & the number possible repetitions of each expansion is very vague.+ Performance:	vastly better Boolean-result performance than "Text.Regex.Posix", but inferior data-capture performance.+-}+			(+				LINEAR_FRACTAL_NONGREEDY_STAR,+				const (replicate 8 {-arbitrary-} testChar) &&& RegEx.dock . (+					(+						mkExtendedRegExFromRepeatableSingletonAlternative Repeatable.zeroOrMore' `iterate` ((Nothing, Nothing) <~>) [Repeatable.zeroOrMore' testRequirement] {-initial value-}+					) !!+				)+			),+{-+ "^((([^<testChar>]|<testChar>)|(<testChar>|[^<testChar>]))|((<testChar>|[^<testChar>])|([^<testChar>]|<testChar>)))$".+ Explanation:	exhibits symmetry in the left & right branches of the binary tree of RegEx.Alternatives, & so the exponentially expanding set of leaves are equivalent & all match the data.+ Performance:	vastly better Boolean-result & comparable data.capture performance to "Text.Regex.Posix", which exhausts memory at complexity 5 to 6, & to egrep which lasts until complexity==6.+-}+			(+				BINARY_TREE_FRACTAL,+				let+					base :: Repeatable.Repetitions+					base	= 2	--Arbitrarily.+				in (`replicate` testChar) . (base ^) &&& RegEx.dock . head . (+					(+						iterate (+							\extendedRegExList -> (+								((Nothing, Nothing) <~>) . return {-to List-monad-} . (^# base) . RegEx.captureGroup+							) `map` [extendedRegExList, reverse extendedRegExList]+						) $ map (+							((Nothing, Nothing) <~>) . return {-to List-monad-} . ($ RegEx.Require $ Meta.Literal testChar)+						) [Repeatable.one, Repeatable.zeroOrOne]+					) !!+				)+			),+{-+ "^(<testChar>1|<testChar>{2}2|<testChar>{3}3| ... |<testChar>{<complexity>}<complexity>)*<testChar>*$".+ Explanation:	none of the Alternatives can match, & consequently the group must match zero times, presenting the opportunity for many wasted trial repetitions.+ Performance:	comparable Boolean-result performance to "Text.Regex.Posix", & marginally superior data-capture performance.+-}+			(+				FUTILE_REPEATABLE_ALTERNATIVES,+				\alternatives	-> (+					replicate 1024 {-arbitrarily-} testChar,+					((Just Anchor.Bow, Just Anchor.Stern) <~>) $ map Repeatable.zeroOrMore [+						RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ (+							\i -> ($ i) `map` [+								(testRequirement ^#),+								RegEx.simply . Meta.Literal . Data.Char.chr . (Data.Char.ord '0' +) . (`mod` 10)+							]+						) `map` [1 .. alternatives],+						testRequirement+					]+				)+			),+{-+ "^a?((ab?)*|(bc?)*|(cd?)*| ...)*$".+ Explanation:	the zeroeth term matches greedily, consuming the datum mandated by the 1st Alternative, so the 2nd Alternative greedily consumes two data, including the datum mandated by the 3rd, ...+		If there're an even number of Alternatives, then n/2 repetitions (one for each), will consume all the input data, but otherwise the final input datum isn't consumed.+		The consumption back-tracks rapidly until the zeroeth term yields-up the initial datum, after which the odd Alternatives match consuming all the input data, in (n/2 + 1) repetitions.+		This suggests a very tractable O(n) time-complexity, but Posix requires that we select the combination of Alternatives which consume most data,+		& since there are two terms in the regex that can consume each input datum, it looks like there should be 2^n candidate solutions; in fact there's just one.+		So, all O(Alternatives ^ repetitions) permutations may be searched in vain for a superior solution.+ Performance:	vastly worse Boolean-result performance than "Text.Regex.Posix", but the latter then stalls indefinitely (CPU-bound) at complexity=[13 (not verbose), 4 (verbose)].+-}+			(+				OVERLAPPING_ALTERNATIVES,+				let+					bracket :: a -> [a] -> [a]+					bracket terminal	= (terminal :) . (++ [terminal])++					zeroOrMoreAlternatives :: [RegEx.Concatenation Char] -> RegEx.Concatenation Char+					zeroOrMoreAlternatives	= return {-to List-monad-} . Repeatable.zeroOrMore . RegEx.captureGroup . map ((Nothing, Nothing) <~>)+				in (+					id &&& (+						((Just Anchor.Bow, Just Anchor.Stern) <~>) . (RegEx.Require (Meta.Literal testChar) ?:) . zeroOrMoreAlternatives . map (+							\(a, b)	-> zeroOrMoreAlternatives $ return {-to List-monad-} [a, b]+						) . init . tail . uncurry zip . (+							map Repeatable.one . init &&& map Repeatable.zeroOrOne . tail+						) . bracket undefined . map (+							RegEx.Require . Meta.Literal+						)+					)+				) . (`take` (filter Data.Char.isAlphaNum $ filter Data.Char.isAscii [minBound .. maxBound])) . succ+			),+{-+ "^(a|b|c)*(a.*?c){3}$".+ Explanation:	zero repetitions of the set of Alternatives on the LHS is the only solution, but because the greedy star, within which they're grouped, permits many more,+		& because the RHS's requirement for all the input-data, isn't explicit, there's a temptation to over-consume.+ Performance:	empirically O(2^n) time-complexity, but linearised by 'ExecutionOptions.moderateGreed'.+		Better Boolean-result & data-capture performance than "Text.Regex.Posix".+-}+			(+				UNBRIDLED_GREED,+				\complexity	-> let+					complexity' :: Test.Performance.ExtendedRegExTest.TestComplexity+					complexity'	= 1 + complexity++					testSet :: String+					testSet	= take complexity' . filter Data.Char.isAlphaNum $ filter Data.Char.isAscii [minBound .. maxBound]+				in (+					concat $ replicate complexity' testSet,+					((Just Anchor.Bow, Just Anchor.Stern) <~>) $ (+						RegEx.captureGroup . map ((Nothing, Nothing) <~>) $ map (+							return {-to List-monad-} . RegEx.simply . Meta.Literal+						) testSet+					) *: [+						(+							RegEx.captureGroup . map ((Nothing, Nothing) <~>) . return {-to List-monad-} $ RegEx.Require (Meta.Literal $ head testSet) -: (.*?) : RegEx.Require (Meta.Literal $ last testSet) -: []+						) ^# complexity'+					]+				)+			),+{-+ "^(a*[^a]|[^b]|[^c]| ... |[^z])*$"+ Explanation:	The first alternative greedily consumes all the input data until finding a mismatch on the last, whilst all the remaining alternatives successfully consume a single input datum.+		The same occurs on each successive repetition of the alternatives, of which there are as many as input data,+		leading to a lot of wasted time with O(<alternatives> ^ <input data>) time-complexity.+ Performance:	poor Boolean-result & worse data-capture performance (benefiting from 'ExecutionOptions.useFirstMatchAmongAlternatives'), compared to "Text.Regex.Posix".+-}+			(+				MULTIPLE_CHOICE,+				const (replicate 8 {-arbitrary-} testChar) &&& (+					((Just Anchor.Bow, Just Anchor.Stern) <~>) . return {-to List-monad-} . Repeatable.zeroOrMore . RegEx.captureGroup . map ((Nothing, Nothing) <~>) . (+						[+							Repeatable.zeroOrMore testRequirement,+							RegEx.simply . Meta.NoneOf $ map BracketExpressionMember.Literal [testChar]+						] :+					) . map (+						return {-to List-monad-} . RegEx.simply . Meta.NoneOf . return {-to List-monad-} . BracketExpressionMember.Literal+					) . (+						`take` tail [testChar ..]+					)+				)+			)+		]+	 ) where+		testChar :: Char+		testChar	= 'a'++		testRequirement :: RegEx.Pattern Char+		testRequirement	= RegEx.Require $ Meta.Literal testChar++		mkExtendedRegExFromRepeatableSingletonAlternative :: (RegEx.Pattern Char -> RegEx.RepeatablePattern Char) -> RegEx.ExtendedRegEx Char -> RegEx.ExtendedRegEx Char+		mkExtendedRegExFromRepeatableSingletonAlternative makeRepetitions	= ((Nothing, Nothing) <~>) . return {-to List-monad-} . makeRepetitions . RegEx.captureGroup . return {-to List-monad-}++{- |+	* The sum of the sequence descending from the specified integer; @n + (n - 1) + (n - 2) + ... + 2 + 1 + 0@.++	* <http://en.wikipedia.org/wiki/Triangular_number>.++	* <http://mathworld.wolfram.com/TriangularNumber.html>.+-}+triangularSeries :: Integral i => i -> i+triangularSeries i	= i * (i + 1) `div` 2
+ src/Grecce/Test/QC/ExtendedRegExChar.hs view
@@ -0,0 +1,205 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' & defines tests based on it.+-}++module Grecce.Test.QC.ExtendedRegExChar(+-- * Types+-- ** Data-types+--	AlternativesChar(..),+--	PatternChar(..),+--	RepeatablePatternChar(..),+-- ** Type-synonyms+--	Testable,+-- * Functions+--	deconstructAlternativesChar,+--	deconstructPatternChar,+--	deconstructRepeatablePatternChar,+	quickChecks+) where++import			Control.Applicative((<$>))+import			Grecce.Test.QC.MetaChar()+import qualified	RegExChar.ExtendedRegExChar		as ExtendedRegExChar	--CAVEAT: beware of the similar name.+import qualified	RegExChar.MetaChar			as MetaChar+import qualified	RegExDot.Anchor				as Anchor+import qualified	RegExDot.BracketExpressionMember	as BracketExpressionMember+import qualified	RegExDot.Consumer			as Consumer+import qualified	RegExDot.ConsumptionBounds		as ConsumptionBounds+import qualified	RegExDot.ConsumptionProfile		as ConsumptionProfile+import qualified	RegExDot.Meta				as Meta+import qualified	RegExDot.RegEx				as RegEx+import qualified	RegExDot.RegExOpts			as RegExOpts+import qualified	RegExDot.Repeatable			as Repeatable+import qualified	RegExDot.Result				as Result+import qualified	Test.QuickCheck+import qualified	ToolShed.SelfValidate			as SelfValidate+import			RegExDot.DSL((-:), (?:), (+:), (<~>))+import			RegExDot.RegEx((+~))+import			Test.QuickCheck((==>))++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype AlternativesChar	= MkAlternativesChar (RegEx.Alternatives Char) deriving (Eq, Read, Show)++-- | Accessor.+deconstructAlternativesChar :: AlternativesChar -> RegEx.Alternatives Char+deconstructAlternativesChar (MkAlternativesChar a)	= a++instance SelfValidate.SelfValidator AlternativesChar where+	isValid	= SelfValidate.isValid . deconstructAlternativesChar++instance Consumer.Consumer AlternativesChar where+	consumptionProfile	= Consumer.consumptionProfile . deconstructAlternativesChar+	starHeight		= Consumer.starHeight . deconstructAlternativesChar++instance Test.QuickCheck.Arbitrary AlternativesChar	where+	arbitrary	= MkAlternativesChar . RegEx.MkAlternatives . map ExtendedRegExChar.extendedRegEx <$> (+		Test.QuickCheck.elements [1, 2]	>>= Test.QuickCheck.vector {-[ExtendedRegExChar]-}+	 ) --TODO: permit zero alternatives.+#if !(MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype PatternChar	= MkPatternChar (RegEx.Pattern Char) deriving (Eq, Read, Show)++-- | Accessor.+deconstructPatternChar :: PatternChar -> RegEx.Pattern Char+deconstructPatternChar (MkPatternChar pattern)	= pattern++instance SelfValidate.SelfValidator PatternChar	where+	isValid	= SelfValidate.isValid . deconstructPatternChar++instance Consumer.Consumer PatternChar	where+	consumptionProfile	= Consumer.consumptionProfile . deconstructPatternChar+	starHeight		= Consumer.starHeight . deconstructPatternChar++instance Test.QuickCheck.Arbitrary PatternChar	where+	arbitrary	= MkPatternChar <$> Test.QuickCheck.frequency [+		(4,	RegEx.Require . MetaChar.deconstruct <$> Test.QuickCheck.arbitrary {-MetaChar-}),+		(1,	RegEx.CaptureGroup . deconstructAlternativesChar <$> Test.QuickCheck.arbitrary {-AlternativesChar-})+	 ] --CAVEAT: may recurse forever if 'RegEx.CaptureGroup / RegEx.Require' is too high.+#if ! (MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype RepeatablePatternChar	= MkRepeatablePatternChar (Repeatable.Repeatable PatternChar)	deriving (Eq, Read, Show)++-- | Accessor.+deconstructRepeatablePatternChar :: RepeatablePatternChar -> Repeatable.Repeatable PatternChar+deconstructRepeatablePatternChar (MkRepeatablePatternChar repeatable)	= repeatable++instance SelfValidate.SelfValidator RepeatablePatternChar	where+	isValid	= SelfValidate.isValid . deconstructRepeatablePatternChar++instance Consumer.Consumer RepeatablePatternChar	where+	consumptionProfile	= Consumer.consumptionProfile . deconstructRepeatablePatternChar+	starHeight		= Consumer.starHeight . deconstructRepeatablePatternChar++instance Test.QuickCheck.Arbitrary RepeatablePatternChar	where+	arbitrary	= do+		patternChar	<- Test.QuickCheck.arbitrary+		fewest		<- Test.QuickCheck.elements [0 .. 9]	--Could be more, but this is an adequate test.+		most		<- Test.QuickCheck.oneof [return {-to Gen-monad-} Nothing, Just <$> Test.QuickCheck.elements [max fewest 1 .. 9]]+		isGreedy	<- Test.QuickCheck.arbitrary {-Bool-}++		let+			repetitionBounds :: Repeatable.RepetitionBounds+			repetitionBounds	= (fewest, most)++		return {-to Gen-monad-} $ MkRepeatablePatternChar Repeatable.MkRepeatable {+			Repeatable.base			= patternChar,+			Repeatable.repetitionBounds	= repetitionBounds,+			Repeatable.isGreedy		= Repeatable.hasPreciseBounds repetitionBounds || isGreedy	--Only specify non-greedy where space exists.+		}+#if ! (MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif++instance Test.QuickCheck.Arbitrary ExtendedRegExChar.ExtendedRegExChar	where+	arbitrary	= do+		hasBowAnchor	<- Test.QuickCheck.arbitrary {-Bool-}+		concatenation	<- map ((deconstructPatternChar <$> {-replace base-}) . deconstructRepeatablePatternChar {-Repeatable.Repeatable PatternChar-}) <$> Test.QuickCheck.vector 2 {-[RepeatablePatternChar]-}+		hasSternAnchor	<- Test.QuickCheck.arbitrary {-Bool-}++		return {-to Gen-monad-} $ ExtendedRegExChar.MkExtendedRegExChar False RegEx.MkExtendedRegEx {+			RegEx.bowAnchor		= if hasBowAnchor then Just Anchor.Bow else Nothing,+			RegEx.concatenation	= concatenation,+			RegEx.sternAnchor	= if hasSternAnchor then Just Anchor.Stern else Nothing+		}++#if ! (MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif++type Testable	= ExtendedRegExChar.ExtendedRegExChar -> Test.QuickCheck.Property++-- | Defines invariant properties, which must hold for any 'ExtendedRegExChar.ExtendedRegExChar'.+quickChecks :: (Testable -> IO ()) -> IO ()+quickChecks checker	= quickChecks1 >> quickChecks2	where+	quickChecks1	= checker `mapM_` [prop_consumptionProfile, prop_consumptionProfile2, prop_io, prop_io', prop_isValid, prop_starHeight]	where+		prop_consumptionProfile, prop_consumptionProfile2, prop_io, prop_io', prop_isValid, prop_starHeight :: Testable+		prop_consumptionProfile r	= Test.QuickCheck.label "prop_consumptionProfile" $ (+			case maybeMaxData of+				Nothing	-> True+				Just m	-> m >= minData+		 ) && (+			not b == all (not . Consumer.getHasSpecificRequirement) (RegEx.concatenation $ ExtendedRegExChar.extendedRegEx r)+		 )+			where+				ConsumptionProfile.MkConsumptionProfile {+					ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),+					ConsumptionProfile.hasSpecificRequirement	= b+				} = Consumer.consumptionProfile r++		prop_consumptionProfile2 r	= RegEx.isDefined (ExtendedRegExChar.extendedRegEx r)	==> Test.QuickCheck.label "prop_consumptionProfile2" $ or [hasSpecificRequirement, canConsumeAnything]	--There's either; a requirement for at least one specific, or we can consume at least one arbitrary; input datum.+			where+				ConsumptionProfile.MkConsumptionProfile {+					ConsumptionProfile.hasSpecificRequirement	= hasSpecificRequirement,+					ConsumptionProfile.canConsumeAnything		= canConsumeAnything+				} = Consumer.consumptionProfile r++		prop_io r		= Test.QuickCheck.label "prop_io" $ read (show r) == r+		prop_io' r		= Test.QuickCheck.label "prop_io'" $ read (show r') == r'	where r' = ExtendedRegExChar.extendedRegEx r	--Check "RegEx.ExtendedRegEx Char" too.+		prop_isValid r		= Test.QuickCheck.label "prop_isValid" $ SelfValidate.isValid r+		prop_starHeight r	= Test.QuickCheck.label "prop_starHeight" $ (Consumer.starHeight r == 0) == ConsumptionBounds.isPrecise (Consumer.getConsumptionBounds r)++	quickChecks2	= Test.QuickCheck.quickCheck {-'checker' is technically the wrong type-} `mapM_` [prop_double]	where+		prop_double :: Double -> Test.QuickCheck.Property+		prop_double d	= Test.QuickCheck.label "prop_double" $ RegEx.extractDataFromMatchList `fmap` Result.getMatchList result == Just s	where+			s :: String+			s	= show $ d * 1e6	--Implementation of show, uses exponential notation, when the number is large.++			result :: RegEx.Result Char+			result = s +~ RegExOpts.mkRegEx (+				(Just Anchor.Bow, Just Anchor.Stern) <~> sign ?: digits +: map (+					Repeatable.zeroOrOne . RegEx.captureGroup . map ((Nothing, Nothing) <~>) . return {-to List-monad-}+				) [+					RegEx.Require (Meta.Literal '.') -: digits +: [],+					RegEx.Require (Meta.AnyOf $ map BracketExpressionMember.Literal "eE") -: sign ?: digits +: []+				]+			 ) where+				sign, digits :: RegEx.Pattern Char+				sign	= RegEx.Require . Meta.AnyOf $ map BracketExpressionMember.Literal "+-"+				digits	= RegEx.Require . Meta.AnyOf $ map BracketExpressionMember.Literal ['0' .. '9']+
+ src/Grecce/Test/QC/MetaChar.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' & defines tests based on it.++ [@TODO@]	Test /Perl-style shortcuts/ & /Posix Character-classes/.+-}++module Grecce.Test.QC.MetaChar(+-- * Types+-- ** Type-synonyms+--	Testable,+-- * Constants+--	testCharacters,+-- * Functions+	quickChecks+) where++import			Control.Applicative((<$>))+import qualified	Data.List+import qualified	RegExChar.MetaChar			as MetaChar	--CAVEAT: beware of the similar name.+import qualified	RegExDot.BracketExpression		as BracketExpression+import qualified	RegExDot.BracketExpressionMember	as BracketExpressionMember+import qualified	RegExDot.Meta				as Meta+import qualified	Test.QuickCheck++-- CAVEAT: module "Test.QuickCheck.Arbitrary" defines an instance of this from package "Quickcheck-2.1.0.1".+#if !(MIN_VERSION_QuickCheck(2,1,0))+instance Test.QuickCheck.Arbitrary Char	where+	arbitrary	= Test.QuickCheck.elements testCharacters+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif++testCharacters :: String+testCharacters	= filter (`notElem` [Meta.shortcutToken, BracketExpression.negationToken]) [' ' .. '~']	--TODO: permit all characters.++instance Test.QuickCheck.Arbitrary MetaChar.MetaChar	where+	arbitrary	= Test.QuickCheck.oneof $ map (MetaChar.MkMetaChar <$>) [+		return {-to Gen-monad-} Meta.Any,+		Meta.Literal <$> Test.QuickCheck.elements testCharacters,+		Meta.AnyOf . map BracketExpressionMember.Literal . Data.List.nub <$> arbitraryCharList 1 16,	--Test.QuickCheck.vector 16 {-Char-},+		Meta.NoneOf . map BracketExpressionMember.Literal . Data.List.nub <$> arbitraryCharList 1 4+	 ] where+		arbitraryCharList :: Int -> Int -> Test.QuickCheck.Gen String+		arbitraryCharList i j	= do+			l	<- Test.QuickCheck.arbitrary {-Int-}++			take (min j $ i `max` l) . Data.List.nub . Data.List.filter (`elem` testCharacters) <$> Test.QuickCheck.vector maxBound {-Char-}+#if ! (MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif++type Testable	= MetaChar.MetaChar -> Test.QuickCheck.Property++-- | Defines invariant properties, which must hold for any 'MetaChar.MetaChar'.+quickChecks :: (Testable -> IO ()) -> IO ()+quickChecks checker	= checker `mapM_` [prop_io]	where+	prop_io :: Testable+	prop_io m	= Test.QuickCheck.label "prop_io" $ read (show m) == m+
+ src/Grecce/Test/QC/QuickChecks.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE CPP #-}+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]	Calls the /quickChecks/-functions for modules supporting this feature.+-}++module Grecce.Test.QC.QuickChecks(+-- * Functions+	run+) where++import qualified	Grecce.Test.QC.ExtendedRegExChar	as Test.QC.ExtendedRegExChar+import qualified	Grecce.Test.QC.MetaChar			as Test.QC.MetaChar+import qualified	Grecce.Test.QC.RepeatableMetaChar	as Test.QC.RepeatableMetaChar+import qualified	Test.QuickCheck++{- |	Run the /quickChecks/-functions for modules supporting this feature.+	The single Boolean flag enables verbose output.+-}+run :: Bool -> IO ()+run isVerbose	=+	putStrLn "MetaChar"			>> Test.QC.MetaChar.quickChecks checker+	>> putStrLn "RepeatableMetaChar"	>> Test.QC.RepeatableMetaChar.quickChecks checker+	>> putStrLn "ExtendedRegExChar"		>> Test.QC.ExtendedRegExChar.quickChecks checker+	where+		checker :: Test.QuickCheck.Testable t => t -> IO ()+		checker+			| isVerbose	=+#if MIN_VERSION_QuickCheck(2,4,0)+				Test.QuickCheck.verboseCheck+#else+				error "Grecce.Test.QC.QuickChecks:\t'Test.QuickCheck.verboseCheck' is only available as of 'QuickCheck-2.4'."+#endif+			| otherwise	= Test.QuickCheck.quickCheck+
+ src/Grecce/Test/QC/RepeatableMetaChar.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE CPP #-}+{-+	Copyright (C) 2010 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+	the Free Software Foundation, either version 3 of the License, or+	(at your option) any later version.++	This program is distributed in the hope that it will be useful,+	but WITHOUT ANY WARRANTY; without even the implied warranty of+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+	GNU General Public License for more details.++	You should have received a copy of the GNU General Public License+	along with this program.  If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@]	Dr. Alistair Ward++ [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' & defines tests based on it.+-}++module Grecce.Test.QC.RepeatableMetaChar(+-- * Types+-- ** Data-types+--	RepeatableMetaChar,+-- ** Type-synonyms+--	Testable,+-- * Functions+--	deconstruct,+	quickChecks+) where++import			Control.Applicative((<$>))+import			Grecce.Test.QC.MetaChar()+import qualified	RegExChar.MetaChar		as MetaChar+import qualified	RegExDot.Consumer		as Consumer+import qualified	RegExDot.ConsumptionBounds	as ConsumptionBounds+import qualified	RegExDot.ConsumptionProfile	as ConsumptionProfile+import qualified	RegExDot.Repeatable		as Repeatable+import qualified	Test.QuickCheck+import qualified	ToolShed.SelfValidate		as SelfValidate++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype RepeatableMetaChar	= MkRepeatableMetaChar (Repeatable.Repeatable MetaChar.MetaChar)	deriving (Eq, Read, Show)++-- | Accessor.+deconstruct :: RepeatableMetaChar -> Repeatable.Repeatable MetaChar.MetaChar+deconstruct (MkRepeatableMetaChar repeatableMetaChar)	= repeatableMetaChar++instance SelfValidate.SelfValidator RepeatableMetaChar	where+	isValid	= SelfValidate.isValid . deconstruct++instance Consumer.Consumer RepeatableMetaChar	where+	consumptionProfile	= Consumer.consumptionProfile . deconstruct+	starHeight		= Consumer.starHeight . deconstruct++instance Test.QuickCheck.Arbitrary RepeatableMetaChar	where+	arbitrary	= do+		metaChar	<- Test.QuickCheck.arbitrary+		fewest		<- Test.QuickCheck.elements [0 .. 9]	--Could be more, but this is an adequate test.+		most		<- Test.QuickCheck.oneof [return Nothing, Just <$> Test.QuickCheck.elements [max fewest 1 .. 9]]+		isGreedy	<- Test.QuickCheck.arbitrary++		let+			repetitionBounds :: Repeatable.RepetitionBounds+			repetitionBounds	= (fewest, most)++		return {-to Gen-monad-} . MkRepeatableMetaChar $ Repeatable.MkRepeatable {+			Repeatable.base			= metaChar,+			Repeatable.repetitionBounds	= repetitionBounds,+			Repeatable.isGreedy		= Repeatable.hasPreciseBounds repetitionBounds || isGreedy	--Only specify 'non-greedy' where space exists.+		}+#if !(MIN_VERSION_QuickCheck(2,1,0))+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.+#endif++type Testable	= RepeatableMetaChar -> Test.QuickCheck.Property++-- | Defines invariant properties, which must hold for any 'RepeatableMetaChar'.+quickChecks :: (Testable -> IO ()) -> IO ()+quickChecks checker	= checker `mapM_` [prop_consumptionProfile, prop_io, prop_isValid, prop_starHeight]	where+	prop_consumptionProfile, prop_io, prop_isValid, prop_starHeight :: Testable+	prop_consumptionProfile r	= Test.QuickCheck.label "prop_consumptionProfile" $ (+		case maybeMaxData of+			Nothing	-> True+			Just m	-> m >= minData+	 ) && (+		b == Consumer.getHasSpecificRequirement (Repeatable.base $ deconstruct r)+	 ) where ConsumptionProfile.MkConsumptionProfile {+		ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),+		ConsumptionProfile.hasSpecificRequirement	= b+	 } = Consumer.consumptionProfile r+	prop_io (MkRepeatableMetaChar r)		= Test.QuickCheck.label "prop_io" $ read (show r) == r+	prop_isValid r					= Test.QuickCheck.label "prop_isValid" $ SelfValidate.isValid r+	prop_starHeight (MkRepeatableMetaChar r)	= Test.QuickCheck.label "prop_starHeight" $ Consumer.starHeight r == if ConsumptionBounds.isPrecise (Consumer.getConsumptionBounds r) then 0 else 1+
src/Main.hs view
@@ -41,20 +41,20 @@ import qualified	Distribution.Package import qualified	Distribution.Text import qualified	Distribution.Version-import qualified	Grecce.Assert.RegExOptsChar			as Assert.RegExOptsChar-import qualified	Grecce.CommandOptions				as CommandOptions-import qualified	Grecce.Grep					as Grep-import qualified	Grecce.Performance.ExtendedRegEx		as Performance.ExtendedRegEx-import qualified	Grecce.Performance.ExtendedRegExTestsNegative	as Performance.ExtendedRegExTestsNegative-import qualified	Grecce.Performance.ExtendedRegExTestsPositive	as Performance.ExtendedRegExTestsPositive-import qualified	Grecce.QC.QuickChecks				as QC.QuickChecks-import qualified	RegExDot.CompilationOptions			as CompilationOptions-import qualified	RegExDot.ExecutionOptions			as ExecutionOptions+import qualified	Grecce.CommandOptions					as CommandOptions+import qualified	Grecce.Grep						as Grep+import qualified	Grecce.Test.Assert.RegExOptsChar			as Test.Assert.RegExOptsChar+import qualified	Grecce.Test.Performance.ExtendedRegEx			as Test.Performance.ExtendedRegEx+import qualified	Grecce.Test.Performance.ExtendedRegExTestsNegative	as Test.Performance.ExtendedRegExTestsNegative+import qualified	Grecce.Test.Performance.ExtendedRegExTestsPositive	as Test.Performance.ExtendedRegExTestsPositive+import qualified	Grecce.Test.QC.QuickChecks				as Test.QC.QuickChecks+import qualified	RegExDot.CompilationOptions				as CompilationOptions+import qualified	RegExDot.ExecutionOptions				as ExecutionOptions import qualified	System-import qualified	System.Console.GetOpt				as G+import qualified	System.Console.GetOpt					as G import qualified	System.IO import qualified	System.IO.Error-import qualified	ToolShed.Defaultable				as Defaultable+import qualified	ToolShed.Defaultable					as Defaultable  -- | Used to thread user-defined command-line options, though the list of functions which implement them. type CommandLineAction	= CommandOptions.CommandOptions -> IO CommandOptions.CommandOptions	--Supplied as the type-argument to 'G.OptDescr'.@@ -92,9 +92,9 @@ 				extendedRegExCharPerformance `G.ReqArg` "(Int,Either [TestName])" 			) ( 				"Test:\tcompare performance with other RegEx-engines, using the specified pair (<Maximum complexity>, Left " ++ show [-					minBound :: Performance.ExtendedRegExTestsNegative.TestName .. maxBound+					minBound :: Test.Performance.ExtendedRegExTestsNegative.TestName .. maxBound 				] ++ " or Right " ++ show [-					minBound :: Performance.ExtendedRegExTestsPositive.TestName .. maxBound+					minBound :: Test.Performance.ExtendedRegExTestsPositive.TestName .. maxBound 				] ++ "). NB: specify this option last." 			), 			G.Option ""	["runQuickChecks"]				(G.NoArg runQuickChecks)							"Test:\trun Quick-checks using arbitrary data & then exit. Specify 'verbose' before this option, for detailed output.",@@ -122,24 +122,24 @@ 				packageIdentifier :: Distribution.Package.PackageIdentifier 				packageIdentifier	= Distribution.Package.PackageIdentifier { 					Distribution.Package.pkgName	= Distribution.Package.PackageName "grecce",-					Distribution.Package.pkgVersion	= Distribution.Version.Version [0, 9, 0, 7] []+					Distribution.Package.pkgVersion	= Distribution.Version.Version [0, 9, 0, 8] [] 				}  			printUsage	= System.IO.hPutStrLn System.IO.stderr usage	>> System.exitWith System.ExitSuccess  			printCurrentSettings, runQuickChecks :: CommandLineAction 			printCurrentSettings commandOptions	= print commandOptions	>> System.exitWith System.ExitSuccess-			runQuickChecks commandOptions		= QC.QuickChecks.run (CommandOptions.verbose commandOptions)	>> System.exitWith System.ExitSuccess+			runQuickChecks commandOptions		= Test.QC.QuickChecks.run (CommandOptions.verbose commandOptions)	>> System.exitWith System.ExitSuccess  			extendedRegExCharPerformance, readExtendedRegExCharFromFile, assertFromFile, assertPosixFromFile, setExtendedRegExChar :: String -> CommandLineAction 			extendedRegExCharPerformance s commandOptions	= (-				uncurry $ Performance.ExtendedRegEx.run (CommandOptions.executionOptions commandOptions)+				uncurry $ Test.Performance.ExtendedRegEx.run (CommandOptions.executionOptions commandOptions) 			 ) (read s)	>> System.exitWith System.ExitSuccess  			readExtendedRegExCharFromFile s commandOptions	= (head . dropWhile null . lines <$> readFile s) >>= (`setExtendedRegExChar` commandOptions)  			assertFromFile fileName commandOptions	= do-				failedTests	<- Assert.RegExOptsChar.findFailures (CommandOptions.compilationOptions commandOptions) (CommandOptions.executionOptions commandOptions) <$> Assert.RegExOptsChar.readTests fileName+				failedTests	<- Test.Assert.RegExOptsChar.findFailures (CommandOptions.compilationOptions commandOptions) (CommandOptions.executionOptions commandOptions) <$> Test.Assert.RegExOptsChar.readTests fileName  				if null failedTests 					then System.exitWith System.ExitSuccess@@ -149,7 +149,7 @@ 						System.exitWith $ System.ExitFailure 2  			assertPosixFromFile fileName _	= do-				failedTests	<- Assert.RegExOptsChar.findFailuresPosix <$> Assert.RegExOptsChar.readTests fileName+				failedTests	<- Test.Assert.RegExOptsChar.findFailuresPosix <$> Test.Assert.RegExOptsChar.readTests fileName  				if null failedTests 					then System.exitWith System.ExitSuccess
src/RegExChar/ExtendedRegExChar.hs view
@@ -34,7 +34,6 @@ ) where  import			Control.Applicative((<$>))-import			Control.Arrow((***)) import			RegExDot.DSL((<~>), (-:)) import			Text.ParserCombinators.Parsec((<?>), (<|>)) import qualified	Control.Monad@@ -46,6 +45,7 @@ import qualified	RegExDot.RegExOpts		as RegExOpts import qualified	RegExDot.Repeatable		as Repeatable import qualified	Text.ParserCombinators.Parsec	as Parsec+import qualified	ToolShed.Pair			as Pair import qualified	ToolShed.SelfValidate		as SelfValidate  infix 4 +~, =~, /~	--Same as (==) & (/=).@@ -101,7 +101,7 @@ 						( 							do 								repeatableCaptureGroup	<- Repeatable.repeatableParser . RegEx.CaptureGroup =<< uncurry Parsec.between (-									Parsec.char *** Parsec.char $ RegEx.captureGroupDelimiters+									Pair.mirror Parsec.char RegEx.captureGroupDelimiters 								 ) alternativesParser {-recurse-} <?> "RegEx.captureGroupDelimiters " ++ show RegEx.captureGroupDelimiters  								extendedRegEx'	<- extendedRegExParser	--Recurse.
src/RegExChar/MetaChar.hs view
@@ -74,6 +74,7 @@ import qualified	RegExDot.Repeatable			as Repeatable import qualified	RegExDot.ShowablePredicate		as ShowablePredicate import qualified	Text.ParserCombinators.Parsec		as Parsec+import qualified	ToolShed.Pair				as Pair import qualified	ToolShed.SelfValidate			as SelfValidate  -- | Holds a mapping from an escape-sequence & the predicate via which it is implemented.@@ -120,7 +121,7 @@ metaCharParser	= MkMetaChar <$> Parsec.choice [ 	(Parsec.char Meta.anyToken <?> "Meta.anyToken " ++ show Meta.anyToken) >> return {-to GenParser-monad-} Meta.Any, 	(Parsec.char Meta.shortcutToken <?> "Meta.shortcutToken " ++ show Meta.shortcutToken) >> Meta.expand <$> Parsec.anyChar,-	uncurry Parsec.between (Parsec.char *** Parsec.char $ BracketExpression.delimiterTokens) (+	uncurry Parsec.between (Pair.mirror Parsec.char BracketExpression.delimiterTokens) ( 		do 			let 				implementPosixCharacterClass :: String -> Maybe (ShowablePredicate.ShowablePredicate Char)@@ -168,7 +169,7 @@ 								_			-> BracketExpressionMember.Literal c	--Escaped literal. 					) <?> "Perl-style shortcut", 					Parsec.try (-						uncurry Parsec.between (Parsec.string *** Parsec.string $ posixCharacterClassDelimiters) (+						uncurry Parsec.between (Pair.mirror Parsec.string posixCharacterClassDelimiters) ( 							do 								identifier	<- Parsec.many1 $ Parsec.noneOf [head $ snd posixCharacterClassDelimiters]