packages feed

regexchar 0.9.0.12 → 0.9.0.13

raw patch · 39 files changed

+2595/−2587 lines, 39 filesdep +regexchardep ~Cabaldep ~toolshedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: regexchar

Dependency ranges changed: Cabal, toolshed

API changes (from Hackage documentation)

- RegExChar.ExtendedRegExChar: extendedRegEx :: ExtendedRegExChar -> ExtendedRegEx Char
- RegExChar.ExtendedRegExChar: hasNonCapturingTopLevelAlternatives :: ExtendedRegExChar -> Bool
- RegExChar.ExtendedRegExChar: instance Consumer ExtendedRegExChar
- RegExChar.ExtendedRegExChar: instance Eq ExtendedRegExChar
- RegExChar.ExtendedRegExChar: instance Read ExtendedRegExChar
- RegExChar.ExtendedRegExChar: instance SelfValidator ExtendedRegExChar
- RegExChar.ExtendedRegExChar: instance ShortcutExpander Char
- RegExChar.ExtendedRegExChar: instance Show ExtendedRegExChar
- RegExChar.MetaChar: instance Consumer MetaChar
- RegExChar.MetaChar: instance Eq MetaChar
- RegExChar.MetaChar: instance Read MetaChar
- RegExChar.MetaChar: instance SelfValidator MetaChar
- RegExChar.MetaChar: instance ShortcutExpander Char
- RegExChar.MetaChar: instance Show MetaChar
- RegExChar.RegExOptsChar: instance RegexLike RegExOptsChar InputData
- RegExChar.RegExOptsChar: instance RegexMaker RegExOptsChar CompilationOptions ExecutionOptions String
- RegExChar.RegExOptsChar: instance RegexOptions RegExOptsChar CompilationOptions ExecutionOptions
+ RegExChar.ExtendedRegExChar: [extendedRegEx] :: ExtendedRegExChar -> ExtendedRegEx Char
+ RegExChar.ExtendedRegExChar: [hasNonCapturingTopLevelAlternatives] :: ExtendedRegExChar -> Bool
+ RegExChar.ExtendedRegExChar: instance GHC.Classes.Eq RegExChar.ExtendedRegExChar.ExtendedRegExChar
+ RegExChar.ExtendedRegExChar: instance GHC.Read.Read RegExChar.ExtendedRegExChar.ExtendedRegExChar
+ RegExChar.ExtendedRegExChar: instance GHC.Show.Show RegExChar.ExtendedRegExChar.ExtendedRegExChar
+ RegExChar.ExtendedRegExChar: instance RegExDot.Consumer.Consumer RegExChar.ExtendedRegExChar.ExtendedRegExChar
+ RegExChar.ExtendedRegExChar: instance RegExDot.RegEx.ShortcutExpander GHC.Types.Char
+ RegExChar.ExtendedRegExChar: instance ToolShed.SelfValidate.SelfValidator RegExChar.ExtendedRegExChar.ExtendedRegExChar
+ RegExChar.MetaChar: instance GHC.Classes.Eq RegExChar.MetaChar.MetaChar
+ RegExChar.MetaChar: instance GHC.Read.Read RegExChar.MetaChar.MetaChar
+ RegExChar.MetaChar: instance GHC.Show.Show RegExChar.MetaChar.MetaChar
+ RegExChar.MetaChar: instance RegExDot.BracketExpressionMember.ShortcutExpander GHC.Types.Char
+ RegExChar.MetaChar: instance RegExDot.Consumer.Consumer RegExChar.MetaChar.MetaChar
+ RegExChar.MetaChar: instance RegExDot.Meta.ShortcutExpander GHC.Types.Char
+ RegExChar.MetaChar: instance ToolShed.SelfValidate.SelfValidator RegExChar.MetaChar.MetaChar
+ RegExChar.RegExOptsChar: instance Text.Regex.Base.RegexLike.RegexLike RegExChar.RegExOptsChar.RegExOptsChar RegExChar.ExtendedRegExChar.InputData
+ RegExChar.RegExOptsChar: instance Text.Regex.Base.RegexLike.RegexMaker RegExChar.RegExOptsChar.RegExOptsChar RegExDot.CompilationOptions.CompilationOptions RegExDot.ExecutionOptions.ExecutionOptions GHC.Base.String
+ RegExChar.RegExOptsChar: instance Text.Regex.Base.RegexLike.RegexOptions RegExChar.RegExOptsChar.RegExOptsChar RegExDot.CompilationOptions.CompilationOptions RegExDot.ExecutionOptions.ExecutionOptions

Files

+ README.markdown view
@@ -0,0 +1,24 @@+# **RegExChar**.++This is **RegExChar**, a regex-engine built from the polymorphic regex-engine 'RegExDot' as a proof of concept.++## Installation++It can be built and installed using [Cabal](https://www.haskell.org/cabal/users-guide/installing-packages.html).++## Documentation++*	The directory **man/** contains the documentation.+*	More information about this application can be found at [RegExChar](http://functionalley.eu/RegExChar/regExChar.html).++## License++For information on copying and distributing this package, see the file **LICENSE** in this directory.++## Bug-reporting++Bug-reports should be emailed to <regexchar *at* functionalley *dot* eu>.++## Author++This application is written and maintained by Dr. Alistair Ward.
− changelog
@@ -1,66 +0,0 @@-2010-11-18 Dr. Alistair Ward <regexchar at functionalley dot eu>--0.9.0.0-	* First version of the package.-0.9.0.1-	* Reacted to major-number changes in the packages 'ToolShed-0.10.0.0' & 'RegExDot-0.10.0.0'.-	* Created "src/RegExChar/" (& then modified module-names accordingly) & "data/" sub-directories.-	* Pacified 'hlint'.-	* Added a makefile.-	* Qualified identifiers used in error-messages.-0.9.0.2-	* Ported to ghc-7.0.1:-		Replaced the deprecated module "Test.QuickCheck.Batch", & labelled properties.-	* Added the cabal-flag 'threaded', to account for the requirement to link with the threaded runtime when using a threaded version of the library package "RegExDot".-0.9.0.3-	* Parallelised processing where @grecce@ is requested to read multiple input-data files.-	* Extracted matching-operation from the "Main" module, into new module "Grecce.Grep".-	* Migrated modules required only by the executable 'grecce', from the directory "RegExChar" into the new directory "Grecce".-	* Replaced use of @threaded@-flag in source-code, with CABAL CPP-macro.-	* Added RPM-spec file.-0.9.0.4-	* Added default values of command-line flags, to usage-message.-	* Reacted to migration of "RegExDot.Options" to "ToolShed.Options".-	* Used new "ToolShed.Package" module.-0.9.0.5-	* Fixed negated reference to unparenthesised CPP-macro 'MIN_VERSION'.-	* Protected reference in "Grecce/QC/QuickChecks.hs", to 'Test.QuickCheck.verboseCheck', using CPP-statement.-0.9.0.6-	* Amended RPM ".spec" file, to install under "/usr", rather than "/usr/local".-	* Renamed package from 'RegExChar' to 'regexchar', for compatibility with Debian's ".deb"-format.-	* Added directory-structure required to build ".deb" package.-0.9.0.7-	* Refined man-page to be an 'extra-source-file' in .cabal & .spec files.-	* Added manually controlled "llvm" flag to "regexchar.cabal".-	* Replaced references to the module "ToolShed.Package" with "Distribution.Package".-	* 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.-0.9.0.9-	* Recoded "RegExChar.RegExOptsChar" to the interface "Data.Array.IArray.IArray", rather than the data-type "Data.Array.Array".-	* Replaced '(+ 1)' and '(- 1)' with the faster calls 'succ' and 'pred', in "RegExChar.RegExOptsChar", "Grecce.Test.Performance.ExtendedRegExTestsPositive" and "Grecce.Grep".-	* Used 'Paths_regexchar.version' in 'Main', rather than hard-coding it.-	* Reacted to new module-hierarchy and addition of method 'ToolShed.SelfValidate.getErrors', in toolshed-0.13.0.0, and used it to improved error-reporting in @instance Read RegExChar.ExtendedRegExChar.ExtendedRegExChar@.-	* Replaced use of "Control.Monad" in "RegExChar.MetaChar" and "RegExChar.ExtendedRegExChar", with "Control.Applicative".-	* Replaced "System" with "System.Environment" and "System.Exit".-	* Removed dependency on "haskell98".-0.9.0.10-	* Fully qualified symbols imported from package "regexdot".-	* Used new constant 'RegExDot.Anchor.unanchored'.-	* Added details to any failure to parse the command-line arguments.-	* Used new test-modules from 'toolshed-0.14.0.0'.-0.9.0.11-	* Refactored 'Grecce.Test.QC.QuickChecks'.-	* Replaced calls to 'error' from inside the IO-monad, with 'Control.Monad.fail'.-	* Trapped command-line arguments to which garbage has been appended.-	* Added files to build .deb to 'regexchar.cabal'.-	* Tested with 'haskell-platform-2013.2.0.0'.-	* Replaced preprocessor-directives with 'build-depends' constraints in 'regexchar.cabal'.-0.9.0.12-	* Either replaced instances of '(<$>)' with 'fmap' to avoid ambiguity between "Control.Applicative" & "Prelude" which (from 'base-4.8') also exports this symbol, or hid the symbol when importing the "Prelude"..
+ changelog.markdown view
@@ -0,0 +1,77 @@+# 2010-11-18 Dr. Alistair Ward <regexchar at functionalley dot eu>++## 0.9.0.0+	* First version of the package.+## 0.9.0.1+	* Reacted to major-number changes in the packages **ToolShed-0.10.0.0** & **RegExDot-0.10.0.0**.+	* Created **src/RegExChar/** (& then modified module-names accordingly) & **data/** sub-directories.+	* Pacified **hlint**.+	* Added a makefile.+	* Qualified identifiers used in error-messages.+## 0.9.0.2+	* Ported to ghc-7.0.1:+		Replaced the deprecated module **Test.QuickCheck.Batch**, & labelled properties.+	* Added the cabal-flag **threaded**, to account for the requirement to link with the threaded runtime when using a threaded version of the library package **RegExDot**.+## 0.9.0.3+	* Parallelised processing where **grecce** is requested to read multiple input-data files.+	* Extracted matching-operation from the **Main** module, into new module **Grecce.Grep**.+	* Migrated modules required only by the executable **grecce**, from the directory **RegExChar** into the new directory **Grecce**.+	* Replaced use of @threaded@-flag in source-code, with CABAL CPP-macro.+	* Added *.spec*-file.+## 0.9.0.4+	* Added default values of command-line flags, to usage-message.+	* Reacted to migration of **RegExDot.Options** to **ToolShed.Options**.+	* Used new **ToolShed.Package** module.+## 0.9.0.5+	* Fixed negated reference to unparenthesised CPP-macro **MIN_VERSION**.+	* Protected reference in **Grecce/QC/QuickChecks.hs**, to `Test.QuickCheck.verboseCheck`, using CPP-statement.+## 0.9.0.6+	* Amended RPM *.spec*-file, to install under **/usr**, rather than **/usr/local**.+	* Renamed package from **RegExChar** to **regexchar**, for compatibility with Debian's *.deb*-format.+	* Added directory-structure required to build *.deb*-package.+## 0.9.0.7+	* Redefined man-page to be an **extra-source-file** in the *.cabal*-file & the *.spec*-file.+	* Added manually controlled **llvm** flag to the *.cabal*-file.+	* Replaced references to the module **ToolShed.Package** with **Distribution.Package**.+	* 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 [Hackage](http://hackage.haskell.org/packages/hackage.html).+## 0.9.0.8+	* Amended the *.cabal*-file 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 the *cabal*-file.+## 0.9.0.9+	* Recoded **RegExChar.RegExOptsChar** to the interface `Data.Array.IArray.IArray`, rather than the data-type `Data.Array.Array`.+	* Replaced `(+ 1)` and `(- 1)` with the faster calls `succ` and `pred`, in **RegExChar.RegExOptsChar**, **Grecce.Test.Performance.ExtendedRegExTestsPositive** and **Grecce.Grep**.+	* Used `Paths_regexchar.version` in **Main**, rather than hard-coding it.+	* Reacted to new module-hierarchy and addition of method `ToolShed.SelfValidate.getErrors`, in **toolshed-0.13.0.0**, and used it to improved error-reporting in @instance Read RegExChar.ExtendedRegExChar.ExtendedRegExChar@.+	* Replaced use of `Control.Monad` in **RegExChar.MetaChar** and **RegExChar.ExtendedRegExChar**, with `Control.Applicative`.+	* Replaced `System` with `System.Environment` and `System.Exit`.+	* Removed dependency on **haskell98**.+## 0.9.0.10+	* Fully qualified symbols imported from package **regexdot**.+	* Used new constant `RegExDot.Anchor.unanchored`.+	* Added details to any failure to parse the command-line arguments.+	* Used new test-modules from **toolshed-0.14.0.0**.+## 0.9.0.11+	* Refactored **Grecce.Test.QC.QuickChecks**.+	* Replaced calls to `error` from inside the IO-monad, with `Control.Monad.fail`.+	* Trapped command-line arguments to which garbage has been appended.+	* Added files to build *.deb* to the *.cabal*-file.+	* Tested with **haskell-platform-2013.2.0.0**.+	* Replaced preprocessor-directives with **build-depends** constraints in the *.cabal*-file.+## 0.9.0.12+	* Either replaced instances of `(<$>)` with `fmap` to avoid ambiguity between **Control.Applicative** & **Prelude** which (from **base-4.8**) also exports this symbol, or hid the symbol when importing the **Prelude**..+## 0.9.0.13+	* Added the compiler to the output returned for the command-line option **version**.+	* Changed flag **threaded** in the *.cabal*-file to **manual**.+	* Added **Default-language**-specification to the *.cabal*-file.+	* Added file **README.markdown**.+	* Converted this file to markdown-format.+	* Replaced `System.Exit.exitWith System.Exit.ExitSuccess` with `System.Exit.exitSuccess`.+	* Moved the entry-point to the test-suite from **Main.hs** to **Test.hs**, both to integrate with **cabal** & to minimise the dependencies of the executable.+	* Partitioned the source-files into **src-lib**, **src-exe**, & **src-test** directories, & referenced them individually from the *.cabal*-file to avoid repeated compilation.+	* Used **CPP** to control the import of symbols from **Control.Applicative**.+
@@ -5,7 +5,7 @@ 	Copyright (C) 2010-2011 Dr. Alistair Ward. All Rights Reserved.  Home-page:-	http://functionalley.eu+	http://functionalley.eu/RegExChar/regExChar.html  License: 	GNU GENERAL PUBLIC LICENSE Version 3; see '/usr/share/common-licenses/GPL-3' or '/usr/share/doc/licenses/gpl-3.0.txt' where available, or the local packaged file 'LICENSE'.
debian/DEBIAN/control view
@@ -1,14 +1,13 @@ Package:	regexchar-Version:	0.9.0.12-1+Version:	0.9.0.13-1 Section:	text Priority:	optional-#Architecture:	i386 Architecture:	amd64 Depends:	libc6-Installed-size:	3496+Installed-size:	3222 Maintainer:	Dr. Alistair Ward <regexchar at functionalley dot eu> Provides:-Homepage:	http://functionalley.eu+Homepage:	http://functionalley.eu/RegExChar/regExChar.html Description:	POSIX extended regular-expression engine.  POSIX extended regex-engine, specialised from the underlying polymorphic engine regexdot, to merely process character-lists, as is typically required. 
− makefile
@@ -1,81 +0,0 @@-# Copyright (C) 2010-2014 Dr. Alistair Ward-#-# This program is free software: you can redistribute it and/or modify-# it under the terms of the GNU General Public License as published by-# 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/>.--.PHONY: all build check clean clobber configure copy deb haddock help hlint install lintian prof rpm rpmlint sdist--PACKAGE_NAME=regexchar--all: install--install: build haddock-	@[ -z "$$CABAL_INSTALL_OPTIONS" ] || echo "INFO: CABAL_INSTALL_OPTIONS='$$CABAL_INSTALL_OPTIONS'"-	runhaskell Setup $@ $$CABAL_INSTALL_OPTIONS--prof:-	CABAL_CONFIGURE_OPTIONS="--enable-library-profiling --enable-executable-profiling $$CABAL_CONFIGURE_OPTIONS" make build--copy: build-	@[ -z "$$CABAL_COPY_OPTIONS" ] || echo "INFO: CABAL_COPY_OPTIONS='$$CABAL_COPY_OPTIONS'"-	runhaskell Setup $@ $$CABAL_COPY_OPTIONS--build: configure-	@[ -z "$$CABAL_BUILD_OPTIONS" ] || echo "INFO: CABAL_BUILD_OPTIONS='$$CABAL_BUILD_OPTIONS'"-	runhaskell Setup $@ $$CABAL_BUILD_OPTIONS--configure: $(PACKAGE_NAME).cabal Setup.hs-	@[ -z "$$CABAL_CONFIGURE_OPTIONS" ] || echo "INFO: CABAL_CONFIGURE_OPTIONS='$$CABAL_CONFIGURE_OPTIONS'"-	runhaskell Setup $@ $$CABAL_CONFIGURE_OPTIONS	#--user--haddock: configure-	PATH=~/.cabal/bin:$$PATH runhaskell Setup $@ --hyperlink-source --executables	#Amend path to find 'HsColour', as required for 'hyperlink-source'.--hlint:-	@$@ -i 'Use ||' src/ +RTS -N--sdist:-	TAR_OPTIONS='--format=ustar' runhaskell Setup $@--check:-	cabal upload --check --verbose=3 dist/*.tar.gz;--rpm: $(PACKAGE_NAME).spec-	rpmbuild -bb --nodeps -- $^-	mv -- `find ~/rpmbuild -type f -name '$(PACKAGE_NAME)*.rpm' -mtime 0 -print` ./--rpmlint: $(PACKAGE_NAME).spec-	@$@ $^--deb: build-	mkdir -p debian/usr/bin/ && strip --strip-all dist/build/grecce/grecce && mv dist/build/grecce/grecce debian/usr/bin/-	mkdir -p 'debian/usr/share/doc/$(PACKAGE_NAME)/' && cp changelog changelog.Debian copyright LICENSE 'debian/usr/share/doc/$(PACKAGE_NAME)/' && cd 'debian/usr/share/doc/$(PACKAGE_NAME)/' && gzip --best -f changelog changelog.Debian LICENSE-	cp 'copyright' 'debian/usr/share/doc/$(PACKAGE_NAME)/'-	mkdir -p 'debian/usr/share/$(PACKAGE_NAME)/' && cp -R data/ 'debian/usr/share/$(PACKAGE_NAME)/'-	mkdir -p debian/usr/share/ && cp -R man/ debian/usr/share/ && gzip --best -f debian/usr/share/man/man1/*.1-	cd 'debian' && md5sum `find usr -type f -print` >'DEBIAN/md5sums'-	fakeroot dpkg-deb --build debian .--lintian:-	lintian -v *.deb--clean:-	runhaskell Setup $@-	rm -rf 'debian/usr/' 'debian/DEBIAN/md5sums'-	find src -type f \( -name '*.hc' -o -name '*.hcr' -o -name '*.hi' -o -name '*.o' \) -delete--clobber: clean-	rm -f -- *.rpm *.deb--help:-	@grep '^[a-zA-Z].*:' makefile | sed -e 's/:.*//'
man/man1/grecce.1 view
@@ -131,9 +131,6 @@ Display the currently defined options & then exit. .SS Test .TP-\fB--runQuickChecks\fR-Uses \fBQuickCheck\fR to validate invariant properties, using arbitrary data; then exits.-.TP \fB--assert=\fR\fIfile\fR Confirms the assertions in the specified file from the \fBdata\fR-directory of the distribution; then exits. .SH EXIT-STATUS@@ -181,7 +178,7 @@ Written by Dr. Alistair Ward. .SH BUGS .SS "REPORTING BUGS"-Report bugs to \fBgrecce\fR \fIat\fR \fBfunctionalley\fR \fIdot\fR \fBeu\fR+Report bugs to <\fBgrecce\fR \fIat\fR \fBfunctionalley\fR \fIdot\fR \fBeu\fR>. .SS Known Bugs There is no support for either \fIBack-references\fR or \fICase-insensitivity\fR. .PP@@ -189,7 +186,7 @@ .PP File-reading is rather slow, due to the inability to optimise the underlying polymorphic regex-engine for Characters. .SH COPYRIGHT-Copyright \(co 2010 Dr. Alistair Ward+Copyright \(co 2010-2015 Dr. Alistair Ward .PP 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. .PP@@ -198,7 +195,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see \fB<http://www.gnu.org/licenses/>\fR. .SH "SEE ALSO" .IP \(bu-Home-page: \fBhttp://functionalley.eu\fR+Home-page: \fBhttp://functionalley.eu/RegExChar/regExChar\fR .IP \(bu Source-documentation is generated by "\fBHaddock\fR", & is available in the distribution. .IP \(bu
regexchar.cabal view
@@ -1,35 +1,65 @@--- Package-properties-Name:			regexchar-Version:		0.9.0.12-Cabal-Version:		>= 1.6-Copyright:		(C) 2010-2015 Dr. Alistair Ward-License:		GPL-License-file:		LICENSE-Author:			Dr. Alistair Ward-Stability:		Stable interface, incomplete features.-Synopsis:		A POSIX, extended regex-engine.-Build-Type:		Simple-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, GHC == 7.4, GHC == 7.6, GHC == 7.10-Homepage:		http://functionalley.eu-Maintainer:		regexchar <at> functionalley <dot> eu-Bug-reports:		regexchar <at> functionalley <dot> eu-Data-files:		data/*.txt-Extra-Source-Files:	changelog copyright changelog.Debian debian/DEBIAN/control makefile man/man1/grecce.1 regexchar.spec+-- This file is part of RegExChar.+--+-- RegExChar 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.+--+-- RegExChar 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 RegExChar.  If not, see <http://www.gnu.org/licenses/>. -flag threaded-    Description:	Link with the threaded runtime.-    default:		True+Name:		regexchar+Version:	0.9.0.13+Cabal-version:	>= 1.10+Copyright:	(C) 2010-2015 Dr. Alistair Ward+License:	GPL+License-file:	LICENSE+Author:		Dr. Alistair Ward+Stability:	stable+Synopsis:	A POSIX, extended regex-engine.+Build-type:	Simple+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, GHC == 7.4, GHC == 7.6, GHC == 7.8, GHC == 7.10+Homepage:	http://functionalley.eu/RegExChar/regExChar.html+Maintainer:	mailto <colon> regexchar <at> functionalley <dot> eu+Bug-reports:	mailto <colon> regexchar <at> functionalley <dot> eu --- Turn on using: 'runhaskell ./Setup.hs configure -f llvm'.+-- These files can be read by the application from 'Paths_weekdaze.datadir'.+Data-files:+    data/*.txt++-- None of these files are needed at run-time.+Extra-source-files:+    changelog.Debian+    changelog.markdown+    copyright+    debian/DEBIAN/control+    man/man1/grecce.1+    README.markdown+    regexchar.spec++-- Enable using: 'cabal configure -f llvm'. flag llvm     Description:	Whether the 'llvm' compiler-backend has been installed and is required for code-generation.-    manual:		True-    default:		False+    Manual:		True+    Default:		False +flag threaded+    Description:	Link with the threaded runtime.+    Manual:		True+    Default:		True+ Library-    hs-source-dirs:	src+    Default-language:	Haskell2010+    GHC-options:	-Wall -O2 -fno-warn-tabs+    GHC-prof-options:	-prof -auto-all -caf-all+    Hs-source-dirs:	src-lib      Exposed-modules:         RegExChar.ExtendedRegExChar@@ -37,13 +67,13 @@         RegExChar.RegExOptsChar      Build-depends:+        array,         base == 4.*,         containers,         parsec == 3.*,+        regex-base,         regexdot >= 0.11.1.0,-        toolshed >= 0.14--    GHC-options:	-Wall -fno-warn-tabs+        toolshed >= 0.16      if impl(ghc >= 7.4.1)         GHC-prof-options:	-prof -fprof-auto -fprof-cafs@@ -54,8 +84,13 @@         GHC-options:	-fllvm  Executable grecce-    hs-source-dirs:	src-    Main-Is:		Main.hs+    Default-language:	Haskell2010+    GHC-options:	-Wall -O2 -fno-warn-tabs+    GHC-prof-options:	-prof -auto-all -caf-all+    Hs-source-dirs:	src-exe+    Main-is:		Main.hs++-- Required for 'cabal sdist'.     Other-modules:         Grecce.CommandOptions         Grecce.Grep@@ -64,21 +99,16 @@         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,-        Cabal >= 1.6 && < 2,+        base == 4.*,+        Cabal >= 1.10,         parallel >= 3.0,-        QuickCheck >= 2.4,+        regexchar,         regex-base,-        regex-posix--    GHC-options:	-Wall -O2 -fno-warn-tabs-    GHC-prof-options:	-prof -auto-all -caf-all+        regex-posix,+        regexdot >= 0.11.1.0,+        toolshed >= 0.16      if flag(threaded)         GHC-options:	-threaded@@ -88,4 +118,24 @@          if flag(llvm)             GHC-options:	-fllvm++Test-Suite quickCheck+    Default-language:	Haskell2010+    GHC-options:	-Wall -fno-warn-tabs+    Hs-source-dirs:	src-test+    Main-is:		Main.hs+    Type:		exitcode-stdio-1.0++-- Required for 'cabal sdist'.+    Other-modules:+        Grecce.Test.QC.ExtendedRegExChar+        Grecce.Test.QC.MetaChar+        Grecce.Test.QC.RepeatableMetaChar++    Build-depends:+        base == 4.*,+        QuickCheck >= 2.4,+        regexchar,+        regexdot >= 0.11.1.0,+        toolshed >= 0.16 
regexchar.spec view
@@ -1,4 +1,4 @@-# Copyright (C) 2012-2014 Dr. Alistair Ward+# Copyright (C) 2012-2015 Dr. Alistair Ward # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by@@ -15,57 +15,55 @@  %define package		%name-%version %define tarBall		%package.tar.gz-%define _bindir		%prefix/bin-%define _libdir		%prefix/lib/%package %define _sharedir	%prefix/share-%define _datadir	%_sharedir/%package-%define _docdir		%_sharedir/doc/%package+%define _datadir	%_sharedir/%name+%define _docdir		%_sharedir/doc/%name %define _mandir		%_sharedir/man  Summary:	A re-implementation of egrep, using a specialisation of a polymorphic regex-engine Name:		regexchar-Version:	0.9.0.12+Version:	0.9.0.13 Release:	1 License:	GPLv3-#From '/usr/share/doc/packages/rpm/GROUPS'.+# From '/usr/share/doc/packages/rpm/GROUPS'. Group:		Applications/Text Source0:	http://functionalley.eu/Downloads/sdist/%tarBall-URL:		http://functionalley.eu+URL:		http://functionalley.eu/RegExChar/regExChar.html Prefix:		/usr-BuildRequires:	ghc+BuildRequires:	haskell-platform  %description-Provides a POSIX extended regex-engine, specialised from an underlying polymorphic engine, to process merely character-lists, as is typically required.+Provides a POSIX extended regex-engine, specialised from an underlying polymorphic engine "regexdot", to process merely character-lists, as is typically required.  %prep-#NB: we've changed directory to %_builddir-(cd $OLDPWD && runhaskell Setup sdist) && tar -zxf $OLDPWD/dist/%tarBall	#Make a source-distribution & unpack it into the build-directory.-cd '%package/' && runhaskell Setup configure --user --prefix=%prefix		#Configure to use the user's personal package-database & to generate an appropriate Paths module.+# NB: CWD has changed to %_builddir+echo 'package="%package", prefix="%prefix", _builddir="%_builddir", buildroot="%buildroot"'+(cd $OLDPWD && cabal sdist) && tar -zxf $OLDPWD/dist/%tarBall	# Make a source-distribution & unpack it into the build-directory.+cd '%package/' && cabal configure --user --prefix='%prefix' --datadir='%_datadir' --datasubdir='' --docdir='%_docdir'	# Tell cabal to use the user's personal package-database, to generate an appropriate "Paths" module, & where to place the documentation.  %build-cd '%package/' && runhaskell Setup build	#Descend into the source-distribution and build according to the previously established configuration.+cd '%package/' && cabal build	# Descend into the source-distribution and build according to the previously established configuration.  %install-cd '%package/'					#Descend into the build-directory.-runhaskell Setup copy --destdir=%buildroot	#Install the package in the target-directory.-rm -rf '%buildroot%_libdir/'			#Remove unrequired libraries.-mkdir -p -- '%buildroot%_docdir' && mv changelog copyright LICENSE '%buildroot%_docdir/'+cd '%package/'	# Descend into the build-directory.+cabal copy --destdir='%buildroot'	# Install the built package in the target-directory.+mkdir -p -- '%buildroot%_docdir' && mv 'changelog.markdown' 'copyright' 'README.markdown' '%buildroot%_docdir/'	# 'LICENSE' has already been copied by cabal. mkdir -p -- '%buildroot%_mandir' && mv 'man/man1' '%buildroot%_mandir/'+rm -rf -- '%buildroot%prefix/lib/'	# The library isn't a deliverable.  %clean-make --directory='%package' clobber-rm -rf -- '%_builddir/%package/' '%buildroot'+rm -rf -- '%_builddir/%package/' '%buildroot/'	# Only the '.rpm' is required.  %files-%attr(0755, root, root)		%_bindir/grecce+%attr(0755, root, root)		%prefix/bin/grecce %attr(0644, root, root)		%_datadir/data/*.txt-%attr(0644, root, root)	%doc	%_docdir/changelog+%attr(0644, root, root)	%doc	%_docdir/changelog.markdown %attr(0644, root, root)	%doc	%_docdir/copyright %attr(0644, root, root)	%doc	%_docdir/LICENSE+%attr(0644, root, root)	%doc	%_docdir/README.markdown %attr(0644, root, root)	%doc	%_mandir/man1/grecce.1.gz  %changelog * Wed May 09 2012	Alistair Ward	<regexchar at functionalley dot eu>	0.9.0.10-1-Removed "rm -rf -- '%buildroot'" from build, for security.-Corrected "Paths" module, even though it's unused.+First cut. 
+ src-exe/Grecce/CommandOptions.hs view
@@ -0,0 +1,172 @@+{-+	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 options, read from the command-line,+	& as such assumes that the type-parameter of the underlying polymorphic /regex/-engine is 'Char'.++	* Supplies mutators, which ensure the consistency of the chosen set.+-}++module Grecce.CommandOptions(+-- * Types+-- ** Type-synonyms+	CompilationOptionsMutator,+	ExecutionOptionsMutator,+--	Transformer,+-- ** Data-types+	CommandOptions(..),+-- * Functions+-- ** Mutators+	setCompilationOption,+	setCountMatches,+	setExecutionOption,+	setInvertMatch,+	setPrependLineNumbers,+	setListFilesWithMatches,+	setListFilesWithoutMatch,+	setVerbose+) where++import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar+import qualified	RegExDot.CompilationOptions+import qualified	RegExDot.ExecutionOptions+import qualified	ToolShed.Defaultable+import qualified	ToolShed.Options++-- | The set of command-line options; based on those provided by /egrep/.+data CommandOptions	= MkCommandOptions {+	countMatches		:: Bool,						-- ^ Print only a count of matching lines per file.+	extendedRegExChar	:: Maybe ExtendedRegExChar.ExtendedRegExChar,		-- ^ The /regex/.+	invertMatch		:: Bool,						-- ^ Select non-matching lines.+	prependLineNumbers	:: Bool,						-- ^ Prepend the line-number of the matched input-data, to the output.+	listFilesWithMatches	:: Bool,						-- ^ List the names of any files containing at least one match.+	listFilesWithoutMatch	:: Bool,						-- ^ List the names of any files containing zero matches.+	verbose			:: Bool,						-- ^ Show the captured data.+	compilationOptions	:: RegExDot.CompilationOptions.CompilationOptions,	-- ^ Used to define the regex-request.+	executionOptions	:: RegExDot.ExecutionOptions.ExecutionOptions		-- ^ Used to control the regex-runtime.+} deriving Show++-- | An arbitrary function which transforms the supplied 'RegExDot.ExecutionOptions.ExecutionOptions'.+type Transformer	= CommandOptions -> CommandOptions++instance ToolShed.Defaultable.Defaultable CommandOptions	where+	defaultValue	= ToolShed.Options.blankValue {+		countMatches		= False,+		extendedRegExChar	= Nothing,+		invertMatch		= False,+		prependLineNumbers	= False,+		listFilesWithMatches	= False,+		listFilesWithoutMatch	= False,+		verbose			= False,+		compilationOptions	= ToolShed.Defaultable.defaultValue,+		executionOptions	= ToolShed.Defaultable.defaultValue+	}++instance ToolShed.Options.Options CommandOptions	where+	blankValue	= MkCommandOptions {+		countMatches		= undefined,+		extendedRegExChar	= undefined,+		invertMatch		= undefined,+		prependLineNumbers	= undefined,+		listFilesWithMatches	= undefined,+		listFilesWithoutMatch	= undefined,+		verbose			= undefined,+		compilationOptions	= undefined,+		executionOptions	= undefined+	}++-- | Mutator.+setCountMatches :: Transformer+setCountMatches commandOptions+	| ($ commandOptions) `any` [+		prependLineNumbers,+		listFilesWithoutMatch,+		listFilesWithMatches,+		verbose+	]		= error "Grecce.CommandOptions.setCountMatches:\t'countMatches' is incompatible with; 'prependLineNumbers', 'listFilesWithoutMatch', 'listFilesWithMatches' & 'verbose'."+	| otherwise	= commandOptions { countMatches = True }++-- | Mutator.+setInvertMatch :: Transformer+setInvertMatch commandOptions+	| verbose commandOptions	= error "Grecce.CommandOptions.setInvertMatch:\t'invertMatch' is incompatible with 'verbose'."+	| otherwise			= commandOptions { invertMatch = True }++-- | Mutator.+setPrependLineNumbers :: Transformer+setPrependLineNumbers commandOptions+	| ($ commandOptions) `any` [+		countMatches,+		listFilesWithoutMatch,+		listFilesWithMatches+	]		= error "Grecce.CommandOptions.setPrependLineNumbers:\t'prependLineNumbers' is incompatible with 'countMatches', 'listFilesWithoutMatch' & 'listFilesWithMatches'."+	| otherwise	= commandOptions { prependLineNumbers = True }++-- | Mutator.+setListFilesWithMatches :: Transformer+setListFilesWithMatches commandOptions+	| ($ commandOptions) `any` [+		countMatches,+		prependLineNumbers,+		listFilesWithoutMatch,+		verbose+	]		= error "Grecce.CommandOptions.setListFilesWithMatches:\t'listFilesWithMatches' is incompatible with; 'countMatches', 'prependLineNumbers', 'listFilesWithoutMatch' & 'verbose'."+	| otherwise	= commandOptions { listFilesWithMatches = True }++-- | Mutator.+setListFilesWithoutMatch :: Transformer+setListFilesWithoutMatch commandOptions+	| ($ commandOptions) `any` [+		countMatches,+		prependLineNumbers,+		listFilesWithMatches,+		verbose+	]		= error "Grecce.CommandOptions.setListFilesWithoutMatch:\t'listFilesWithoutMatch' is incompatible with; 'countMatches', 'prependLineNumbers', 'listFilesWithMatches' & 'verbose'."+	| otherwise	= commandOptions { listFilesWithoutMatch = True }++-- | Mutator, which additionally sets the corresponding 'RegExDot.ExecutionOptions.ExecutionOptions'.+setVerbose :: Transformer+setVerbose commandOptions+	| ($ commandOptions) `any` [+		countMatches,+		invertMatch,+		listFilesWithoutMatch,+		listFilesWithMatches+	]		= error "Grecce.CommandOptions.setVerbose:\t'verbose' is incompatible with; 'countMatches', 'invertMatch', 'listFilesWithoutMatch' & 'listFilesWithMatches'."+	| otherwise	= commandOptions {+		verbose			= True,+		executionOptions	= RegExDot.ExecutionOptions.setVerbose True $ executionOptions commandOptions+	}++-- | A function which accepts a 'String' & the 'RegExDot.CompilationOptions.CompilationOptions' to transform, using its value.+type CompilationOptionsMutator	= String -> RegExDot.CompilationOptions.CompilationOptions -> RegExDot.CompilationOptions.CompilationOptions++-- | Generic mutator, which accepts a function & the parameter-string it requires, to amend an unspecified field of 'RegExDot.CompilationOptions.CompilationOptions'.+setCompilationOption :: CompilationOptionsMutator -> String -> Transformer+setCompilationOption compilationOptionsMutator s commandOptions	= commandOptions { compilationOptions = compilationOptionsMutator s $ compilationOptions commandOptions }++-- | A function which accepts a 'String' & the 'RegExDot.ExecutionOptions.ExecutionOptions' to transform, using its value.+type ExecutionOptionsMutator	= String -> RegExDot.ExecutionOptions.ExecutionOptions -> RegExDot.ExecutionOptions.ExecutionOptions++-- | Generic mutator, which accepts a function & the parameter-string it requires, to amend an unspecified field of 'RegExDot.ExecutionOptions.ExecutionOptions'.+setExecutionOption :: ExecutionOptionsMutator -> String -> Transformer+setExecutionOption executionOptionsMutator s commandOptions	= commandOptions { executionOptions = executionOptionsMutator s $ executionOptions commandOptions }+
+ src-exe/Grecce/Grep.hs view
@@ -0,0 +1,206 @@+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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@]	Performs the match-operation on the specified file-list, using the user's command-line options.+-}++module Grecce.Grep(+-- * Types+--	LineNumber,+--	Matches,+-- ** Type-synonyms+-- * Functions+	grep+) where++import			Control.Arrow((&&&))+import qualified	Control.Arrow+import qualified	Control.Monad+import qualified	Control.Parallel.Strategies+import qualified	Data.List+import qualified	Grecce.CommandOptions		as CommandOptions+import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar+import			RegExChar.ExtendedRegExChar((+~), (=~))+import qualified	RegExDot.RegEx+import qualified	RegExDot.RegExOpts+import qualified	RegExDot.Result+import qualified	System.Exit+import qualified	System.IO++type LineNumber	= Int+type Matches	= Int++-- | Creates a 'RegExDot.RegExOpts.RegExOpts' record from 'CommandOptions.CommandOptions', and uses it to filter the lines read from the list of input-data files, the result of which is then printed.+grep+	:: CommandOptions.CommandOptions	-- ^ The match-criteria, which may include the name of the file on which to operate.+	-> [String]				-- ^ A supplementary list of files on which to operate+	-> IO ()				-- ^ Nothing is returned, since the result is printed.+grep commandOptions nonOptions+{-+ The algorithm depends fundamentally on whether the data comes from 'stdin' or from file.+ This is because of the requirement, in the former case, to deliver instantaneous feedback.+ This forces us to print matches as they're found, rather than batching them for return to the caller to print.+ If we COULD return 'IO [String]', then 'matchFilterStdIn' could be called instead of 'grep' when (fileName == "-"); annoyingly, it just doesn't work.+-}+	| any ($ fileNames) [null, all (== "-")]	= let+		matchFilterStdIn :: LineNumber -> Matches -> IO System.Exit.ExitCode+		matchFilterStdIn lineNumber matches	= {-#SCC "matchFilterStdIn" #-} do+			isEOF	<- System.IO.isEOF++			if isEOF+				then if listFilesWithMatches+					then return {-to IO-monad-} $ System.Exit.ExitFailure 1	-- No match has been found, otherwise we'd have exited earlier.+					else if listFilesWithoutMatch+						then putStrLn dummyFileName	>> return {-to IO-monad-} System.Exit.ExitSuccess+						else do+							Control.Monad.when countMatches $ print matches++							return {-to IO-monad-} $ if matches == 0+								then System.Exit.ExitFailure 1+								else System.Exit.ExitSuccess+				else {-not EOF-} do+					line	<- getLine	-- Process line-at-a-time, to provide instant feedback.++					let+						lineNumber' :: LineNumber+						lineNumber'	= succ lineNumber++						onSuccess :: String -> IO System.Exit.ExitCode+						onSuccess line'+							| listFilesWithMatches	= putStrLn dummyFileName	>> return {-to IO-monad-} System.Exit.ExitSuccess+							| listFilesWithoutMatch	= return {-to IO-monad-} $ System.Exit.ExitFailure 1+							| otherwise		= do+								Control.Monad.unless countMatches . putStrLn $ (+									if prependLineNumbers+										then showLineNumber lineNumber'+										else id+								 ) line'++								matchFilterStdIn lineNumber' $ succ matches	-- Recurse.++						onFailure, onMismatch :: IO System.Exit.ExitCode+						onFailure	= matchFilterStdIn lineNumber' matches	-- Recurse+						onMismatch+							| invertMatch	= onSuccess line+							| otherwise	= onFailure++					if verbose+						then let+							result :: RegExDot.RegEx.Result Char+							result	= line +~ regExOpts+						in if RegExDot.Result.isMatch result+							then if invertMatch+								then onFailure+								else onSuccess $ show result+							else onMismatch+						else {-terse-} if line =~ regExOpts+							then if invertMatch+								then onFailure+								else onSuccess line+							else onMismatch+			where+				dummyFileName :: String+				dummyFileName	= "<standard input>"+	in matchFilterStdIn 0 0 >>= System.Exit.exitWith+	| otherwise {-file-names provided-}	= let+		findMatch :: String -> RegExDot.RegEx.Result Char+		findMatch	= (+~ regExOpts)++		matchFilter :: [String] -> [String]+		matchFilter	= {-#SCC "matchFilter" #-} (+			if countMatches+				then return {-to List-monad-} . show . length	-- Substitute the list of matches, with its length.+				else id+		 ) . (+			let+				isMatch :: String -> Bool+				isMatch = {-#SCC "isMatch" #-} (if invertMatch then not else id) . (=~ regExOpts)+			in if prependLineNumbers+				then map (uncurry showLineNumber) . (+					if verbose+						then map (+							Control.Arrow.second show+						) . filter (+							RegExDot.Result.isMatch . snd+						) . map (+							Control.Arrow.second findMatch+						)+						else {-terse-} filter (isMatch . snd)+				) . zip [1 :: LineNumber ..]+				else {-unnumbered-} if verbose+					then map show . filter RegExDot.Result.isMatch . map findMatch+					else {-terse-} filter isMatch+		 )++		identifySource :: String -> [String] -> [String]+		identifySource fileName results+			| listFilesWithMatches			= [fileName | not isEmpty] {-list-comprehension-}+			| listFilesWithoutMatch			= [fileName | isEmpty] {-list-comprehension-}+			| length (Data.List.nub fileNames) > 1	= (showString fileName . separate) `map` results+			| otherwise				= results+			where+				isEmpty :: Bool+				isEmpty	= null results+	in do+		results <- (+			concat . Control.Parallel.Strategies.parMap Control.Parallel.Strategies.rdeepseq (+				uncurry identifySource . Control.Arrow.second (matchFilter . {-#SCC "lines" #-} lines {-chops '\n'-})+			) . zip fileNames+		 ) `fmap` mapM readFile fileNames++		mapM_ putStrLn results++		System.Exit.exitWith $ if null results+			then System.Exit.ExitFailure 1+			else System.Exit.ExitSuccess+	where+		countMatches, invertMatch, prependLineNumbers, listFilesWithMatches, listFilesWithoutMatch, verbose :: Bool+		[countMatches, invertMatch, prependLineNumbers, listFilesWithMatches, listFilesWithoutMatch, verbose]	= ($ commandOptions) `map` [+			CommandOptions.countMatches,+			CommandOptions.invertMatch,+			CommandOptions.prependLineNumbers,+			CommandOptions.listFilesWithMatches,+			CommandOptions.listFilesWithoutMatch,+			CommandOptions.verbose+		 ] -- Divvy-up.++-- Separate the regEx & the names of the input-data files to feed it.+		extendedRegExChar	:: ExtendedRegExChar.ExtendedRegExChar+		fileNames		:: [String]+		(extendedRegExChar, fileNames)	= case CommandOptions.extendedRegExChar commandOptions of+			Just c	-> (c, nonOptions)+			_+				| null nonOptions	-> error "Undefined regex."+				| otherwise		-> read . head &&& tail $ nonOptions++-- Combine the regex & options, to create a complete task-description.+		regExOpts :: RegExDot.RegExOpts.RegExOpts ExtendedRegExChar.ExtendedRegExChar+		regExOpts	= RegExDot.RegExOpts.MkRegExOpts {+			RegExDot.RegExOpts.compilationOptions	= CommandOptions.compilationOptions commandOptions,+			RegExDot.RegExOpts.executionOptions	= CommandOptions.executionOptions commandOptions,+			RegExDot.RegExOpts.regEx		= extendedRegExChar+		}++-- Define functions used to format the output.+		separate :: ShowS+		separate	= showChar ':'++		showLineNumber :: LineNumber -> ShowS+		showLineNumber n	= shows n . separate+
+ src-exe/Grecce/Test/Assert/RegExOptsChar.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE FlexibleContexts #-}+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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 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+import qualified	RegExDot.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 :: RegExDot.CompilationOptions.CompilationOptions -> RegExDot.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 parse " ++ show fileName ++ "; " ++ show line ++ "."+	) . filter (+		(/= '#') . head	-- Remove comments.+	) . filter (+		not . null	-- Remove blank lines.+	) . lines+ ) `fmap` readFile fileName+
+ src-exe/Grecce/Test/Performance/ExtendedRegEx.hs view
@@ -0,0 +1,148 @@+{-# LANGUAGE CPP #-}+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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 'RegExDot.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 qualified	Control.Arrow+import			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+import qualified	RegExDot.RegEx+import qualified	RegExDot.RegExOpts+import qualified	Text.Regex.Posix+import qualified	ToolShed.Defaultable+import qualified	ToolShed.System.TimePure++#if !MIN_VERSION_base(4,8,0)+import	Control.Applicative((<$>), (<*>))+#endif++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 :: RegExDot.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 (+				ToolShed.System.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 -> (+					RegExDot.RegEx./~ RegExDot.RegExOpts.MkRegExOpts {	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+						RegExDot.RegExOpts.compilationOptions	= ToolShed.Defaultable.defaultValue,+						RegExDot.RegExOpts.executionOptions	= executionOptions,+						RegExDot.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 <$> (+				(ToolShed.System.TimePure.getCPUSeconds . ($ inputData)) `mapM` [+					showMatch,+					if RegExDot.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 :: RegExDot.RegExOpts.RegExOpts (RegExDot.RegEx.ExtendedRegEx Char)+					regExOpts	= RegExDot.RegExOpts.MkRegExOpts {+						RegExDot.RegExOpts.compilationOptions	= ToolShed.Defaultable.defaultValue,+						RegExDot.RegExOpts.executionOptions	= executionOptions,+						RegExDot.RegExOpts.regEx		= extendedRegEx+					} -- Similar to 'RegexLike.makeRegexOpts', but without the requirement to read the regex.+				in if RegExDot.ExecutionOptions.requireMatchList executionOptions+					then show . (RegExDot.RegEx.+~ regExOpts)	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+					else show . (RegExDot.RegEx.=~ regExOpts)	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+			) &&& show . ExtendedRegExChar.MkExtendedRegExChar False {-hasNonCapturingTopLevelAlternatives-}+		 ) . testGenerator+
+ src-exe/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++-- | 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	= (RegExDot.RegEx.InputData a, RegExDot.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-exe/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-exe/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+import qualified	RegExDot.BracketExpressionMember+import			RegExDot.DSL((-:), (?:), (*:), (<~>))+import qualified	RegExDot.Meta+import qualified	RegExDot.RegEx+import			RegExDot.RegEx((.*), (.*?))+import qualified	RegExDot.Repeatable+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 -> (RegExDot.RegEx.Pattern Char -> RegExDot.RegEx.RepeatablePattern Char) -> RegExDot.RegEx.RepeatablePattern Char+					exactly n f	= (RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . return {-to List-monad-} $ f testRequirement) ^# n+				in ((Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . (`map` [RegExDot.Repeatable.zeroOrOne, RegExDot.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")) &&& RegExDot.RegEx.dock . (+					`mkExtendedRegExFromRepeatableSingletonAlternative` (RegExDot.Anchor.unanchored <~>) [+						(.*),+						RegExDot.RegEx.simply $ RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.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 (+					RegExDot.Anchor.unanchored <~> RegExDot.RegEx.captureGroup (+						map (+							(RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . (testRequirement ^#) . (2 ^)+						) [0 :: Int .. 1]+					) *: RegExDot.RegEx.Require (RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . return {-to List-monad-} . RegExDot.Repeatable.zeroOrMore . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ [RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . replicate i . RegExDot.Repeatable.one . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ [RegExDot.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 :: RegExDot.Repeatable.Repetitions+					base	= 2	-- Arbitrarily.++					bounds :: RegExDot.Repeatable.RepetitionBounds+					bounds	= (0, Just base)+				in (`replicate` testChar) . (base ^) &&& RegExDot.RegEx.dock . (+					(+						mkExtendedRegExFromRepeatableSingletonAlternative (^#-># bounds) `iterate` (RegExDot.Anchor.unanchored <~>) [testRequirement ^#-># bounds] {-initial value-}+					) !!+				) . pred+			),+{-+ "^((((((((((((((<testChar>*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*? ... $".+ Explanation:	interesting because all 'RegExDot.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) &&& RegExDot.RegEx.dock . (+					(+						mkExtendedRegExFromRepeatableSingletonAlternative RegExDot.Repeatable.zeroOrMore' `iterate` (RegExDot.Anchor.unanchored <~>) [RegExDot.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 RegExDot.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 :: RegExDot.Repeatable.Repetitions+					base	= 2	-- Arbitrarily.+				in (`replicate` testChar) . (base ^) &&& RegExDot.RegEx.dock . head . (+					(+						iterate (+							\extendedRegExList -> (+								(RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . (^# base) . RegExDot.RegEx.captureGroup+							) `map` [extendedRegExList, reverse extendedRegExList]+						) $ map (+							(RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . ($ RegExDot.RegEx.Require $ RegExDot.Meta.Literal testChar)+						) [RegExDot.Repeatable.one, RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) $ map RegExDot.Repeatable.zeroOrMore [+						RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ (+							\i -> ($ i) `map` [+								(testRequirement ^#),+								RegExDot.RegEx.simply . RegExDot.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 :: [RegExDot.RegEx.Concatenation Char] -> RegExDot.RegEx.Concatenation Char+					zeroOrMoreAlternatives	= return {-to List-monad-} . RegExDot.Repeatable.zeroOrMore . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>)+				in (+					id &&& (+						((Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . (RegExDot.RegEx.Require (RegExDot.Meta.Literal testChar) ?:) . zeroOrMoreAlternatives . map (+							\(a, b)	-> zeroOrMoreAlternatives $ return {-to List-monad-} [a, b]+						) . init . tail . uncurry zip . (+							map RegExDot.Repeatable.one . init &&& map RegExDot.Repeatable.zeroOrOne . tail+						) . bracket undefined . map (+							RegExDot.RegEx.Require . RegExDot.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'	= succ complexity++					testSet :: String+					testSet	= take complexity' . filter Data.Char.isAlphaNum $ filter Data.Char.isAscii [minBound .. maxBound]+				in (+					concat $ replicate complexity' testSet,+					((Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) $ (+						RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ map (+							return {-to List-monad-} . RegExDot.RegEx.simply . RegExDot.Meta.Literal+						) testSet+					) *: [+						(+							RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} $ RegExDot.RegEx.Require (RegExDot.Meta.Literal $ head testSet) -: (.*?) : RegExDot.RegEx.Require (RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . return {-to List-monad-} . RegExDot.Repeatable.zeroOrMore . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . (+						[+							RegExDot.Repeatable.zeroOrMore testRequirement,+							RegExDot.RegEx.simply . RegExDot.Meta.NoneOf $ map RegExDot.BracketExpressionMember.Literal [testChar]+						] :+					) . map (+						return {-to List-monad-} . RegExDot.RegEx.simply . RegExDot.Meta.NoneOf . return {-to List-monad-} . RegExDot.BracketExpressionMember.Literal+					) . (+						`take` tail [testChar ..]+					)+				)+			)+		]+	 ) where+		testChar :: Char+		testChar	= 'a'++		testRequirement :: RegExDot.RegEx.Pattern Char+		testRequirement	= RegExDot.RegEx.Require $ RegExDot.Meta.Literal testChar++		mkExtendedRegExFromRepeatableSingletonAlternative :: (RegExDot.RegEx.Pattern Char -> RegExDot.RegEx.RepeatablePattern Char) -> RegExDot.RegEx.ExtendedRegEx Char -> RegExDot.RegEx.ExtendedRegEx Char+		mkExtendedRegExFromRepeatableSingletonAlternative makeRepetitions	= (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . makeRepetitions . RegExDot.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 * succ i `div` 2
+ src-exe/Main.hs view
@@ -0,0 +1,208 @@+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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@]++	* Contains the entry-point to the program.++	* Provides command-line access to "ExtendedRegExChar".++	* Defines the permissible command-line arguments; aping /egrep/, but with the addition of /--verbose/, which enables one to see the details of the data-capture.++ [@TODO@]	Coordinate the output of 'printVersion' with the definition in '.cabal'; this may not be feasible.+-}++module Main(main) where++import qualified	Data.List+import qualified	Data.Version+import qualified	Distribution.Package+import qualified	Distribution.Text+import qualified	Distribution.Version+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	Paths_regexchar						as Paths	-- Either local stub, or package-instance autogenerated by 'Setup.hs build'.+import qualified	RegExDot.CompilationOptions+import qualified	RegExDot.ExecutionOptions+import qualified	System.Console.GetOpt					as G+import qualified	System.Environment+import qualified	System.Exit+import qualified	System.Info+import qualified	System.IO+import qualified	System.IO.Error+import qualified	ToolShed.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'.++-- | On failure to parse the specified string, returns an explanatory error.+read' :: Read a => String -> String -> a+read' errorMessage s	= case reads s of+	[(x, "")]	-> x+	_		-> error $ errorMessage ++ show s++-- | On failure to parse a command-line argument, returns an explanatory error.+readCommandArg :: Read a => String -> a+readCommandArg	= read' "failed to parse command-line argument "++{- |+	* Parses the command-line arguments, to determine 'CommandOptions.CommandOptions'.++	* Arguments following 'CommandOptions.CommandOptions', are interpreted as a /regex/, followed by the names of the files to which it is applied.+-}+main :: IO ()+main	= do+	progName	<- System.Environment.getProgName++	let+		usageMessage :: String+		usageMessage	= "Usage:\t" ++ G.usageInfo progName optDescrList ++ "  <regex> [<file-name>, ...]"++-- Define the command-line options, & the 'CommandLineAction's used to handle them.+		optDescrList :: [G.OptDescr CommandLineAction]+		optDescrList	= [+--				 String	[String]					(G.ArgDescr CommandLineAction)							String+			G.Option "?"	["help"]					(G.NoArg $ const printUsage)							"Output:\tdisplay this help-text & then exit.",+			G.Option ""	["verbose"]					(G.NoArg $ return {-to IO-monad-} . CommandOptions.setVerbose)			("Output:\tsee how the input data was captured by the RegEx; default '" ++ show (CommandOptions.verbose ToolShed.Defaultable.defaultValue) ++ "'. CAVEAT: to be effective, it should precede other options."),+			G.Option ""	["version"]					(G.NoArg $ const printVersion)							"Output:\tprint version-information & then exit.",+			G.Option "c"	["count"]					(G.NoArg $ return {-to IO-monad-} . CommandOptions.setCountMatches)		("Output:\tprint only a count of matching lines per file; default '" ++ show (CommandOptions.countMatches ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option "l"	["files-with-matches"]				(G.NoArg $ return {-to IO-monad-} . CommandOptions.setListFilesWithMatches)	("Output:\tlist names of files containing at least one match; default '" ++ show (CommandOptions.listFilesWithMatches ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option "L"	["files-without-match"]				(G.NoArg $ return {-to IO-monad-} . CommandOptions.setListFilesWithoutMatch)	("Output:\tlist names of files not containing any matches; default '" ++ show (CommandOptions.listFilesWithoutMatch ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option "n"	["number"]					(G.NoArg $ return {-to IO-monad-} . CommandOptions.setPrependLineNumbers)	("Output:\tprepend the line-number of the input, to the output; default '" ++ show (CommandOptions.prependLineNumbers ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option "v"	["invert-match"]				(G.NoArg $ return {-to IO-monad-} . CommandOptions.setInvertMatch)		("Output:\tselect non-matching lines; default '" ++ show (CommandOptions.invertMatch ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["printCurrentSettings"]			(G.NoArg printCurrentSettings)							"Output:\tdisplay the currently defined options & then exit.",+			G.Option "e"	["regex"]					(setExtendedRegExChar `G.ReqArg` "<regex>")					"Input:\tdefine the regex.",+			G.Option "f"	["file"]					(readExtendedRegExCharFromFile `G.ReqArg` "<file-name>")			"Input:\tread the regex from file.",+			G.Option ""	["performance"]					(+				extendedRegExCharPerformance `G.ReqArg` "(Int,Either [TestName])"+			) (+				"Test:\tcompare performance with other RegEx-engines, using the specified pair (<Maximum complexity>, Left " ++ show [+					minBound :: Test.Performance.ExtendedRegExTestsNegative.TestName .. maxBound+				] ++ " or Right " ++ show [+					minBound :: Test.Performance.ExtendedRegExTestsPositive.TestName .. maxBound+				] ++ "). NB: specify this option last."+			),+			G.Option ""	["assert"]					(assertFromFile `G.ReqArg` "<file-name>")					"Test:\trun the assertions, defined in the specified file, & then exit. NB: specify this option last.",+			G.Option ""	["assertPosix"]					(assertPosixFromFile `G.ReqArg` "<file-name>")					"Test:\trun the assertions, defined in the specified file, against Text.Regex.Posix, & then exit. NB: specify this option last.",+			G.Option ""	["abortTrialRepetitionsOnInherentFailure"]	(setExecutionOption abortTrialRepetitionsOnInherentFailure `G.ReqArg` "Bool")	("Performance:\tif an alternative can't match, irrespective of the subsequent concatenation, then terminate futile trial repetitions; default '" ++ show (RegExDot.ExecutionOptions.abortTrialRepetitionsOnInherentFailure ToolShed.Defaultable.defaultValue) ++ "'."),+--			G.Option ""	["abortTrialRepetitionsOnZeroConsumption"]	(setExecutionOption abortTrialRepetitionsOnZeroConsumption `G.ReqArg` "Bool")	("Performance:\tcheck for zero data-consumption by the n-th repetition of an alternative, before considering (n + 1); default '" ++ show (RegExDot.ExecutionOptions.abortTrialRepetitionsOnZeroConsumption ToolShed.Defaultable.defaultValue) ++ "'."),+--			G.Option ""	["bypassInputDataForLiberalConsumer"]		(setExecutionOption bypassInputDataForLiberalConsumer `G.ReqArg` "Bool")	("Performance:\tbypass reading of the unconsumed input data, if the remaining RegEx can consume a sufficient quantity of anything; default '" ++ show (RegExDot.ExecutionOptions.bypassInputDataForLiberalConsumer ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["catchIncompatibleAnchors"]			(setExecutionOption catchIncompatibleAnchors `G.ReqArg` "Bool")			("Performance:\tavoid futile trial solutions, involving repetitions of anchored alternatives, which must consume data; default '" ++ show (RegExDot.ExecutionOptions.catchIncompatibleAnchors ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["checkExistenceOfInelasticTail"]		(setExecutionOption checkExistenceOfInelasticTail `G.ReqArg` "Bool")		("Performance:\tif the regex ends in one or more Meta-data, whose repetition-range is precisely defined, check that this sequence exists at the end of the input data; default '" ++ show (RegExDot.ExecutionOptions.checkExistenceOfInelasticTail ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["checkForUnconsumableData"]			(setExecutionOption checkForUnconsumableData `G.ReqArg` "Bool")			("Performance:\tcheck whether there's no possibility of consuming some of the input data; default '" ++ show (RegExDot.ExecutionOptions.checkForUnconsumableData ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["moderateGreed"]				(setExecutionOption moderateGreed `G.ReqArg` "Bool")				("Performance:\tgreedily consume data, only up to the limit beyond which, future requirements would be compromised; default '" ++ show (RegExDot.ExecutionOptions.moderateGreed ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["permitReorderingOfAlternatives"]		(setExecutionOption permitReorderingOfAlternatives `G.ReqArg` "Bool")		("Performance:\tpermit alternatives to be re-ordered, in an attempt to process the cheapest first; default '" ++ show (RegExDot.ExecutionOptions.permitReorderingOfAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["preferAlternativesWhichFeedTheGreedy"]	(setExecutionOption preferAlternativesWhichFeedTheGreedy `G.ReqArg` "Bool")	("Preference:\tprefer solutions in which the choice of alternatives directs data from non-greedy to greedy consumers; default '" ++ show (RegExDot.ExecutionOptions.preferAlternativesWhichFeedTheGreedy ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["preferAlternativesWhichMimickUnrolling"]	(setExecutionOption preferAlternativesWhichMimickUnrolling `G.ReqArg` "Bool")	("Preference:\tprefer solutions in which the choice of alternatives consumes data like the unrolled repeatable group; default '" ++ show (RegExDot.ExecutionOptions.preferAlternativesWhichMimickUnrolling ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["preferFewerRepeatedAlternatives"]		(setExecutionOption preferFewerRepeatedAlternatives `G.ReqArg` "Bool")		("Preference:\tprefer solutions employing fewer repetitions of alternatives, to discourage the capture of null lists; default '" ++ show (RegExDot.ExecutionOptions.preferFewerRepeatedAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["unrollRepeatedSingletonAlternative"]		(setExecutionOption unrollRepeatedSingletonAlternative `G.ReqArg` "Bool")	("Performance:\tunroll repetitions of singleton alternatives; this doesn't affect the result; default '" ++ show (RegExDot.ExecutionOptions.unrollRepeatedSingletonAlternative ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["useFirstMatchAmongAlternatives"]		(setExecutionOption useFirstMatchAmongAlternatives `G.ReqArg` "Bool")		("Performance:\trather than performing an exhaustive search for the optimal choice amongst alternatives, merely select the first that matches; conform to Perl rather than Posix; default '" ++ show (RegExDot.ExecutionOptions.useFirstMatchAmongAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["validateMinConsumptionOfAlternatives"]	(setExecutionOption validateMinConsumptionOfAlternatives `G.ReqArg` "Bool")	("Performance:\twhen the number of repetitions of a group of alternatives is precisely specified, check the availability of the resulting minimum data-requirement; default '" ++ show (RegExDot.ExecutionOptions.validateMinConsumptionOfAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),+			G.Option ""	["complyStrictlyWithPosix"]			(setCompilationOption complyStrictlyWithPosix `G.ReqArg` "Bool")		("Output:\tdefine the offset of captured data, corresponding to a sub-expression which matched zero times, as the artificial value -1 specified by Posix; currently only affects results of 'assert'; default '" ++ show (RegExDot.CompilationOptions.complyStrictlyWithPosix ToolShed.Defaultable.defaultValue) ++ "'.")+		 ] where+			printVersion, printUsage :: IO CommandOptions.CommandOptions++			printVersion	= System.IO.hPutStrLn System.IO.stderr (+				Distribution.Text.display packageIdentifier ++ "\n\nCompiled by " ++ show compiler ++ ".\n\nCopyright (C) 2010-2015 " ++ author ++ ".\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by " ++ author ++ "."+			 ) >> System.Exit.exitSuccess	where+				packageIdentifier :: Distribution.Package.PackageIdentifier+				packageIdentifier	= Distribution.Package.PackageIdentifier {+					Distribution.Package.pkgName	= Distribution.Package.PackageName "grecce",+					Distribution.Package.pkgVersion	= Distribution.Version.Version (Data.Version.versionBranch Paths.version) []+				}++				author, compiler :: String+				author		= "Dr. Alistair Ward"+				compiler	= System.Info.compilerName ++ "-" ++ Data.List.intercalate "." (map show $ Data.Version.versionBranch System.Info.compilerVersion)++			printUsage	= System.IO.hPutStrLn System.IO.stderr usageMessage	>> System.Exit.exitSuccess++			printCurrentSettings :: CommandLineAction+			printCurrentSettings commandOptions	= print commandOptions	>> System.Exit.exitSuccess++			extendedRegExCharPerformance, readExtendedRegExCharFromFile, assertFromFile, assertPosixFromFile, setExtendedRegExChar :: String -> CommandLineAction+			extendedRegExCharPerformance s commandOptions	= (+				uncurry $ Test.Performance.ExtendedRegEx.run (CommandOptions.executionOptions commandOptions)+			 ) (readCommandArg s)	>> System.Exit.exitSuccess++			readExtendedRegExCharFromFile s commandOptions	= ((head . dropWhile null . lines) `fmap` readFile s) >>= (`setExtendedRegExChar` commandOptions)++			assertFromFile fileName commandOptions	= do+				failedTests	<- Test.Assert.RegExOptsChar.findFailures (CommandOptions.compilationOptions commandOptions) (CommandOptions.executionOptions commandOptions) `fmap` Test.Assert.RegExOptsChar.readTests fileName++				if null failedTests+					then System.Exit.exitSuccess+					else do+						mapM_ print failedTests++						System.Exit.exitWith $ System.Exit.ExitFailure 2++			assertPosixFromFile fileName _	= do+				failedTests	<- Test.Assert.RegExOptsChar.findFailuresPosix `fmap` Test.Assert.RegExOptsChar.readTests fileName++				if null failedTests+					then System.Exit.exitSuccess+					else do+						mapM_ print failedTests++						System.Exit.exitWith $ System.Exit.ExitFailure 2++			setExtendedRegExChar s commandOptions	= case CommandOptions.extendedRegExChar commandOptions of+				Just extendedRegExChar	-> fail $ "The regex has already been defined as /" ++ show extendedRegExChar ++ "/"+				_			-> return {-to IO-monad-} commandOptions { CommandOptions.extendedRegExChar = Just $ readCommandArg s }++			abortTrialRepetitionsOnInherentFailure, {-abortTrialRepetitionsOnZeroConsumption, bypassInputDataForLiberalConsumer,-} catchIncompatibleAnchors, checkExistenceOfInelasticTail, checkForUnconsumableData, moderateGreed, permitReorderingOfAlternatives, preferAlternativesWhichFeedTheGreedy, preferAlternativesWhichMimickUnrolling, preferFewerRepeatedAlternatives, unrollRepeatedSingletonAlternative, useFirstMatchAmongAlternatives, validateMinConsumptionOfAlternatives :: CommandOptions.ExecutionOptionsMutator+			abortTrialRepetitionsOnInherentFailure s e	= e { RegExDot.ExecutionOptions.abortTrialRepetitionsOnInherentFailure = readCommandArg s }+--			abortTrialRepetitionsOnZeroConsumption s e	= e { RegExDot.ExecutionOptions.abortTrialRepetitionsOnZeroConsumption = readCommandArg s }+--			bypassInputDataForLiberalConsumer s e		= e { RegExDot.ExecutionOptions.bypassInputDataForLiberalConsumer = readCommandArg s }+			catchIncompatibleAnchors s e			= e { RegExDot.ExecutionOptions.catchIncompatibleAnchors = readCommandArg s }+			checkExistenceOfInelasticTail s e		= e { RegExDot.ExecutionOptions.checkExistenceOfInelasticTail = readCommandArg s }+			checkForUnconsumableData s e			= e { RegExDot.ExecutionOptions.checkForUnconsumableData = readCommandArg s }+			moderateGreed s e				= e { RegExDot.ExecutionOptions.moderateGreed = readCommandArg s }+			permitReorderingOfAlternatives s e		= e { RegExDot.ExecutionOptions.permitReorderingOfAlternatives = readCommandArg s }+			preferAlternativesWhichFeedTheGreedy s e	= e { RegExDot.ExecutionOptions.preferAlternativesWhichFeedTheGreedy = readCommandArg s }+			preferAlternativesWhichMimickUnrolling s e	= e { RegExDot.ExecutionOptions.preferAlternativesWhichMimickUnrolling = readCommandArg s }+			preferFewerRepeatedAlternatives s e		= e { RegExDot.ExecutionOptions.preferFewerRepeatedAlternatives = readCommandArg s }+			unrollRepeatedSingletonAlternative s e		= e { RegExDot.ExecutionOptions.unrollRepeatedSingletonAlternative = readCommandArg s }+			useFirstMatchAmongAlternatives s e		= e { RegExDot.ExecutionOptions.useFirstMatchAmongAlternatives = readCommandArg s }+			validateMinConsumptionOfAlternatives s e	= e { RegExDot.ExecutionOptions.validateMinConsumptionOfAlternatives = readCommandArg s }++			complyStrictlyWithPosix :: CommandOptions.CompilationOptionsMutator+			complyStrictlyWithPosix s e	= e { RegExDot.CompilationOptions.complyStrictlyWithPosix = readCommandArg s }++			setCompilationOption :: CommandOptions.CompilationOptionsMutator -> String -> CommandLineAction+			setCompilationOption compilationOptionsMutator s	= return {-to IO-monad-} . CommandOptions.setCompilationOption compilationOptionsMutator s++			setExecutionOption :: CommandOptions.ExecutionOptionsMutator -> String -> CommandLineAction+			setExecutionOption executionOptionsMutator s	= return {-to IO-monad-} . CommandOptions.setExecutionOption executionOptionsMutator s++	args	<- System.Environment.getArgs++--	G.getOpt :: G.ArgOrder CommandLineAction -> [G.OptDescr Action] -> [String] -> ([Action], [String], [String])+	case G.getOpt G.RequireOrder optDescrList args of+		(commandLineActions, nonOptions, [])	-> do+			commandOptions	<- Data.List.foldl' (>>=) (return {-to IO-monad-} ToolShed.Defaultable.defaultValue) commandLineActions	-- Sequentially transform the 'CommandOptions', using 'CommandLineAction's corresponding to the specified command-line flags.++			Grep.grep commandOptions nonOptions	-- Perform the requested match, against the list of input-data files.+		(_, _, errors)	-> System.IO.Error.ioError . System.IO.Error.userError $ concat errors ++ usageMessage	-- Throw.+
+ src-lib/RegExChar/ExtendedRegExChar.hs view
@@ -0,0 +1,210 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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@]	An 'RegExDot.RegEx.ExtendedRegEx', which has been specialised for 'Char', to create a tradition non-polymorphic /regex/.+-}++module RegExChar.ExtendedRegExChar(+-- * Types+-- ** Type-synonyms+	ExtendedRegExChar(..),+	InputData,+-- * Functions+-- ** Operators+	(+~),+	(=~),+	(/~)+) where++import qualified	Data.List+import qualified	RegExChar.MetaChar		as MetaChar+import qualified	RegExDot.Anchor+import qualified	RegExDot.Consumer+import			RegExDot.DSL((<~>), (-:))+import qualified	RegExDot.RegEx+import qualified	RegExDot.RegExOpts+import qualified	RegExDot.Repeatable+import qualified	Text.ParserCombinators.Parsec	as Parsec+import			Text.ParserCombinators.Parsec((<?>), (<|>))+import qualified	ToolShed.Data.Pair+import qualified	ToolShed.SelfValidate++#if !MIN_VERSION_base(4,8,0)+import	Control.Applicative((<$>), (<*>))+#endif++infix 4 +~, =~, /~	-- Same as (==) & (/=).++-- | Specialise a 'RegExDot.RegEx.ExtendedRegEx' for 'Char', & encapsulate it to permit tailored instance-declarations.+data ExtendedRegExChar	= MkExtendedRegExChar {+	hasNonCapturingTopLevelAlternatives	:: Bool,	-- ^ The string from which a 'RegExDot.RegEx.ExtendedRegEx' is read, may, if data-capture isn't required, omit explicit delimiters around top-level 'RegExDot.RegEx.Alternatives'.+	extendedRegEx				:: RegExDot.RegEx.ExtendedRegEx Char+} deriving Eq++-- | Abbreviation.+type InputData	= RegExDot.RegEx.InputData Char++instance ToolShed.SelfValidate.SelfValidator ExtendedRegExChar	where+	getErrors MkExtendedRegExChar {+		hasNonCapturingTopLevelAlternatives	= hasNonCapturingTopLevelAlternatives',+		extendedRegEx				= extendedRegEx'+	}+		| not $ ToolShed.SelfValidate.isValid extendedRegEx'	= ToolShed.SelfValidate.getErrors extendedRegEx'+		| otherwise						= ToolShed.SelfValidate.extractErrors [+			(hasNonCapturingTopLevelAlternatives' && any (not . RegExDot.RegEx.isCaptureGroup . RegExDot.Repeatable.base) (RegExDot.RegEx.concatenation extendedRegEx'), "Invalid NonCapturingTopLevelAlternatives.")+		]++instance RegExDot.Consumer.Consumer ExtendedRegExChar	where+	consumptionProfile	= RegExDot.Consumer.consumptionProfile . extendedRegEx+	starHeight		= RegExDot.Consumer.starHeight . extendedRegEx++instance RegExDot.RegEx.ShortcutExpander Char	where+	expand c	= error $ "RegExDot.RegEx.ShortcutExpander.expand RegExChar.ExtendedRegExChar:\tunrecognised shortcut '" ++ show c ++ "'."++instance Read ExtendedRegExChar	where+	readsPrec _ s+		| s == reverse RegExDot.Anchor.tokens	= [+			(+				MkExtendedRegExChar {+					hasNonCapturingTopLevelAlternatives	= False,+					extendedRegEx				= (Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~> []+				},+				""+			)+		] -- The order of adjacent zero-width assertions is irrelevant.+		| otherwise			= let+			extendedRegExCharParser :: Parsec.Parser ExtendedRegExChar+			extendedRegExCharParser	= reduce {-correct prior assumption-} <$> alternativesParser {-assume non-capturing top-level Alternatives-} where+				reduce :: RegExDot.RegEx.Alternatives Char -> ExtendedRegExChar+				reduce alternatives+					| RegExDot.RegEx.isSingletonAlternatives alternatives	= MkExtendedRegExChar False . head $ RegExDot.RegEx.deconstructAlternatives alternatives+					| otherwise						= MkExtendedRegExChar True $ RegExDot.Anchor.unanchored <~> RegExDot.RegEx.CaptureGroup alternatives -: []	-- Infer non-capturing top-level 'RegExDot.RegEx.Alternatives' from the presence of 'RegExDot.RegEx.alternativeExtendedRegExSeparatorToken's.++				alternativesParser :: Parsec.Parser (RegExDot.RegEx.Alternatives Char)+				alternativesParser	= RegExDot.RegEx.MkAlternatives <$> extendedRegExParser `Parsec.sepBy1` (Parsec.char RegExDot.RegEx.alternativeExtendedRegExSeparatorToken <?> "RegExDot.RegEx.alternativeExtendedRegExSeparatorToken " ++ show RegExDot.RegEx.alternativeExtendedRegExSeparatorToken)	where+					extendedRegExParser :: Parsec.Parser (RegExDot.RegEx.ExtendedRegEx Char)+					extendedRegExParser	= do+						maybeBowAnchor			<- Parsec.option Nothing {-default-} $ (Parsec.char RegExDot.Anchor.bowToken <?> "RegExDot.Anchor.bowToken " ++ show RegExDot.Anchor.bowToken) >> return {-to ParsecT-monad-} (Just RegExDot.Anchor.Bow)+						repeatableRequirementList	<- repeatableRequirementListParser++						(+							do+								repeatableCaptureGroup	<- RegExDot.Repeatable.repeatableParser . RegExDot.RegEx.CaptureGroup =<< uncurry Parsec.between (+									ToolShed.Data.Pair.mirror Parsec.char RegExDot.RegEx.captureGroupDelimiters+								 ) alternativesParser {-recurse-} <?> "RegExDot.RegEx.captureGroupDelimiters " ++ show RegExDot.RegEx.captureGroupDelimiters++								extendedRegEx'		<- extendedRegExParser	-- Recurse.++								return {-to ParsecT-monad-} $ RegExDot.RegEx.transformExtendedRegEx ((repeatableRequirementList ++) . (repeatableCaptureGroup :)) extendedRegEx' { RegExDot.RegEx.bowAnchor = maybeBowAnchor }+						 ) <|> (+							do+								maybeSternAnchor	<- Parsec.option Nothing {-default-} $ (Parsec.char RegExDot.Anchor.sternToken <?> "RegExDot.Anchor.sternToken " ++ show RegExDot.Anchor.sternToken) >> return {-to ParsecT-monad-} (Just RegExDot.Anchor.Stern)++								return {-to ParsecT-monad-} RegExDot.RegEx.MkExtendedRegEx {+									RegExDot.RegEx.bowAnchor	= maybeBowAnchor,+									RegExDot.RegEx.concatenation	= repeatableRequirementList,+									RegExDot.RegEx.sternAnchor	= maybeSternAnchor+								}+						 )+						where+							repeatableRequirementListParser :: Parsec.Parser (RegExDot.RegEx.Concatenation Char)+							repeatableRequirementListParser	= Parsec.choice [+								Parsec.try . Parsec.lookAhead $ (+									Parsec.char RegExDot.Anchor.sternToken <?> "RegExDot.Anchor.sternToken " ++ show RegExDot.Anchor.sternToken+								) >> (+									(+										Parsec.eof >> return {-to ParsecT-monad-} []+									) <|> (+										Parsec.oneOf [RegExDot.RegEx.alternativeExtendedRegExSeparatorToken, snd RegExDot.RegEx.captureGroupDelimiters] >> return {-to ParsecT-monad-} []+									)+								),+								(:) <$> (+									MetaChar.metaCharParser >>= RegExDot.Repeatable.repeatableParser . RegExDot.RegEx.Require . MetaChar.deconstruct+								) <*> repeatableRequirementListParser, {-recurse-}+								return {-to ParsecT-monad-} []+							 ]++		in (+			error . ("readsPrec RegExChar.ExtendedRegExChar:\tparse-error; " ++) . show	-- Failure to parse.+		) `either` (+			\pair@(extendedRegExChar, _)	-> if ToolShed.SelfValidate.isValid extendedRegExChar+				then [pair]+				else error $ ToolShed.SelfValidate.getFirstError extendedRegExChar	-- Parsed OK, but invalid.+		) $ Parsec.parse (+			(,) <$> extendedRegExCharParser <*> Parsec.getInput+		) "ExtendedRegExChar" s++instance Show ExtendedRegExChar	where+	showsPrec _ MkExtendedRegExChar {+		hasNonCapturingTopLevelAlternatives	= hasNonCapturingTopLevelAlternatives',+		extendedRegEx				= RegExDot.RegEx.MkExtendedRegEx {+			RegExDot.RegEx.bowAnchor	= maybeBowAnchor,+			RegExDot.RegEx.concatenation	= concatenation',+			RegExDot.RegEx.sternAnchor	= maybeSternAnchor+		}+	} = RegExDot.RegEx.showsMaybeAnchor maybeBowAnchor . foldl (.) (showString "") (+		(+			let+				showAlternatives :: RegExDot.RegEx.Alternatives Char -> [ShowS]+				showAlternatives	= Data.List.intersperse (showChar RegExDot.RegEx.alternativeExtendedRegExSeparatorToken) . map (shows . MkExtendedRegExChar False) . RegExDot.RegEx.deconstructAlternatives+			in if hasNonCapturingTopLevelAlternatives'+				then map (+					\repeatablePattern	-> case RegExDot.Repeatable.base repeatablePattern of+						RegExDot.RegEx.CaptureGroup alternatives	-> foldr (.) (showString "") $ showAlternatives alternatives+						_						-> error $ "Show RegExChar.ExtendedRegExChar: unexpected " ++ show repeatablePattern+				)+				else map (+					\repeatablePattern	-> (+						case RegExDot.Repeatable.base repeatablePattern of+							RegExDot.RegEx.Require meta			-> shows $ MetaChar.MkMetaChar meta+							RegExDot.RegEx.CaptureGroup alternatives	-> showChar (+								fst RegExDot.RegEx.captureGroupDelimiters+							 ) . foldr (.) (+								showChar $ snd RegExDot.RegEx.captureGroupDelimiters	-- Initial value.+							 ) (+								showAlternatives alternatives+							 )+					) . RegExDot.Repeatable.showSuffix repeatablePattern+				)+		 ) concatenation'+	 ) . RegExDot.RegEx.showsMaybeAnchor maybeSternAnchor++-- | A veneer over the underlying polymorphic operator, 'RegExDot.RegEx.+~'.+(+~)+	:: InputData						-- ^ The input-data string.+	-> RegExDot.RegExOpts.RegExOpts ExtendedRegExChar	-- ^ The match-options, parameterised by the regex-specification.+	-> RegExDot.RegEx.Result Char+inputData +~ regExOpts	= inputData RegExDot.RegEx.+~ fmap extendedRegEx regExOpts	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.++-- | A veneer over the underlying polymorphic operator, 'RegExDot.RegEx.=~'.+(=~)+	:: InputData						-- ^ The input-data string.+	-> RegExDot.RegExOpts.RegExOpts ExtendedRegExChar	-- ^ The match-options, parameterised by the regex-specification.+	-> Bool+inputData =~ regExOpts	= inputData RegExDot.RegEx.=~ fmap extendedRegEx regExOpts	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.++-- | Pattern-mismatch operator.+(/~)+	:: InputData						-- ^ The input-data string.+	-> RegExDot.RegExOpts.RegExOpts ExtendedRegExChar	-- ^ The match-options, parameterised by the regex-specification.+	-> Bool+(/~) inputData	= not . (inputData =~)+
+ src-lib/RegExChar/MetaChar.hs view
@@ -0,0 +1,256 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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 'RegExDot.Meta.ShortcutExpander' 'Char', to implement some of the traditional /Perl-style shortcuts/:++	[@\\d@]		=> Any 'Data.Char.isDigit'-character.++	[@\\D@]		=> Any non-'Data.Char.isDigit' character.++	[@\\s@]		=> Any 'Data.Char.isSpace'-character.++	[@\\S@]		=> Any non-'Data.Char.isSpace' character.++	[@\\w@]		=> Any 'Data.Char.isWord' letter.++	[@\\W@]		=> Any non-'Data.Char.isWord' letter.++	* Enables one to compose concise regexen, containing any 'Char' that's a member of one of these predefined sets.++	* Though 'RegExDot.Meta.Meta' is polymorphic, & the type-parameter can't be assumed to implement either 'Enum' or 'Ord',+	'Char' actually does, so this module is able to implement ranges within a /Bracket-expression/.++	* Defines specialised instances of 'Read' & 'Show', to cope with /Perl-style shortcuts/, /Posix Character-classes/ & /Bracket-expression/ range-specifications.++ [@TODO@]	Use @Environment.getLocale@. Regrettably, this returns in the "IO"-monad, & even it didn't, how does one pass that information to 'Read' ?!+-}++module RegExChar.MetaChar(+-- * Types+--	AssociationList,+--	Dictionary,+-- ** Type-synonyms+	MetaChar(..),+-- * Constants+--	bracketExpressionRangeToken,+--	posixCharacterClassDelimiters,+-- * Functions+--	implementPerlShortcut,+	metaCharParser,+-- ** Accessors (Deconstructors)+	deconstruct+) where++import			Control.Arrow((***))+import qualified	Data.Char+import qualified	Data.Map+import qualified	RegExDot.BracketExpression+import qualified	RegExDot.BracketExpressionMember+import qualified	RegExDot.Consumer+import qualified	RegExDot.Meta+import qualified	RegExDot.RegEx+import qualified	RegExDot.Repeatable+import qualified	RegExDot.ShowablePredicate+import qualified	Text.ParserCombinators.Parsec	as Parsec+import			Text.ParserCombinators.Parsec((<?>))+import qualified	ToolShed.Data.Pair+import qualified	ToolShed.SelfValidate++#if !MIN_VERSION_base(4,8,0)+import	Control.Applicative((<$>), (<*>))+#endif++-- | Holds a mapping from an escape-sequence & the predicate via which it is implemented.+type AssociationList key	= [(key, RegExDot.ShowablePredicate.Predicate Char)]++-- | Holds a mapping from an escape-sequence & the predicate via which it is implemented.+type Dictionary key		= Data.Map.Map key (RegExDot.ShowablePredicate.Predicate Char)++instance RegExDot.BracketExpressionMember.ShortcutExpander Char	where+	findPredicate shortcut	= RegExDot.ShowablePredicate.MkShowablePredicate [RegExDot.Meta.shortcutToken, shortcut] <$> shortcut `Data.Map.lookup` dictionary where+		dictionary :: Dictionary Char+		dictionary	= Data.Map.fromList $ perlShortcuts ++ invert perlShortcuts	where+			perlShortcuts :: AssociationList Char+			perlShortcuts	= [+				('d',	Data.Char.isDigit),+				('s',	Data.Char.isSpace),+				('w',	\c -> ($ c) `any` [Data.Char.isAlphaNum, (== '_')])+			 ]++			invert :: AssociationList Char -> AssociationList Char+			invert	= map (Data.Char.toUpper *** (not .))++instance RegExDot.Meta.ShortcutExpander Char	where+	expand c	= case RegExDot.BracketExpressionMember.findPredicate c of+		Just showablePredicate	-> RegExDot.Meta.Predicate showablePredicate+		_			-> RegExDot.Meta.Literal c++-- | A specialised instance, encapsulated to permit tailored instance-declarations.+newtype MetaChar	= MkMetaChar (RegExDot.Meta.Meta Char)	deriving Eq++-- | Accessor.+deconstruct :: MetaChar -> RegExDot.Meta.Meta Char+deconstruct (MkMetaChar metaChar)	= metaChar++instance ToolShed.SelfValidate.SelfValidator MetaChar	where+	getErrors	= ToolShed.SelfValidate.getErrors . deconstruct++instance RegExDot.Consumer.Consumer MetaChar	where+	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstruct+	starHeight		= RegExDot.Consumer.starHeight . deconstruct++-- | Builds a parser of traditional regex-syntax, which understands 'Char'-specific concepts like /Perl-style shortcuts/ & /Posix Character-classes/.+metaCharParser :: Parsec.Parser MetaChar+metaCharParser	= MkMetaChar <$> Parsec.choice [+	(Parsec.char RegExDot.Meta.anyToken <?> "RegExDot.Meta.anyToken " ++ show RegExDot.Meta.anyToken) >> return {-to ParsecT-monad-} RegExDot.Meta.Any,+	(Parsec.char RegExDot.Meta.shortcutToken <?> "RegExDot.Meta.shortcutToken " ++ show RegExDot.Meta.shortcutToken) >> RegExDot.Meta.expand <$> Parsec.anyChar,+	uncurry Parsec.between (ToolShed.Data.Pair.mirror Parsec.char RegExDot.BracketExpression.delimiterTokens) (+		do+			let+				implementPosixCharacterClass :: String -> Maybe (RegExDot.ShowablePredicate.ShowablePredicate Char)+				implementPosixCharacterClass identifier	= RegExDot.ShowablePredicate.MkShowablePredicate (+					fst posixCharacterClassDelimiters ++ identifier ++ snd posixCharacterClassDelimiters+				 ) <$> identifier `Data.Map.lookup` dictionary	where+					dictionary :: Dictionary String+					dictionary	= Data.Map.fromList $ posixCharacterClasses ++ invert posixCharacterClasses	where+						posixCharacterClasses :: AssociationList String+						posixCharacterClasses	= [+							("alnum",	Data.Char.isAlphaNum),+							("alpha",	Data.Char.isAlpha),+							("ascii",	Data.Char.isAscii),+							("blank",	(`elem` " \t")),+							("cntrl",	Data.Char.isControl),+							("digit",	Data.Char.isDigit),+							("graph",	\c	-> not $ ($ c) `any` [Data.Char.isSpace, Data.Char.isControl]),+							("lower",	Data.Char.isLower),+							("print",	Data.Char.isPrint),+							("punct",	Data.Char.isPunctuation),+							("space",	Data.Char.isSpace),+							("upper",	Data.Char.isUpper),+							("word",	\c	-> ($ c) `any` [Data.Char.isAlphaNum, (== '_')]),+							("xdigit",	Data.Char.isHexDigit)+						 ]++						invert :: AssociationList String -> AssociationList String+						invert	= map $ (RegExDot.BracketExpression.negationToken :) *** (not .)++			cTor	<- Parsec.option RegExDot.Meta.AnyOf {-default-} $ (Parsec.char RegExDot.BracketExpression.negationToken <?> "RegExDot.BracketExpression.negationToken " ++ show RegExDot.BracketExpression.negationToken) >> return {-to ParsecT-monad-} RegExDot.Meta.NoneOf++			literalBracketExpressionTerminator	<- Parsec.option [] {-default-} $ return {-to List-monad-} . RegExDot.BracketExpressionMember.Literal <$> (+				Parsec.char (snd RegExDot.BracketExpression.delimiterTokens)	<?> "Literal Bracket-expression terminator " ++ show (snd RegExDot.BracketExpression.delimiterTokens)+			 ) -- If the first item in a BracketExpression (or negated BracketExpression) is the terminator-token, then it is treated as a 'RegExDot.BracketExpressionMember.Literal'.++			cTor . (literalBracketExpressionTerminator ++) <$> Parsec.many {-potentially zero-} (+				Parsec.choice [+					(+						do+							_	<- Parsec.char RegExDot.Meta.shortcutToken	<?> "RegExDot.Meta.shortcutToken " ++ show RegExDot.Meta.shortcutToken+							c	<- Parsec.anyChar++							return {-to ParsecT-monad-} $ case RegExDot.BracketExpressionMember.findPredicate c of+								Just showablePredicate	-> RegExDot.BracketExpressionMember.Predicate showablePredicate+								_			-> RegExDot.BracketExpressionMember.Literal c	-- Escaped literal.+					) <?> "Perl-style shortcut",+					Parsec.try (+						uncurry Parsec.between (ToolShed.Data.Pair.mirror Parsec.string posixCharacterClassDelimiters) (+							do+								identifier	<- Parsec.many1 $ Parsec.noneOf [head $ snd posixCharacterClassDelimiters]++								case implementPosixCharacterClass identifier of+									Just showablePredicate	-> return {-to ParsecT-monad-} $ RegExDot.BracketExpressionMember.Predicate showablePredicate+									_			-> Parsec.unexpected $ "MetaChar.metaCharParser:\tunrecognised Posix Character-class; " ++ show identifier+						) <?> "Posix Character-class " ++ show posixCharacterClassDelimiters+					), -- Regurgitate erroneously consumed input.+					Parsec.try (+						(+							do+								rangeStart	<- Parsec.noneOf [snd RegExDot.BracketExpression.delimiterTokens]+								_		<- Parsec.char bracketExpressionRangeToken	<?> "bracketExpressionRangeToken " ++ show bracketExpressionRangeToken+								rangeEnd	<- Parsec.noneOf [snd RegExDot.BracketExpression.delimiterTokens]++								return {-to ParsecT-monad-} . RegExDot.BracketExpressionMember.Predicate . RegExDot.ShowablePredicate.MkShowablePredicate [+									rangeStart,+									bracketExpressionRangeToken,+									rangeEnd+								 ] $ \c -> rangeStart <= c && c <= rangeEnd	-- Create custom predicate, utilising "Ord Char".+						) <?> "Bracket-expression range"+					), -- Regurgitate erroneously consumed input.+					RegExDot.BracketExpressionMember.Literal <$> Parsec.noneOf [snd RegExDot.BracketExpression.delimiterTokens]	<?> "RegExDot.BracketExpressionMember.Literal"	-- TODO: the first Char-member can be a literal ']'.+				] <?> "Bracket-expression member"+			 ) <?> "Bracket-expression member-list"+	) <?> "RegExDot.BracketExpression.delimiterTokens " ++ show RegExDot.BracketExpression.delimiterTokens,+	RegExDot.Meta.Literal <$> Parsec.noneOf RegExDot.RegEx.tokens+ ]++instance Read MetaChar	where+	readsPrec _	= (+		(fail . ("readsPrec RegExChar.MetaChar:\tparse-error; " ++) . show) `either` return+	 ) . Parsec.parse (+		(,) <$> metaCharParser <*> Parsec.getInput+	 ) "MetaChar"++-- | The token used to signify an ordered range of members in a /Bracket-expression/.+bracketExpressionRangeToken :: Char+bracketExpressionRangeToken	= '-'++-- | The delimiters of a /Posix Character-class/.+posixCharacterClassDelimiters :: (String, String)+posixCharacterClassDelimiters	= ("[:", ":]")++instance Show MetaChar	where+	showsPrec _ (MkMetaChar RegExDot.Meta.Any)				= showChar RegExDot.Meta.anyToken+	showsPrec _ (MkMetaChar (RegExDot.Meta.Literal c))			= (+		if c `elem` [+			fst RegExDot.BracketExpression.delimiterTokens,+			fst RegExDot.Repeatable.rangeDelimiters,+			RegExDot.Repeatable.oneOrMoreToken,+			RegExDot.Repeatable.zeroOrMoreToken,+			RegExDot.Repeatable.zeroOrOneToken,+			RegExDot.Meta.anyToken,+			RegExDot.Meta.shortcutToken+		] ++ RegExDot.RegEx.tokens+			then showChar RegExDot.Meta.shortcutToken+			else id+	 ) . showChar c+	showsPrec _ (MkMetaChar (RegExDot.Meta.AnyOf bracketExpression))	= showChar (+		fst RegExDot.BracketExpression.delimiterTokens+	 ) . showString (+		foldr (+			\e	-> case e of+				RegExDot.BracketExpressionMember.Predicate showablePredicate	-> shows showablePredicate+				RegExDot.BracketExpressionMember.Literal literal		-> (+					if literal `elem` [+						bracketExpressionRangeToken,		-- CAVEAT: only unambiguously literal when at the start or end of a "BracketExpression".+						RegExDot.Meta.shortcutToken,+						snd RegExDot.BracketExpression.delimiterTokens	-- CAVEAT: only unambiguously literal when at the start of a "BracketExpression".+					]+						then showChar RegExDot.Meta.shortcutToken+						else id+				 ) . showChar literal+		) (+			showChar (snd RegExDot.BracketExpression.delimiterTokens) ""	-- Initial value.+		) bracketExpression+	 )+	showsPrec _ (MkMetaChar (RegExDot.Meta.NoneOf bracketExpression))	= showChar x . showChar RegExDot.BracketExpression.negationToken . showString xs	where (x : xs)	= show . MkMetaChar $ RegExDot.Meta.AnyOf bracketExpression+	showsPrec _ (MkMetaChar m)						= shows m+
+ src-lib/RegExChar/RegExOptsChar.hs view
@@ -0,0 +1,219 @@+{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances, FlexibleContexts #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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@]	Creates a /back-end/ implementation, conforming to <http://hackage.haskell.org/packages/archive/regex-base/latest/doc/html/Text-Regex-Base-RegexLike.html>.++ [@CAVEATS@]++	* The underlying polymorphic (in terms of the base-type of the list of input data) 'RegExDot.RegEx.ExtendedRegEx'-engine is never going to be a drop-in replacement for other /regex/-engines,+	so this standard interface has only been implemented for traditional input data-type ['Char'].++	* The standard interface requires many Haskell-extensions, but since this implementation is just a thin layer over the underlying portable polymorphic 'RegExDot.RegEx.ExtendedRegEx'-engine,+	the latter can still be used directly, where any of these extensions are unavailable.+-}++module RegExChar.RegExOptsChar(+-- * Types+-- ** Type-synonyms+	MatchSpan,+--	MatchDataSpan,+	RegExOptsChar,+-- * Functions+--	exciseNonCapturingTopLevelAlternatives,+--	matchUntilFailure,+--	toMatchDataSpanList,+	toZeroIndexedArray,+-- ** Operators+	(=~)+-- ** Predicates+--	complyStrictlyWithPosix,+--	hasNonCapturingTopLevelAlternatives+) where++import qualified	Data.Array.IArray+import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar+import qualified	RegExDot.CompilationOptions+import qualified	RegExDot.ConsumptionBounds+import qualified	RegExDot.DataSpan+import qualified	RegExDot.DataSpanTree+import qualified	RegExDot.ExecutionOptions+import qualified	RegExDot.RegEx+import qualified	RegExDot.RegExOpts+import qualified	RegExDot.Result+import qualified	RegExDot.Tree+import qualified	Text.Regex.Base.RegexLike	as RegexLike+import			Text.Regex.Base.Context()	-- Instance-declarations.+import qualified	ToolShed.Data.List+import qualified	ToolShed.Defaultable+import qualified	ToolShed.Options++infix 4 =~	-- Same as (==).++-- | Defines a specific instance of the polymorphic base-type.+type RegExOptsChar	= RegExDot.RegExOpts.RegExOpts ExtendedRegExChar.ExtendedRegExChar++-- | Convenience accessor-function.+hasNonCapturingTopLevelAlternatives :: RegExOptsChar -> Bool+hasNonCapturingTopLevelAlternatives	= ExtendedRegExChar.hasNonCapturingTopLevelAlternatives . RegExDot.RegExOpts.regEx++-- | Convenience accessor-function.+complyStrictlyWithPosix :: RegExOptsChar -> Bool+complyStrictlyWithPosix	= RegExDot.CompilationOptions.complyStrictlyWithPosix . RegExDot.RegExOpts.compilationOptions++instance RegexLike.RegexOptions RegExOptsChar RegExDot.CompilationOptions.CompilationOptions RegExDot.ExecutionOptions.ExecutionOptions	where+	blankCompOpt	= ToolShed.Options.blankValue+	blankExecOpt	= ToolShed.Options.blankValue+	defaultCompOpt	= ToolShed.Defaultable.defaultValue+	defaultExecOpt	= ToolShed.Defaultable.defaultValue+	setExecOpts e r	= r { RegExDot.RegExOpts.executionOptions = e }+	getExecOpts	= RegExDot.RegExOpts.executionOptions++-- Newer versions of this 'Text.Regex.Base.RegexLike.RegexMaker' have additional monadic methods, which can fail on parse-errors.+instance RegexLike.RegexMaker RegExOptsChar RegExDot.CompilationOptions.CompilationOptions RegExDot.ExecutionOptions.ExecutionOptions String	where+	makeRegexOpts c e source = RegExDot.RegExOpts.MkRegExOpts {+		RegExDot.RegExOpts.compilationOptions	= c,+		RegExDot.RegExOpts.executionOptions	= e,+		RegExDot.RegExOpts.regEx		= read source+	}++-- | The offset and length of the 'RegExDot.RegEx.InputData' consumed in one 'RegExDot.RegEx.Match'.+type MatchSpan		= (RegexLike.MatchOffset, RegexLike.MatchLength)++{- |+	* The 'MatchSpan' augmented by the consumed 'ExtendedRegExChar.InputData' to which it refers.++	* Similar to 'RegExDot.DataSpan.DataSpan'.+-}+type MatchDataSpan	= (ExtendedRegExChar.InputData, MatchSpan)++{- |+	* Convert the 'RegExDot.RegEx.MatchList', into the 'MatchDataSpan's required by "Text.Regex.Base.RegexLike".++	* Treat the whole 'ExtendedRegExChar.ExtendedRegExChar' as an additional implicit capture-group.++	* CAVEAT: @RegExDot.DataSpanTree.extractCaptureGroups True@ may return some 'RegExDot.DataSpan.DataSpan's containing the artificial offset @-1@ specified by Posix => don't use this as the basis for any arithmetic.+-}+toMatchDataSpanList+	:: Bool+	-> RegExDot.ConsumptionBounds.DataLength	-- ^ The offset to use for zero-length match.+	-> RegExDot.RegEx.MatchList Char		-- ^ The list of matches.+	-> [MatchDataSpan]+toMatchDataSpanList _ offset []				= [RegExDot.DataSpan.empty offset]	-- The whole regex matched, but consumed nothing.+toMatchDataSpanList strictPosixCompliance _ matchList	= RegExDot.DataSpanTree.extractCaptureGroups strictPosixCompliance . return {-to List-monad-} . RegExDot.Tree.Node . return {-to List-monad-} $ RegExDot.DataSpanTree.toTreeList matchList++-- | Optionally remove the 2nd element from the list, where it represents the data captured by a groups of top-level 'Alternatives', which weren't explicitly delimited & therefore are non-capturing.+exciseNonCapturingTopLevelAlternatives :: RegExOptsChar -> [MatchDataSpan] -> [MatchDataSpan]+exciseNonCapturingTopLevelAlternatives regExOptsChar+	| hasNonCapturingTopLevelAlternatives regExOptsChar	= ToolShed.Data.List.excise 1	-- The zeroeth represents the whole regex, the 1st represents the top-level non-capturing group of Alternatives, & the remainder represent explicitly delimited groups.+	| otherwise						= id++-- | Convert the specified list, into a zero-indexed array.+toZeroIndexedArray :: [e] -> Data.Array.IArray.Array Int e+toZeroIndexedArray l	= Data.Array.IArray.listArray (0, pred $ length l) l++{- |+	* Repeatedly apply the 'RegExOptsChar' to the 'ExtendedRegExChar.InputData', forwarding unmatched input data to the next match-attempt, until it's all been consumed.++	* The offsets, from the start of the input data, of all matches after the first, are shifted to account for input data already consumed by previous matches.+-}+matchUntilFailure+	:: RegExOptsChar		-- ^ The match-criteria.+	-> ExtendedRegExChar.InputData	-- ^ The input-data, to be consumed by repeated matching.+	-> [RegExDot.RegEx.MatchList Char]+matchUntilFailure regExOptsChar inputData	= shiftOffsets 0 $ matchUntilFailure' inputData	where+	matchUntilFailure' :: ExtendedRegExChar.InputData -> [RegExDot.RegEx.MatchList Char]+	matchUntilFailure' unmatchedInputData	= case unmatchedInputData ExtendedRegExChar.+~ regExOptsChar of	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+		(_, Just matchList, maybeSternAnchorResult)	-> matchList : if null (RegExDot.RegEx.extractDataFromMatchList matchList) then [] else matchUntilFailure' (RegExDot.RegEx.extractDataFromMatch' maybeSternAnchorResult)+		_						-> []++	shiftOffsets :: RegExDot.ConsumptionBounds.DataLength -> [RegExDot.RegEx.MatchList Char] -> [RegExDot.RegEx.MatchList Char]+	shiftOffsets offset (matchList : matchLists)	= let+		shiftedMatchList :: RegExDot.RegEx.MatchList Char+		shiftedMatchList	= RegExDot.RegEx.shiftMatchList offset matchList+	 in shiftedMatchList : shiftOffsets (RegExDot.DataSpan.after . last . RegExDot.DataSpanTree.flattenTreeList 0 $ RegExDot.DataSpanTree.toTreeList shiftedMatchList) matchLists {-recurse-}+	shiftOffsets _ _				= []++instance RegexLike.RegexLike RegExOptsChar ExtendedRegExChar.InputData	where+{- E.g.:+	("xabcdxabdxxadx" RegExOptsChar.=~ "a(b(c?))*d") :: [Text.Regex.Base.RegexLike.MatchArray]+	[array (0,2) [(0,(1,4)),(1,(2,2)),(2,(3,1))],array (0,2) [(0,(6,3)),(1,(7,1)),(2,(8,0))],array (0,1) [(0,(11,2)),(1,(-1,0))]]+-}+--	matchAll :: RegExOptsChar -> ExtendedRegExChar.InputData -> [RegexLike.MatchArray]+	matchAll regExOptsChar	= map (toZeroIndexedArray . map snd {-span-} . exciseNonCapturingTopLevelAlternatives regExOptsChar . toMatchDataSpanList (complyStrictlyWithPosix regExOptsChar) 0) . matchUntilFailure regExOptsChar++{- E.g.:+	("xabcdxabdxxadx" RegExOptsChar.=~ "a(b(c?))*d") :: [Text.Regex.Base.RegexLike.MatchText String]+	[array (0,2) [(0,("abcd",(1,4))),(1,("bc",(2,2))),(2,("c",(3,1)))],array (0,2) [(0,("abd",(6,3))),(1,("b",(7,1))),(2,("",(8,0)))],array (0,1) [(0,("ad",(11,2))),(1,("",(-1,0)))]]+-}+--	matchAllText :: RegExOptsChar -> ExtendedRegExChar.InputData -> [RegexLike.MatchText ExtendedRegExChar.InputData]+	matchAllText regExOptsChar	= map (toZeroIndexedArray . exciseNonCapturingTopLevelAlternatives regExOptsChar . toMatchDataSpanList (complyStrictlyWithPosix regExOptsChar) 0) . matchUntilFailure regExOptsChar++{- E.g.:+	("xabcdx" RegExOptsChar.=~ "a(b(c?))*d") :: Text.Regex.Base.RegexLike.MatchArray+	array (0,2) [(0,(1,4)),(1,(2,2)),(2,(3,1))]+-}+--	matchOnce :: RegExOptsChar -> ExtendedRegExChar.InputData -> Maybe RegexLike.MatchArray+	matchOnce regExOptsChar inputData	= (+		toZeroIndexedArray . map snd {-span-} . exciseNonCapturingTopLevelAlternatives regExOptsChar . toMatchDataSpanList (+			complyStrictlyWithPosix regExOptsChar+		) (+			RegExDot.RegEx.externalMatchLength $ RegExDot.Result.getPreMatch extendedRegExResult+		)+	 ) `fmap` RegExDot.Result.getMatchList extendedRegExResult	where+		extendedRegExResult :: RegExDot.RegEx.Result Char+		extendedRegExResult	= inputData ExtendedRegExChar.+~ regExOptsChar	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.++{- E.g.:+	("xabcdx" RegExOptsChar.=~ "a(b(c?))*d") :: (String, Text.Regex.Base.RegexLike.MatchText String, String)+	("x",array (0,2) [(0,("abcd",(1,4))),(1,("bc",(2,2))),(2,("c",(3,1)))],"x")+-}+--	matchOnceText :: RegExOptsChar -> ExtendedRegExChar.InputData -> Maybe (ExtendedRegExChar.InputData, MatchText ExtendedRegExChar.InputData, ExtendedRegExChar.InputData)+	matchOnceText regExOptsChar inputData	= case inputData ExtendedRegExChar.+~ regExOptsChar of	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.+		(maybeBowAnchorResult, Just matchList, maybeSternAnchorResult)	-> Just (+			RegExDot.RegEx.extractDataFromMatch' maybeBowAnchorResult,+			toZeroIndexedArray . exciseNonCapturingTopLevelAlternatives regExOptsChar $ toMatchDataSpanList (+				complyStrictlyWithPosix regExOptsChar+			) (+				RegExDot.RegEx.externalMatchLength maybeBowAnchorResult+			) matchList,+			RegExDot.RegEx.extractDataFromMatch' maybeSternAnchorResult+		 )+		_								-> Nothing++{- E.g.:+	("xabcdx" RegExOptsChar.=~ "a(b(c?))*d") :: Bool+	True+-}+--	matchTest :: RegExOptsChar -> ExtendedRegExChar.InputData -> Bool+	matchTest	= flip (ExtendedRegExChar.=~)	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.++{- |+	* Match-operator.++	* The polymorphic return-type is resolved by the caller's "RegexLike.RegexContext".+-}+(=~) :: RegexLike.RegexContext RegExOptsChar ExtendedRegExChar.InputData target+	=> ExtendedRegExChar.InputData	-- ^ The input data.+	-> String			-- ^ The string from which to read the regex-specification.+	-> target			-- ^ The polymorphic return-type.+inputData =~ s	= (RegexLike.makeRegex s :: RegExOptsChar) `RegexLike.match` inputData+
+ src-test/Grecce/Test/QC/ExtendedRegExChar.hs view
@@ -0,0 +1,192 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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(+-- * Constants+	results,+-- * Types+-- ** Data-types+--	AlternativesChar(..),+--	PatternChar(..),+--	RepeatablePatternChar(..),+-- * Functions+-- ** Accessors+--	deconstructAlternativesChar,+--	deconstructPatternChar,+--	deconstructRepeatablePatternChar+) where++import qualified	Data.Maybe+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+import qualified	RegExDot.BracketExpressionMember+import qualified	RegExDot.Consumer+import qualified	RegExDot.ConsumptionBounds+import qualified	RegExDot.ConsumptionProfile+import			RegExDot.DSL((-:), (?:), (+:), (<~>))+import qualified	RegExDot.Meta+import qualified	RegExDot.RegEx+import			RegExDot.RegEx((+~))+import qualified	RegExDot.RegExOpts+import qualified	RegExDot.Repeatable+import qualified	RegExDot.Result+import qualified	Test.QuickCheck+import			Test.QuickCheck((==>))+import qualified	ToolShed.SelfValidate+import qualified	ToolShed.Test.ReversibleIO++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype AlternativesChar	= MkAlternativesChar (RegExDot.RegEx.Alternatives Char) deriving (Eq, Read, Show)++-- | Accessor.+deconstructAlternativesChar :: AlternativesChar -> RegExDot.RegEx.Alternatives Char+deconstructAlternativesChar (MkAlternativesChar a)	= a++instance ToolShed.SelfValidate.SelfValidator AlternativesChar where+	getErrors	= ToolShed.SelfValidate.getErrors . deconstructAlternativesChar++instance RegExDot.Consumer.Consumer AlternativesChar where+	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstructAlternativesChar+	starHeight		= RegExDot.Consumer.starHeight . deconstructAlternativesChar++instance Test.QuickCheck.Arbitrary AlternativesChar	where+	arbitrary	= (MkAlternativesChar . RegExDot.RegEx.MkAlternatives . map ExtendedRegExChar.extendedRegEx) `fmap` (+		Test.QuickCheck.elements [1, 2]	>>= Test.QuickCheck.vector {-[ExtendedRegExChar]-}+	 ) -- TODO: permit zero alternatives.++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype PatternChar	= MkPatternChar (RegExDot.RegEx.Pattern Char) deriving (Eq, Read, Show)++-- | Accessor.+deconstructPatternChar :: PatternChar -> RegExDot.RegEx.Pattern Char+deconstructPatternChar (MkPatternChar pattern)	= pattern++instance ToolShed.SelfValidate.SelfValidator PatternChar	where+	getErrors	= ToolShed.SelfValidate.getErrors . deconstructPatternChar++instance RegExDot.Consumer.Consumer PatternChar	where+	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstructPatternChar+	starHeight		= RegExDot.Consumer.starHeight . deconstructPatternChar++instance Test.QuickCheck.Arbitrary PatternChar	where+	arbitrary	= MkPatternChar `fmap` Test.QuickCheck.frequency [+		(4,	(RegExDot.RegEx.Require . MetaChar.deconstruct) `fmap` Test.QuickCheck.arbitrary {-MetaChar-}),+		(1,	(RegExDot.RegEx.CaptureGroup . deconstructAlternativesChar) `fmap` Test.QuickCheck.arbitrary {-AlternativesChar-})+	 ] -- CAVEAT: may recurse forever if 'RegExDot.RegEx.CaptureGroup / RegExDot.RegEx.Require' is too high.++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype RepeatablePatternChar	= MkRepeatablePatternChar (RegExDot.Repeatable.Repeatable PatternChar)	deriving (Eq, Read, Show)++-- | Accessor.+deconstructRepeatablePatternChar :: RepeatablePatternChar -> RegExDot.Repeatable.Repeatable PatternChar+deconstructRepeatablePatternChar (MkRepeatablePatternChar repeatable)	= repeatable++instance ToolShed.SelfValidate.SelfValidator RepeatablePatternChar	where+	getErrors	= ToolShed.SelfValidate.getErrors . deconstructRepeatablePatternChar++instance RegExDot.Consumer.Consumer RepeatablePatternChar	where+	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstructRepeatablePatternChar+	starHeight		= RegExDot.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 `fmap` Test.QuickCheck.elements [max fewest 1 .. 9]]+		isGreedy	<- Test.QuickCheck.arbitrary {-Bool-}++		let+			repetitionBounds :: RegExDot.Repeatable.RepetitionBounds+			repetitionBounds	= (fewest, most)++		return {-to Gen-monad-} $ MkRepeatablePatternChar RegExDot.Repeatable.MkRepeatable {+			RegExDot.Repeatable.base		= patternChar,+			RegExDot.Repeatable.repetitionBounds	= repetitionBounds,+			RegExDot.Repeatable.isGreedy		= RegExDot.Repeatable.hasPreciseBounds repetitionBounds || isGreedy	-- Only specify non-greedy where space exists.+		}++instance Test.QuickCheck.Arbitrary ExtendedRegExChar.ExtendedRegExChar	where+	arbitrary	= do+		hasBowAnchor	<- Test.QuickCheck.arbitrary {-Bool-}+		concatenation	<- map (fmap deconstructPatternChar {-replace base-} . deconstructRepeatablePatternChar {-RegExDot.Repeatable.Repeatable PatternChar-}) `fmap` Test.QuickCheck.vector 2 {-[RepeatablePatternChar]-}+		hasSternAnchor	<- Test.QuickCheck.arbitrary {-Bool-}++		return {-to Gen-monad-} $ ExtendedRegExChar.MkExtendedRegExChar False RegExDot.RegEx.MkExtendedRegEx {+			RegExDot.RegEx.bowAnchor	= if hasBowAnchor then Just RegExDot.Anchor.Bow else Nothing,+			RegExDot.RegEx.concatenation	= concatenation,+			RegExDot.RegEx.sternAnchor	= if hasSternAnchor then Just RegExDot.Anchor.Stern else Nothing+		}++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results	= sequence [+	Test.QuickCheck.quickCheckResult prop_consumptionProfile,+	Test.QuickCheck.quickCheckResult prop_consumptionProfile2,+	Test.QuickCheck.quickCheckResult prop_io,+	Test.QuickCheck.quickCheckResult prop_io',+	Test.QuickCheck.quickCheckResult prop_isValid,+	Test.QuickCheck.quickCheckResult prop_starHeight,+	Test.QuickCheck.quickCheckResult prop_double+ ] where+		prop_consumptionProfile, prop_consumptionProfile2, prop_io, prop_io', prop_isValid, prop_starHeight :: ExtendedRegExChar.ExtendedRegExChar -> Test.QuickCheck.Property+		prop_consumptionProfile r	= Test.QuickCheck.label "prop_consumptionProfile" $ Data.Maybe.maybe True (>= minData) maybeMaxData && (+			not b == all (not . RegExDot.Consumer.getHasSpecificRequirement) (RegExDot.RegEx.concatenation $ ExtendedRegExChar.extendedRegEx r)+		 )+			where+				RegExDot.ConsumptionProfile.MkConsumptionProfile {+					RegExDot.ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),+					RegExDot.ConsumptionProfile.hasSpecificRequirement	= b+				} = RegExDot.Consumer.consumptionProfile r++		prop_consumptionProfile2 r	= RegExDot.RegEx.isDefined (ExtendedRegExChar.extendedRegEx r)	==> Test.QuickCheck.label "prop_consumptionProfile2" $ hasSpecificRequirement || canConsumeAnything	-- There's either; a requirement for at least one specific, or we can consume at least one arbitrary; input datum.+			where+				RegExDot.ConsumptionProfile.MkConsumptionProfile {+					RegExDot.ConsumptionProfile.hasSpecificRequirement	= hasSpecificRequirement,+					RegExDot.ConsumptionProfile.canConsumeAnything		= canConsumeAnything+				} = RegExDot.Consumer.consumptionProfile r++		prop_io			= Test.QuickCheck.label "prop_io" . ToolShed.Test.ReversibleIO.isReversible+		prop_io' r		= Test.QuickCheck.label "prop_io'" $ ToolShed.Test.ReversibleIO.isReversible r'	where r' = ExtendedRegExChar.extendedRegEx r	-- Check "RegExDot.RegEx.ExtendedRegEx Char" too.+		prop_isValid r		= Test.QuickCheck.label "prop_isValid" $ ToolShed.SelfValidate.isValid r+		prop_starHeight r	= Test.QuickCheck.label "prop_starHeight" $ (RegExDot.Consumer.starHeight r == 0) == RegExDot.ConsumptionBounds.isPrecise (RegExDot.Consumer.getConsumptionBounds r)++		prop_double :: Double -> Test.QuickCheck.Property+		prop_double d	= Test.QuickCheck.label "prop_double" $ RegExDot.RegEx.extractDataFromMatchList `fmap` RegExDot.Result.getMatchList result == Just s	where+			s :: String+			s	= show $ d * 1e6	-- Implementation of show, uses exponential notation, when the number is large.++			result :: RegExDot.RegEx.Result Char+			result = s +~ RegExDot.RegExOpts.mkRegEx (+				(Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~> sign ?: digits +: map (+					RegExDot.Repeatable.zeroOrOne . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-}+				) [+					RegExDot.RegEx.Require (RegExDot.Meta.Literal '.') -: digits +: [],+					RegExDot.RegEx.Require (RegExDot.Meta.AnyOf $ map RegExDot.BracketExpressionMember.Literal "eE") -: sign ?: digits +: []+				]+			 ) where+				sign, digits :: RegExDot.RegEx.Pattern Char+				sign	= RegExDot.RegEx.Require . RegExDot.Meta.AnyOf $ map RegExDot.BracketExpressionMember.Literal "+-"+				digits	= RegExDot.RegEx.Require . RegExDot.Meta.AnyOf $ map RegExDot.BracketExpressionMember.Literal ['0' .. '9']+
+ src-test/Grecce/Test/QC/MetaChar.hs view
@@ -0,0 +1,66 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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(+-- * Constants+	results,+--	testCharacters,+-- * Types+-- ** Type-synonyms+--	Testable+) where++import qualified	Data.List+import qualified	RegExChar.MetaChar	as MetaChar	-- CAVEAT: beware of the similar name.+import qualified	RegExDot.BracketExpression+import qualified	RegExDot.BracketExpressionMember+import qualified	RegExDot.Meta+import qualified	Test.QuickCheck+import qualified	ToolShed.Test.ReversibleIO++testCharacters :: String+testCharacters	= filter (`notElem` [RegExDot.Meta.shortcutToken, RegExDot.BracketExpression.negationToken]) [' ' .. '~']	-- TODO: permit all characters.++instance Test.QuickCheck.Arbitrary MetaChar.MetaChar	where+	arbitrary	= Test.QuickCheck.oneof $ map (fmap MetaChar.MkMetaChar) [+		return {-to Gen-monad-} RegExDot.Meta.Any,+		RegExDot.Meta.Literal `fmap` Test.QuickCheck.elements testCharacters,+		(RegExDot.Meta.AnyOf . map RegExDot.BracketExpressionMember.Literal . Data.List.nub) `fmap` arbitraryCharList 1 16,	-- Test.QuickCheck.vector 16 {-Char-},+		(RegExDot.Meta.NoneOf . map RegExDot.BracketExpressionMember.Literal . Data.List.nub) `fmap` 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)) `fmap` Test.QuickCheck.vector maxBound {-Char-}++type Testable	= MetaChar.MetaChar -> Test.QuickCheck.Property++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = mapM Test.QuickCheck.quickCheckResult [prop_io]	where+	prop_io :: Testable+	prop_io	= Test.QuickCheck.label "prop_io" . ToolShed.Test.ReversibleIO.isReversible+
+ src-test/Grecce/Test/QC/RepeatableMetaChar.hs view
@@ -0,0 +1,92 @@+{-+	Copyright (C) 2010-2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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(+-- * Constants+	results,+-- * Types+-- ** Data-types+--	RepeatableMetaChar,+-- ** Type-synonyms+--	Testable,+-- * Functions+--	deconstruct+) where++import qualified	Data.Maybe+import			Grecce.Test.QC.MetaChar()+import qualified	RegExChar.MetaChar	as MetaChar+import qualified	RegExDot.Consumer+import qualified	RegExDot.ConsumptionBounds+import qualified	RegExDot.ConsumptionProfile+import qualified	RegExDot.Repeatable+import qualified	Test.QuickCheck+import qualified	ToolShed.SelfValidate+import qualified	ToolShed.Test.ReversibleIO++-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.+newtype RepeatableMetaChar	= MkRepeatableMetaChar (RegExDot.Repeatable.Repeatable MetaChar.MetaChar)	deriving (Eq, Read, Show)++-- | Accessor.+deconstruct :: RepeatableMetaChar -> RegExDot.Repeatable.Repeatable MetaChar.MetaChar+deconstruct (MkRepeatableMetaChar repeatableMetaChar)	= repeatableMetaChar++instance ToolShed.SelfValidate.SelfValidator RepeatableMetaChar	where+	getErrors	= ToolShed.SelfValidate.getErrors . deconstruct++instance RegExDot.Consumer.Consumer RepeatableMetaChar	where+	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstruct+	starHeight		= RegExDot.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 `fmap` Test.QuickCheck.elements [max fewest 1 .. 9]]+		isGreedy	<- Test.QuickCheck.arbitrary++		let+			repetitionBounds :: RegExDot.Repeatable.RepetitionBounds+			repetitionBounds	= (fewest, most)++		return {-to Gen-monad-} . MkRepeatableMetaChar $ RegExDot.Repeatable.MkRepeatable {+			RegExDot.Repeatable.base		= metaChar,+			RegExDot.Repeatable.repetitionBounds	= repetitionBounds,+			RegExDot.Repeatable.isGreedy		= RegExDot.Repeatable.hasPreciseBounds repetitionBounds || isGreedy	-- Only specify 'non-greedy' where space exists.+		}++type Testable	= RepeatableMetaChar -> Test.QuickCheck.Property++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results	= mapM Test.QuickCheck.quickCheckResult [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" $ Data.Maybe.maybe True (>= minData) maybeMaxData && b == RegExDot.Consumer.getHasSpecificRequirement (RegExDot.Repeatable.base $ deconstruct r)	where+		RegExDot.ConsumptionProfile.MkConsumptionProfile {+			RegExDot.ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),+			RegExDot.ConsumptionProfile.hasSpecificRequirement	= b+		} = RegExDot.Consumer.consumptionProfile r++	prop_io (MkRepeatableMetaChar r)		= Test.QuickCheck.label "prop_io" $ ToolShed.Test.ReversibleIO.isReversible r+	prop_isValid r					= Test.QuickCheck.label "prop_isValid" $ ToolShed.SelfValidate.isValid r+	prop_starHeight (MkRepeatableMetaChar r)	= Test.QuickCheck.label "prop_starHeight" $ RegExDot.Consumer.starHeight r == if RegExDot.ConsumptionBounds.isPrecise (RegExDot.Consumer.getConsumptionBounds r) then 0 else 1+
+ src-test/Main.hs view
@@ -0,0 +1,46 @@+{-+	Copyright (C) 2015 Dr. Alistair Ward++	This program is free software: you can redistribute it and/or modify+	it under the terms of the GNU General Public License as published by+	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 Main(main) where++import			Control.Arrow((***))+import qualified	Control.Monad+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	System.Exit+import qualified	ToolShed.Test.QuickCheck.Result++-- | Entry-point.+main :: IO ()+main	= mapM_ (+	snd {-exit-status-} . (+		putStrLn . (++ ":") *** (+			>>= (`Control.Monad.unless` System.Exit.exitFailure) . all ToolShed.Test.QuickCheck.Result.isSuccessful+		)+	)+ ) [+	("MetaChar",		Test.QC.MetaChar.results),+	("RepeatableMetaChar",	Test.QC.RepeatableMetaChar.results),+	("ExtendedRegExChar",	Test.QC.ExtendedRegExChar.results)+ ]+
− src/Grecce/CommandOptions.hs
@@ -1,172 +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 options, read from the command-line,-	& as such assumes that the type-parameter of the underlying polymorphic /regex/-engine is 'Char'.--	* Supplies mutators, which ensure the consistency of the chosen set.--}--module Grecce.CommandOptions(--- * Types--- ** Type-synonyms-	CompilationOptionsMutator,-	ExecutionOptionsMutator,---	Transformer,--- ** Data-types-	CommandOptions(..),--- * Functions--- ** Mutators-	setCompilationOption,-	setCountMatches,-	setExecutionOption,-	setInvertMatch,-	setPrependLineNumbers,-	setListFilesWithMatches,-	setListFilesWithoutMatch,-	setVerbose-) where--import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar-import qualified	RegExDot.CompilationOptions-import qualified	RegExDot.ExecutionOptions-import qualified	ToolShed.Defaultable-import qualified	ToolShed.Options---- | The set of command-line options; based on those provided by /egrep/.-data CommandOptions	= MkCommandOptions {-	countMatches		:: Bool,						-- ^ Print only a count of matching lines per file.-	extendedRegExChar	:: Maybe ExtendedRegExChar.ExtendedRegExChar,		-- ^ The /regex/.-	invertMatch		:: Bool,						-- ^ Select non-matching lines.-	prependLineNumbers	:: Bool,						-- ^ Prepend the line-number of the matched input-data, to the output.-	listFilesWithMatches	:: Bool,						-- ^ List the names of any files containing at least one match.-	listFilesWithoutMatch	:: Bool,						-- ^ List the names of any files containing zero matches.-	verbose			:: Bool,						-- ^ Show the captured data.-	compilationOptions	:: RegExDot.CompilationOptions.CompilationOptions,	-- ^ Used to define the regex-request.-	executionOptions	:: RegExDot.ExecutionOptions.ExecutionOptions		-- ^ Used to control the regex-runtime.-} deriving Show---- | An arbitrary function which transforms the supplied 'RegExDot.ExecutionOptions.ExecutionOptions'.-type Transformer	= CommandOptions -> CommandOptions--instance ToolShed.Defaultable.Defaultable CommandOptions	where-	defaultValue	= ToolShed.Options.blankValue {-		countMatches		= False,-		extendedRegExChar	= Nothing,-		invertMatch		= False,-		prependLineNumbers	= False,-		listFilesWithMatches	= False,-		listFilesWithoutMatch	= False,-		verbose			= False,-		compilationOptions	= ToolShed.Defaultable.defaultValue,-		executionOptions	= ToolShed.Defaultable.defaultValue-	}--instance ToolShed.Options.Options CommandOptions	where-	blankValue	= MkCommandOptions {-		countMatches		= undefined,-		extendedRegExChar	= undefined,-		invertMatch		= undefined,-		prependLineNumbers	= undefined,-		listFilesWithMatches	= undefined,-		listFilesWithoutMatch	= undefined,-		verbose			= undefined,-		compilationOptions	= undefined,-		executionOptions	= undefined-	}---- | Mutator.-setCountMatches :: Transformer-setCountMatches commandOptions-	| ($ commandOptions) `any` [-		prependLineNumbers,-		listFilesWithoutMatch,-		listFilesWithMatches,-		verbose-	]		= error "Grecce.CommandOptions.setCountMatches:\t'countMatches' is incompatible with; 'prependLineNumbers', 'listFilesWithoutMatch', 'listFilesWithMatches' & 'verbose'."-	| otherwise	= commandOptions { countMatches = True }---- | Mutator.-setInvertMatch :: Transformer-setInvertMatch commandOptions-	| verbose commandOptions	= error "Grecce.CommandOptions.setInvertMatch:\t'invertMatch' is incompatible with 'verbose'."-	| otherwise			= commandOptions { invertMatch = True }---- | Mutator.-setPrependLineNumbers :: Transformer-setPrependLineNumbers commandOptions-	| ($ commandOptions) `any` [-		countMatches,-		listFilesWithoutMatch,-		listFilesWithMatches-	]		= error "Grecce.CommandOptions.setPrependLineNumbers:\t'prependLineNumbers' is incompatible with 'countMatches', 'listFilesWithoutMatch' & 'listFilesWithMatches'."-	| otherwise	= commandOptions { prependLineNumbers = True }---- | Mutator.-setListFilesWithMatches :: Transformer-setListFilesWithMatches commandOptions-	| ($ commandOptions) `any` [-		countMatches,-		prependLineNumbers,-		listFilesWithoutMatch,-		verbose-	]		= error "Grecce.CommandOptions.setListFilesWithMatches:\t'listFilesWithMatches' is incompatible with; 'countMatches', 'prependLineNumbers', 'listFilesWithoutMatch' & 'verbose'."-	| otherwise	= commandOptions { listFilesWithMatches = True }---- | Mutator.-setListFilesWithoutMatch :: Transformer-setListFilesWithoutMatch commandOptions-	| ($ commandOptions) `any` [-		countMatches,-		prependLineNumbers,-		listFilesWithMatches,-		verbose-	]		= error "Grecce.CommandOptions.setListFilesWithoutMatch:\t'listFilesWithoutMatch' is incompatible with; 'countMatches', 'prependLineNumbers', 'listFilesWithMatches' & 'verbose'."-	| otherwise	= commandOptions { listFilesWithoutMatch = True }---- | Mutator, which additionally sets the corresponding 'RegExDot.ExecutionOptions.ExecutionOptions'.-setVerbose :: Transformer-setVerbose commandOptions-	| ($ commandOptions) `any` [-		countMatches,-		invertMatch,-		listFilesWithoutMatch,-		listFilesWithMatches-	]		= error "Grecce.CommandOptions.setVerbose:\t'verbose' is incompatible with; 'countMatches', 'invertMatch', 'listFilesWithoutMatch' & 'listFilesWithMatches'."-	| otherwise	= commandOptions {-		verbose			= True,-		executionOptions	= RegExDot.ExecutionOptions.setVerbose True $ executionOptions commandOptions-	}---- | A function which accepts a 'String' & the 'RegExDot.CompilationOptions.CompilationOptions' to transform, using its value.-type CompilationOptionsMutator	= String -> RegExDot.CompilationOptions.CompilationOptions -> RegExDot.CompilationOptions.CompilationOptions---- | Generic mutator, which accepts a function & the parameter-string it requires, to amend an unspecified field of 'RegExDot.CompilationOptions.CompilationOptions'.-setCompilationOption :: CompilationOptionsMutator -> String -> Transformer-setCompilationOption compilationOptionsMutator s commandOptions	= commandOptions { compilationOptions = compilationOptionsMutator s $ compilationOptions commandOptions }---- | A function which accepts a 'String' & the 'RegExDot.ExecutionOptions.ExecutionOptions' to transform, using its value.-type ExecutionOptionsMutator	= String -> RegExDot.ExecutionOptions.ExecutionOptions -> RegExDot.ExecutionOptions.ExecutionOptions---- | Generic mutator, which accepts a function & the parameter-string it requires, to amend an unspecified field of 'RegExDot.ExecutionOptions.ExecutionOptions'.-setExecutionOption :: ExecutionOptionsMutator -> String -> Transformer-setExecutionOption executionOptionsMutator s commandOptions	= commandOptions { executionOptions = executionOptionsMutator s $ executionOptions commandOptions }-
− src/Grecce/Grep.hs
@@ -1,206 +0,0 @@-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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@]	Performs the match-operation on the specified file-list, using the user's command-line options.--}--module Grecce.Grep(--- * Types---	LineNumber,---	Matches,--- ** Type-synonyms--- * Functions-	grep-) where--import			Control.Arrow((&&&))-import qualified	Control.Arrow-import qualified	Control.Monad-import qualified	Control.Parallel.Strategies-import qualified	Data.List-import qualified	Grecce.CommandOptions		as CommandOptions-import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar-import			RegExChar.ExtendedRegExChar((+~), (=~))-import qualified	RegExDot.RegEx-import qualified	RegExDot.RegExOpts-import qualified	RegExDot.Result-import qualified	System.Exit-import qualified	System.IO--type LineNumber	= Int-type Matches	= Int---- | Creates a 'RegExDot.RegExOpts.RegExOpts' record from 'CommandOptions.CommandOptions', and uses it to filter the lines read from the list of input-data files, the result of which is then printed.-grep-	:: CommandOptions.CommandOptions	-- ^ The match-criteria, which may include the name of the file on which to operate.-	-> [String]				-- ^ A supplementary list of files on which to operate-	-> IO ()				-- ^ Nothing is returned, since the result is printed.-grep commandOptions nonOptions-{-- The algorithm depends fundamentally on whether the data comes from 'stdin' or from file.- This is because of the requirement, in the former case, to deliver instantaneous feedback.- This forces us to print matches as they're found, rather than batching them for return to the caller to print.- If we COULD return 'IO [String]', then 'matchFilterStdIn' could be called instead of 'grep' when (fileName == "-"); annoyingly, it just doesn't work.--}-	| any ($ fileNames) [null, all (== "-")]	= let-		matchFilterStdIn :: LineNumber -> Matches -> IO System.Exit.ExitCode-		matchFilterStdIn lineNumber matches	= {-#SCC "matchFilterStdIn" #-} do-			isEOF	<- System.IO.isEOF--			if isEOF-				then if listFilesWithMatches-					then return {-to IO-monad-} $ System.Exit.ExitFailure 1	-- No match has been found, otherwise we'd have exited earlier.-					else if listFilesWithoutMatch-						then putStrLn dummyFileName	>> return {-to IO-monad-} System.Exit.ExitSuccess-						else do-							Control.Monad.when countMatches $ print matches--							return {-to IO-monad-} $ if matches == 0-								then System.Exit.ExitFailure 1-								else System.Exit.ExitSuccess-				else {-not EOF-} do-					line	<- getLine	-- Process line-at-a-time, to provide instant feedback.--					let-						lineNumber' :: LineNumber-						lineNumber'	= succ lineNumber--						onSuccess :: String -> IO System.Exit.ExitCode-						onSuccess line'-							| listFilesWithMatches	= putStrLn dummyFileName	>> return {-to IO-monad-} System.Exit.ExitSuccess-							| listFilesWithoutMatch	= return {-to IO-monad-} $ System.Exit.ExitFailure 1-							| otherwise		= do-								Control.Monad.unless countMatches . putStrLn $ (-									if prependLineNumbers-										then showLineNumber lineNumber'-										else id-								 ) line'--								matchFilterStdIn lineNumber' $ succ matches	-- Recurse.--						onFailure, onMismatch :: IO System.Exit.ExitCode-						onFailure	= matchFilterStdIn lineNumber' matches	-- Recurse-						onMismatch-							| invertMatch	= onSuccess line-							| otherwise	= onFailure--					if verbose-						then let-							result :: RegExDot.RegEx.Result Char-							result	= line +~ regExOpts-						in if RegExDot.Result.isMatch result-							then if invertMatch-								then onFailure-								else onSuccess $ show result-							else onMismatch-						else {-terse-} if line =~ regExOpts-							then if invertMatch-								then onFailure-								else onSuccess line-							else onMismatch-			where-				dummyFileName :: String-				dummyFileName	= "<standard input>"-	in matchFilterStdIn 0 0 >>= System.Exit.exitWith-	| otherwise {-file-names provided-}	= let-		findMatch :: String -> RegExDot.RegEx.Result Char-		findMatch	= (+~ regExOpts)--		matchFilter :: [String] -> [String]-		matchFilter	= {-#SCC "matchFilter" #-} (-			if countMatches-				then return {-to List-monad-} . show . length	-- Substitute the list of matches, with its length.-				else id-		 ) . (-			let-				isMatch :: String -> Bool-				isMatch = {-#SCC "isMatch" #-} (if invertMatch then not else id) . (=~ regExOpts)-			in if prependLineNumbers-				then map (uncurry showLineNumber) . (-					if verbose-						then map (-							Control.Arrow.second show-						) . filter (-							RegExDot.Result.isMatch . snd-						) . map (-							Control.Arrow.second findMatch-						)-						else {-terse-} filter (isMatch . snd)-				) . zip [1 :: LineNumber ..]-				else {-unnumbered-} if verbose-					then map show . filter RegExDot.Result.isMatch . map findMatch-					else {-terse-} filter isMatch-		 )--		identifySource :: String -> [String] -> [String]-		identifySource fileName results-			| listFilesWithMatches			= [fileName | not isEmpty] {-list-comprehension-}-			| listFilesWithoutMatch			= [fileName | isEmpty] {-list-comprehension-}-			| length (Data.List.nub fileNames) > 1	= (showString fileName . separate) `map` results-			| otherwise				= results-			where-				isEmpty :: Bool-				isEmpty	= null results-	in do-		results <- (-			concat . Control.Parallel.Strategies.parMap Control.Parallel.Strategies.rdeepseq (-				uncurry identifySource . Control.Arrow.second (matchFilter . {-#SCC "lines" #-} lines {-chops '\n'-})-			) . zip fileNames-		 ) `fmap` mapM readFile fileNames--		mapM_ putStrLn results--		System.Exit.exitWith $ if null results-			then System.Exit.ExitFailure 1-			else System.Exit.ExitSuccess-	where-		countMatches, invertMatch, prependLineNumbers, listFilesWithMatches, listFilesWithoutMatch, verbose :: Bool-		[countMatches, invertMatch, prependLineNumbers, listFilesWithMatches, listFilesWithoutMatch, verbose]	= ($ commandOptions) `map` [-			CommandOptions.countMatches,-			CommandOptions.invertMatch,-			CommandOptions.prependLineNumbers,-			CommandOptions.listFilesWithMatches,-			CommandOptions.listFilesWithoutMatch,-			CommandOptions.verbose-		 ] -- Divvy-up.---- Separate the regEx & the names of the input-data files to feed it.-		extendedRegExChar	:: ExtendedRegExChar.ExtendedRegExChar-		fileNames		:: [String]-		(extendedRegExChar, fileNames)	= case CommandOptions.extendedRegExChar commandOptions of-			Just c	-> (c, nonOptions)-			_-				| null nonOptions	-> error "Undefined regex."-				| otherwise		-> read . head &&& tail $ nonOptions---- Combine the regex & options, to create a complete task-description.-		regExOpts :: RegExDot.RegExOpts.RegExOpts ExtendedRegExChar.ExtendedRegExChar-		regExOpts	= RegExDot.RegExOpts.MkRegExOpts {-			RegExDot.RegExOpts.compilationOptions	= CommandOptions.compilationOptions commandOptions,-			RegExDot.RegExOpts.executionOptions	= CommandOptions.executionOptions commandOptions,-			RegExDot.RegExOpts.regEx		= extendedRegExChar-		}---- Define functions used to format the output.-		separate :: ShowS-		separate	= showChar ':'--		showLineNumber :: LineNumber -> ShowS-		showLineNumber n	= shows n . separate-
− src/Grecce/Test/Assert/RegExOptsChar.hs
@@ -1,93 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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 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-import qualified	RegExDot.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 :: RegExDot.CompilationOptions.CompilationOptions -> RegExDot.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 parse " ++ show fileName ++ "; " ++ show line ++ "."-	) . filter (-		(/= '#') . head	-- Remove comments.-	) . filter (-		not . null	-- Remove blank lines.-	) . lines- ) `fmap` readFile fileName-
− src/Grecce/Test/Performance/ExtendedRegEx.hs
@@ -1,145 +0,0 @@-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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 'RegExDot.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 Prelude hiding ((<$>), (<*>))	-- The "Prelude" from 'base-4.8' exports this symbol.-import			Control.Applicative((<$>), (<*>))-import qualified	Control.Arrow-import			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-import qualified	RegExDot.RegEx-import qualified	RegExDot.RegExOpts-import qualified	Text.Regex.Posix-import qualified	ToolShed.Defaultable-import qualified	ToolShed.System.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 :: RegExDot.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 (-				ToolShed.System.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 -> (-					RegExDot.RegEx./~ RegExDot.RegExOpts.MkRegExOpts {	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-						RegExDot.RegExOpts.compilationOptions	= ToolShed.Defaultable.defaultValue,-						RegExDot.RegExOpts.executionOptions	= executionOptions,-						RegExDot.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 <$> (-				(ToolShed.System.TimePure.getCPUSeconds . ($ inputData)) `mapM` [-					showMatch,-					if RegExDot.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 :: RegExDot.RegExOpts.RegExOpts (RegExDot.RegEx.ExtendedRegEx Char)-					regExOpts	= RegExDot.RegExOpts.MkRegExOpts {-						RegExDot.RegExOpts.compilationOptions	= ToolShed.Defaultable.defaultValue,-						RegExDot.RegExOpts.executionOptions	= executionOptions,-						RegExDot.RegExOpts.regEx		= extendedRegEx-					} -- Similar to 'RegexLike.makeRegexOpts', but without the requirement to read the regex.-				in if RegExDot.ExecutionOptions.requireMatchList executionOptions-					then show . (RegExDot.RegEx.+~ regExOpts)	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-					else show . (RegExDot.RegEx.=~ regExOpts)	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-			) &&& show . ExtendedRegExChar.MkExtendedRegExChar False {-hasNonCapturingTopLevelAlternatives-}-		 ) . testGenerator-
− src/Grecce/Test/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.Test.Performance.ExtendedRegExTest(--- * Type-classes-	TestGeneratorRepository(..),--- * Types--- ** Type-synonyms-	TestComplexity,-	Test,-	TestGenerator-) where--import qualified	RegExDot.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	= (RegExDot.RegEx.InputData a, RegExDot.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
@@ -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.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
@@ -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.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-import qualified	RegExDot.BracketExpressionMember-import			RegExDot.DSL((-:), (?:), (*:), (<~>))-import qualified	RegExDot.Meta-import qualified	RegExDot.RegEx-import			RegExDot.RegEx((.*), (.*?))-import qualified	RegExDot.Repeatable-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 -> (RegExDot.RegEx.Pattern Char -> RegExDot.RegEx.RepeatablePattern Char) -> RegExDot.RegEx.RepeatablePattern Char-					exactly n f	= (RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . return {-to List-monad-} $ f testRequirement) ^# n-				in ((Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . (`map` [RegExDot.Repeatable.zeroOrOne, RegExDot.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")) &&& RegExDot.RegEx.dock . (-					`mkExtendedRegExFromRepeatableSingletonAlternative` (RegExDot.Anchor.unanchored <~>) [-						(.*),-						RegExDot.RegEx.simply $ RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.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 (-					RegExDot.Anchor.unanchored <~> RegExDot.RegEx.captureGroup (-						map (-							(RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . (testRequirement ^#) . (2 ^)-						) [0 :: Int .. 1]-					) *: RegExDot.RegEx.Require (RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . return {-to List-monad-} . RegExDot.Repeatable.zeroOrMore . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ [RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . replicate i . RegExDot.Repeatable.one . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ [RegExDot.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 :: RegExDot.Repeatable.Repetitions-					base	= 2	-- Arbitrarily.--					bounds :: RegExDot.Repeatable.RepetitionBounds-					bounds	= (0, Just base)-				in (`replicate` testChar) . (base ^) &&& RegExDot.RegEx.dock . (-					(-						mkExtendedRegExFromRepeatableSingletonAlternative (^#-># bounds) `iterate` (RegExDot.Anchor.unanchored <~>) [testRequirement ^#-># bounds] {-initial value-}-					) !!-				) . pred-			),-{-- "^((((((((((((((<testChar>*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*?)*? ... $".- Explanation:	interesting because all 'RegExDot.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) &&& RegExDot.RegEx.dock . (-					(-						mkExtendedRegExFromRepeatableSingletonAlternative RegExDot.Repeatable.zeroOrMore' `iterate` (RegExDot.Anchor.unanchored <~>) [RegExDot.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 RegExDot.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 :: RegExDot.Repeatable.Repetitions-					base	= 2	-- Arbitrarily.-				in (`replicate` testChar) . (base ^) &&& RegExDot.RegEx.dock . head . (-					(-						iterate (-							\extendedRegExList -> (-								(RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . (^# base) . RegExDot.RegEx.captureGroup-							) `map` [extendedRegExList, reverse extendedRegExList]-						) $ map (-							(RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . ($ RegExDot.RegEx.Require $ RegExDot.Meta.Literal testChar)-						) [RegExDot.Repeatable.one, RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) $ map RegExDot.Repeatable.zeroOrMore [-						RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ (-							\i -> ($ i) `map` [-								(testRequirement ^#),-								RegExDot.RegEx.simply . RegExDot.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 :: [RegExDot.RegEx.Concatenation Char] -> RegExDot.RegEx.Concatenation Char-					zeroOrMoreAlternatives	= return {-to List-monad-} . RegExDot.Repeatable.zeroOrMore . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>)-				in (-					id &&& (-						((Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . (RegExDot.RegEx.Require (RegExDot.Meta.Literal testChar) ?:) . zeroOrMoreAlternatives . map (-							\(a, b)	-> zeroOrMoreAlternatives $ return {-to List-monad-} [a, b]-						) . init . tail . uncurry zip . (-							map RegExDot.Repeatable.one . init &&& map RegExDot.Repeatable.zeroOrOne . tail-						) . bracket undefined . map (-							RegExDot.RegEx.Require . RegExDot.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'	= succ complexity--					testSet :: String-					testSet	= take complexity' . filter Data.Char.isAlphaNum $ filter Data.Char.isAscii [minBound .. maxBound]-				in (-					concat $ replicate complexity' testSet,-					((Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) $ (-						RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) $ map (-							return {-to List-monad-} . RegExDot.RegEx.simply . RegExDot.Meta.Literal-						) testSet-					) *: [-						(-							RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} $ RegExDot.RegEx.Require (RegExDot.Meta.Literal $ head testSet) -: (.*?) : RegExDot.RegEx.Require (RegExDot.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 RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~>) . return {-to List-monad-} . RegExDot.Repeatable.zeroOrMore . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . (-						[-							RegExDot.Repeatable.zeroOrMore testRequirement,-							RegExDot.RegEx.simply . RegExDot.Meta.NoneOf $ map RegExDot.BracketExpressionMember.Literal [testChar]-						] :-					) . map (-						return {-to List-monad-} . RegExDot.RegEx.simply . RegExDot.Meta.NoneOf . return {-to List-monad-} . RegExDot.BracketExpressionMember.Literal-					) . (-						`take` tail [testChar ..]-					)-				)-			)-		]-	 ) where-		testChar :: Char-		testChar	= 'a'--		testRequirement :: RegExDot.RegEx.Pattern Char-		testRequirement	= RegExDot.RegEx.Require $ RegExDot.Meta.Literal testChar--		mkExtendedRegExFromRepeatableSingletonAlternative :: (RegExDot.RegEx.Pattern Char -> RegExDot.RegEx.RepeatablePattern Char) -> RegExDot.RegEx.ExtendedRegEx Char -> RegExDot.RegEx.ExtendedRegEx Char-		mkExtendedRegExFromRepeatableSingletonAlternative makeRepetitions	= (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-} . makeRepetitions . RegExDot.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 * succ i `div` 2
− src/Grecce/Test/QC/ExtendedRegExChar.hs
@@ -1,188 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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 qualified	Data.Maybe-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-import qualified	RegExDot.BracketExpressionMember-import qualified	RegExDot.Consumer-import qualified	RegExDot.ConsumptionBounds-import qualified	RegExDot.ConsumptionProfile-import			RegExDot.DSL((-:), (?:), (+:), (<~>))-import qualified	RegExDot.Meta-import qualified	RegExDot.RegEx-import			RegExDot.RegEx((+~))-import qualified	RegExDot.RegExOpts-import qualified	RegExDot.Repeatable-import qualified	RegExDot.Result-import qualified	Test.QuickCheck-import			Test.QuickCheck((==>))-import qualified	ToolShed.SelfValidate-import qualified	ToolShed.Test.ReversibleIO---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype AlternativesChar	= MkAlternativesChar (RegExDot.RegEx.Alternatives Char) deriving (Eq, Read, Show)---- | Accessor.-deconstructAlternativesChar :: AlternativesChar -> RegExDot.RegEx.Alternatives Char-deconstructAlternativesChar (MkAlternativesChar a)	= a--instance ToolShed.SelfValidate.SelfValidator AlternativesChar where-	getErrors	= ToolShed.SelfValidate.getErrors . deconstructAlternativesChar--instance RegExDot.Consumer.Consumer AlternativesChar where-	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstructAlternativesChar-	starHeight		= RegExDot.Consumer.starHeight . deconstructAlternativesChar--instance Test.QuickCheck.Arbitrary AlternativesChar	where-	arbitrary	= (MkAlternativesChar . RegExDot.RegEx.MkAlternatives . map ExtendedRegExChar.extendedRegEx) `fmap` (-		Test.QuickCheck.elements [1, 2]	>>= Test.QuickCheck.vector {-[ExtendedRegExChar]-}-	 ) -- TODO: permit zero alternatives.---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype PatternChar	= MkPatternChar (RegExDot.RegEx.Pattern Char) deriving (Eq, Read, Show)---- | Accessor.-deconstructPatternChar :: PatternChar -> RegExDot.RegEx.Pattern Char-deconstructPatternChar (MkPatternChar pattern)	= pattern--instance ToolShed.SelfValidate.SelfValidator PatternChar	where-	getErrors	= ToolShed.SelfValidate.getErrors . deconstructPatternChar--instance RegExDot.Consumer.Consumer PatternChar	where-	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstructPatternChar-	starHeight		= RegExDot.Consumer.starHeight . deconstructPatternChar--instance Test.QuickCheck.Arbitrary PatternChar	where-	arbitrary	= MkPatternChar `fmap` Test.QuickCheck.frequency [-		(4,	(RegExDot.RegEx.Require . MetaChar.deconstruct) `fmap` Test.QuickCheck.arbitrary {-MetaChar-}),-		(1,	(RegExDot.RegEx.CaptureGroup . deconstructAlternativesChar) `fmap` Test.QuickCheck.arbitrary {-AlternativesChar-})-	 ] -- CAVEAT: may recurse forever if 'RegExDot.RegEx.CaptureGroup / RegExDot.RegEx.Require' is too high.---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype RepeatablePatternChar	= MkRepeatablePatternChar (RegExDot.Repeatable.Repeatable PatternChar)	deriving (Eq, Read, Show)---- | Accessor.-deconstructRepeatablePatternChar :: RepeatablePatternChar -> RegExDot.Repeatable.Repeatable PatternChar-deconstructRepeatablePatternChar (MkRepeatablePatternChar repeatable)	= repeatable--instance ToolShed.SelfValidate.SelfValidator RepeatablePatternChar	where-	getErrors	= ToolShed.SelfValidate.getErrors . deconstructRepeatablePatternChar--instance RegExDot.Consumer.Consumer RepeatablePatternChar	where-	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstructRepeatablePatternChar-	starHeight		= RegExDot.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 `fmap` Test.QuickCheck.elements [max fewest 1 .. 9]]-		isGreedy	<- Test.QuickCheck.arbitrary {-Bool-}--		let-			repetitionBounds :: RegExDot.Repeatable.RepetitionBounds-			repetitionBounds	= (fewest, most)--		return {-to Gen-monad-} $ MkRepeatablePatternChar RegExDot.Repeatable.MkRepeatable {-			RegExDot.Repeatable.base		= patternChar,-			RegExDot.Repeatable.repetitionBounds	= repetitionBounds,-			RegExDot.Repeatable.isGreedy		= RegExDot.Repeatable.hasPreciseBounds repetitionBounds || isGreedy	-- Only specify non-greedy where space exists.-		}--instance Test.QuickCheck.Arbitrary ExtendedRegExChar.ExtendedRegExChar	where-	arbitrary	= do-		hasBowAnchor	<- Test.QuickCheck.arbitrary {-Bool-}-		concatenation	<- map (fmap deconstructPatternChar {-replace base-} . deconstructRepeatablePatternChar {-RegExDot.Repeatable.Repeatable PatternChar-}) `fmap` Test.QuickCheck.vector 2 {-[RepeatablePatternChar]-}-		hasSternAnchor	<- Test.QuickCheck.arbitrary {-Bool-}--		return {-to Gen-monad-} $ ExtendedRegExChar.MkExtendedRegExChar False RegExDot.RegEx.MkExtendedRegEx {-			RegExDot.RegEx.bowAnchor	= if hasBowAnchor then Just RegExDot.Anchor.Bow else Nothing,-			RegExDot.RegEx.concatenation	= concatenation,-			RegExDot.RegEx.sternAnchor	= if hasSternAnchor then Just RegExDot.Anchor.Stern else Nothing-		}--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" $ Data.Maybe.maybe True (>= minData) maybeMaxData && (-			not b == all (not . RegExDot.Consumer.getHasSpecificRequirement) (RegExDot.RegEx.concatenation $ ExtendedRegExChar.extendedRegEx r)-		 )-			where-				RegExDot.ConsumptionProfile.MkConsumptionProfile {-					RegExDot.ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),-					RegExDot.ConsumptionProfile.hasSpecificRequirement	= b-				} = RegExDot.Consumer.consumptionProfile r--		prop_consumptionProfile2 r	= RegExDot.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-				RegExDot.ConsumptionProfile.MkConsumptionProfile {-					RegExDot.ConsumptionProfile.hasSpecificRequirement	= hasSpecificRequirement,-					RegExDot.ConsumptionProfile.canConsumeAnything		= canConsumeAnything-				} = RegExDot.Consumer.consumptionProfile r--		prop_io			= Test.QuickCheck.label "prop_io" . ToolShed.Test.ReversibleIO.isReversible-		prop_io' r		= Test.QuickCheck.label "prop_io'" $ ToolShed.Test.ReversibleIO.isReversible r'	where r' = ExtendedRegExChar.extendedRegEx r	-- Check "RegExDot.RegEx.ExtendedRegEx Char" too.-		prop_isValid r		= Test.QuickCheck.label "prop_isValid" $ ToolShed.SelfValidate.isValid r-		prop_starHeight r	= Test.QuickCheck.label "prop_starHeight" $ (RegExDot.Consumer.starHeight r == 0) == RegExDot.ConsumptionBounds.isPrecise (RegExDot.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" $ RegExDot.RegEx.extractDataFromMatchList `fmap` RegExDot.Result.getMatchList result == Just s	where-			s :: String-			s	= show $ d * 1e6	-- Implementation of show, uses exponential notation, when the number is large.--			result :: RegExDot.RegEx.Result Char-			result = s +~ RegExDot.RegExOpts.mkRegEx (-				(Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~> sign ?: digits +: map (-					RegExDot.Repeatable.zeroOrOne . RegExDot.RegEx.captureGroup . map (RegExDot.Anchor.unanchored <~>) . return {-to List-monad-}-				) [-					RegExDot.RegEx.Require (RegExDot.Meta.Literal '.') -: digits +: [],-					RegExDot.RegEx.Require (RegExDot.Meta.AnyOf $ map RegExDot.BracketExpressionMember.Literal "eE") -: sign ?: digits +: []-				]-			 ) where-				sign, digits :: RegExDot.RegEx.Pattern Char-				sign	= RegExDot.RegEx.Require . RegExDot.Meta.AnyOf $ map RegExDot.BracketExpressionMember.Literal "+-"-				digits	= RegExDot.RegEx.Require . RegExDot.Meta.AnyOf $ map RegExDot.BracketExpressionMember.Literal ['0' .. '9']-
− src/Grecce/Test/QC/MetaChar.hs
@@ -1,67 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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 qualified	Data.List-import qualified	RegExChar.MetaChar	as MetaChar	-- CAVEAT: beware of the similar name.-import qualified	RegExDot.BracketExpression-import qualified	RegExDot.BracketExpressionMember-import qualified	RegExDot.Meta-import qualified	Test.QuickCheck-import qualified	ToolShed.Test.ReversibleIO--testCharacters :: String-testCharacters	= filter (`notElem` [RegExDot.Meta.shortcutToken, RegExDot.BracketExpression.negationToken]) [' ' .. '~']	-- TODO: permit all characters.--instance Test.QuickCheck.Arbitrary MetaChar.MetaChar	where-	arbitrary	= Test.QuickCheck.oneof $ map (fmap MetaChar.MkMetaChar) [-		return {-to Gen-monad-} RegExDot.Meta.Any,-		RegExDot.Meta.Literal `fmap` Test.QuickCheck.elements testCharacters,-		(RegExDot.Meta.AnyOf . map RegExDot.BracketExpressionMember.Literal . Data.List.nub) `fmap` arbitraryCharList 1 16,	-- Test.QuickCheck.vector 16 {-Char-},-		(RegExDot.Meta.NoneOf . map RegExDot.BracketExpressionMember.Literal . Data.List.nub) `fmap` 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)) `fmap` Test.QuickCheck.vector maxBound {-Char-}--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	= Test.QuickCheck.label "prop_io" . ToolShed.Test.ReversibleIO.isReversible-
− src/Grecce/Test/QC/QuickChecks.hs
@@ -1,49 +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@]	Calls the /quickChecks/-functions for modules supporting this feature.--}--module Grecce.Test.QC.QuickChecks(--- * Functions-	run-) where--import qualified	Control.Arrow-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	= mapM_ (-	uncurry (>>) . Control.Arrow.first putStrLn- ) [-	("MetaChar",		Test.QC.MetaChar.quickChecks checker),-	("RepeatableMetaChar",	Test.QC.RepeatableMetaChar.quickChecks checker),-	("ExtendedRegExChar",	Test.QC.ExtendedRegExChar.quickChecks checker)- ] where-	checker :: Test.QuickCheck.Testable t => t -> IO ()-	checker-		| isVerbose	= Test.QuickCheck.verboseCheck-		| otherwise	= Test.QuickCheck.quickCheck-
− src/Grecce/Test/QC/RepeatableMetaChar.hs
@@ -1,92 +0,0 @@-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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 qualified	Data.Maybe-import			Grecce.Test.QC.MetaChar()-import qualified	RegExChar.MetaChar	as MetaChar-import qualified	RegExDot.Consumer-import qualified	RegExDot.ConsumptionBounds-import qualified	RegExDot.ConsumptionProfile-import qualified	RegExDot.Repeatable-import qualified	Test.QuickCheck-import qualified	ToolShed.SelfValidate-import qualified	ToolShed.Test.ReversibleIO---- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.-newtype RepeatableMetaChar	= MkRepeatableMetaChar (RegExDot.Repeatable.Repeatable MetaChar.MetaChar)	deriving (Eq, Read, Show)---- | Accessor.-deconstruct :: RepeatableMetaChar -> RegExDot.Repeatable.Repeatable MetaChar.MetaChar-deconstruct (MkRepeatableMetaChar repeatableMetaChar)	= repeatableMetaChar--instance ToolShed.SelfValidate.SelfValidator RepeatableMetaChar	where-	getErrors	= ToolShed.SelfValidate.getErrors . deconstruct--instance RegExDot.Consumer.Consumer RepeatableMetaChar	where-	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstruct-	starHeight		= RegExDot.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 `fmap` Test.QuickCheck.elements [max fewest 1 .. 9]]-		isGreedy	<- Test.QuickCheck.arbitrary--		let-			repetitionBounds :: RegExDot.Repeatable.RepetitionBounds-			repetitionBounds	= (fewest, most)--		return {-to Gen-monad-} . MkRepeatableMetaChar $ RegExDot.Repeatable.MkRepeatable {-			RegExDot.Repeatable.base		= metaChar,-			RegExDot.Repeatable.repetitionBounds	= repetitionBounds,-			RegExDot.Repeatable.isGreedy		= RegExDot.Repeatable.hasPreciseBounds repetitionBounds || isGreedy	-- Only specify 'non-greedy' where space exists.-		}--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" $ Data.Maybe.maybe True (>= minData) maybeMaxData && b == RegExDot.Consumer.getHasSpecificRequirement (RegExDot.Repeatable.base $ deconstruct r)	where RegExDot.ConsumptionProfile.MkConsumptionProfile {-		RegExDot.ConsumptionProfile.consumptionBounds		= (minData, maybeMaxData),-		RegExDot.ConsumptionProfile.hasSpecificRequirement	= b-	} = RegExDot.Consumer.consumptionProfile r--	prop_io (MkRepeatableMetaChar r)		= Test.QuickCheck.label "prop_io" $ ToolShed.Test.ReversibleIO.isReversible r--	prop_isValid r					= Test.QuickCheck.label "prop_isValid" $ ToolShed.SelfValidate.isValid r--	prop_starHeight (MkRepeatableMetaChar r)	= Test.QuickCheck.label "prop_starHeight" $ RegExDot.Consumer.starHeight r == if RegExDot.ConsumptionBounds.isPrecise (RegExDot.Consumer.getConsumptionBounds r) then 0 else 1-
− src/Main.hs
@@ -1,207 +0,0 @@-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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@]--	* Contains the entry-point to the program.--	* Provides command-line access to "ExtendedRegExChar".--	* Defines the permissible command-line arguments; aping /egrep/, but with the addition of /--verbose/, which enables one to see the details of the data-capture.-- [@TODO@]	Coordinate the output of 'printVersion' with the definition in '.cabal'; this may not be feasible.--}--module Main(main) where--import qualified	Data.List-import qualified	Data.Version-import qualified	Distribution.Package-import qualified	Distribution.Text-import qualified	Distribution.Version-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	Paths_regexchar						as Paths	-- Either local stub, or package-instance autogenerated by 'Setup.hs build'.-import qualified	RegExDot.CompilationOptions-import qualified	RegExDot.ExecutionOptions-import qualified	System.Console.GetOpt					as G-import qualified	System.Environment-import qualified	System.Exit-import qualified	System.IO-import qualified	System.IO.Error-import qualified	ToolShed.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'.---- | On failure to parse the specified string, returns an explanatory error.-read' :: Read a => String -> String -> a-read' errorMessage s	= case reads s of-	[(x, "")]	-> x-	_		-> error $ errorMessage ++ show s---- | On failure to parse a command-line argument, returns an explanatory error.-readCommandArg :: Read a => String -> a-readCommandArg	= read' "failed to parse command-line argument "--{- |-	* Parses the command-line arguments, to determine 'CommandOptions.CommandOptions'.--	* Arguments following 'CommandOptions.CommandOptions', are interpreted as a /regex/, followed by the names of the files to which it is applied.--}-main :: IO ()-main	= do-	progName	<- System.Environment.getProgName--	let-		usageMessage :: String-		usageMessage	= "Usage:\t" ++ G.usageInfo progName optDescrList ++ "  <regex> [<file-name>, ...]"---- Define the command-line options, & the 'CommandLineAction's used to handle them.-		optDescrList :: [G.OptDescr CommandLineAction]-		optDescrList	= [---				 String	[String]					(G.ArgDescr CommandLineAction)							String-			G.Option "?"	["help"]					(G.NoArg $ const printUsage)							"Output:\tdisplay this help-text & then exit.",-			G.Option ""	["verbose"]					(G.NoArg $ return {-to IO-monad-} . CommandOptions.setVerbose)			("Output:\tsee how the input data was captured by the RegEx; default '" ++ show (CommandOptions.verbose ToolShed.Defaultable.defaultValue) ++ "'. CAVEAT: to be effective, it should precede other options."),-			G.Option ""	["version"]					(G.NoArg $ const printVersion)							"Output:\tprint version-information & then exit.",-			G.Option "c"	["count"]					(G.NoArg $ return {-to IO-monad-} . CommandOptions.setCountMatches)		("Output:\tprint only a count of matching lines per file; default '" ++ show (CommandOptions.countMatches ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option "l"	["files-with-matches"]				(G.NoArg $ return {-to IO-monad-} . CommandOptions.setListFilesWithMatches)	("Output:\tlist names of files containing at least one match; default '" ++ show (CommandOptions.listFilesWithMatches ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option "L"	["files-without-match"]				(G.NoArg $ return {-to IO-monad-} . CommandOptions.setListFilesWithoutMatch)	("Output:\tlist names of files not containing any matches; default '" ++ show (CommandOptions.listFilesWithoutMatch ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option "n"	["number"]					(G.NoArg $ return {-to IO-monad-} . CommandOptions.setPrependLineNumbers)	("Output:\tprepend the line-number of the input, to the output; default '" ++ show (CommandOptions.prependLineNumbers ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option "v"	["invert-match"]				(G.NoArg $ return {-to IO-monad-} . CommandOptions.setInvertMatch)		("Output:\tselect non-matching lines; default '" ++ show (CommandOptions.invertMatch ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["printCurrentSettings"]			(G.NoArg printCurrentSettings)							"Output:\tdisplay the currently defined options & then exit.",-			G.Option "e"	["regex"]					(setExtendedRegExChar `G.ReqArg` "<regex>")					"Input:\tdefine the regex.",-			G.Option "f"	["file"]					(readExtendedRegExCharFromFile `G.ReqArg` "<file-name>")			"Input:\tread the regex from file.",-			G.Option ""	["performance"]					(-				extendedRegExCharPerformance `G.ReqArg` "(Int,Either [TestName])"-			) (-				"Test:\tcompare performance with other RegEx-engines, using the specified pair (<Maximum complexity>, Left " ++ show [-					minBound :: Test.Performance.ExtendedRegExTestsNegative.TestName .. maxBound-				] ++ " or Right " ++ show [-					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.",-			G.Option ""	["assert"]					(assertFromFile `G.ReqArg` "<file-name>")					"Test:\trun the assertions, defined in the specified file, & then exit. NB: specify this option last.",-			G.Option ""	["assertPosix"]					(assertPosixFromFile `G.ReqArg` "<file-name>")					"Test:\trun the assertions, defined in the specified file, against Text.Regex.Posix, & then exit. NB: specify this option last.",-			G.Option ""	["abortTrialRepetitionsOnInherentFailure"]	(setExecutionOption abortTrialRepetitionsOnInherentFailure `G.ReqArg` "Bool")	("Performance:\tif an alternative can't match, irrespective of the subsequent concatenation, then terminate futile trial repetitions; default '" ++ show (RegExDot.ExecutionOptions.abortTrialRepetitionsOnInherentFailure ToolShed.Defaultable.defaultValue) ++ "'."),---			G.Option ""	["abortTrialRepetitionsOnZeroConsumption"]	(setExecutionOption abortTrialRepetitionsOnZeroConsumption `G.ReqArg` "Bool")	("Performance:\tcheck for zero data-consumption by the n-th repetition of an alternative, before considering (n + 1); default '" ++ show (RegExDot.ExecutionOptions.abortTrialRepetitionsOnZeroConsumption ToolShed.Defaultable.defaultValue) ++ "'."),---			G.Option ""	["bypassInputDataForLiberalConsumer"]		(setExecutionOption bypassInputDataForLiberalConsumer `G.ReqArg` "Bool")	("Performance:\tbypass reading of the unconsumed input data, if the remaining RegEx can consume a sufficient quantity of anything; default '" ++ show (RegExDot.ExecutionOptions.bypassInputDataForLiberalConsumer ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["catchIncompatibleAnchors"]			(setExecutionOption catchIncompatibleAnchors `G.ReqArg` "Bool")			("Performance:\tavoid futile trial solutions, involving repetitions of anchored alternatives, which must consume data; default '" ++ show (RegExDot.ExecutionOptions.catchIncompatibleAnchors ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["checkExistenceOfInelasticTail"]		(setExecutionOption checkExistenceOfInelasticTail `G.ReqArg` "Bool")		("Performance:\tif the regex ends in one or more Meta-data, whose repetition-range is precisely defined, check that this sequence exists at the end of the input data; default '" ++ show (RegExDot.ExecutionOptions.checkExistenceOfInelasticTail ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["checkForUnconsumableData"]			(setExecutionOption checkForUnconsumableData `G.ReqArg` "Bool")			("Performance:\tcheck whether there's no possibility of consuming some of the input data; default '" ++ show (RegExDot.ExecutionOptions.checkForUnconsumableData ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["moderateGreed"]				(setExecutionOption moderateGreed `G.ReqArg` "Bool")				("Performance:\tgreedily consume data, only up to the limit beyond which, future requirements would be compromised; default '" ++ show (RegExDot.ExecutionOptions.moderateGreed ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["permitReorderingOfAlternatives"]		(setExecutionOption permitReorderingOfAlternatives `G.ReqArg` "Bool")		("Performance:\tpermit alternatives to be re-ordered, in an attempt to process the cheapest first; default '" ++ show (RegExDot.ExecutionOptions.permitReorderingOfAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["preferAlternativesWhichFeedTheGreedy"]	(setExecutionOption preferAlternativesWhichFeedTheGreedy `G.ReqArg` "Bool")	("Preference:\tprefer solutions in which the choice of alternatives directs data from non-greedy to greedy consumers; default '" ++ show (RegExDot.ExecutionOptions.preferAlternativesWhichFeedTheGreedy ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["preferAlternativesWhichMimickUnrolling"]	(setExecutionOption preferAlternativesWhichMimickUnrolling `G.ReqArg` "Bool")	("Preference:\tprefer solutions in which the choice of alternatives consumes data like the unrolled repeatable group; default '" ++ show (RegExDot.ExecutionOptions.preferAlternativesWhichMimickUnrolling ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["preferFewerRepeatedAlternatives"]		(setExecutionOption preferFewerRepeatedAlternatives `G.ReqArg` "Bool")		("Preference:\tprefer solutions employing fewer repetitions of alternatives, to discourage the capture of null lists; default '" ++ show (RegExDot.ExecutionOptions.preferFewerRepeatedAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["unrollRepeatedSingletonAlternative"]		(setExecutionOption unrollRepeatedSingletonAlternative `G.ReqArg` "Bool")	("Performance:\tunroll repetitions of singleton alternatives; this doesn't affect the result; default '" ++ show (RegExDot.ExecutionOptions.unrollRepeatedSingletonAlternative ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["useFirstMatchAmongAlternatives"]		(setExecutionOption useFirstMatchAmongAlternatives `G.ReqArg` "Bool")		("Performance:\trather than performing an exhaustive search for the optimal choice amongst alternatives, merely select the first that matches; conform to Perl rather than Posix; default '" ++ show (RegExDot.ExecutionOptions.useFirstMatchAmongAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["validateMinConsumptionOfAlternatives"]	(setExecutionOption validateMinConsumptionOfAlternatives `G.ReqArg` "Bool")	("Performance:\twhen the number of repetitions of a group of alternatives is precisely specified, check the availability of the resulting minimum data-requirement; default '" ++ show (RegExDot.ExecutionOptions.validateMinConsumptionOfAlternatives ToolShed.Defaultable.defaultValue) ++ "'."),-			G.Option ""	["complyStrictlyWithPosix"]			(setCompilationOption complyStrictlyWithPosix `G.ReqArg` "Bool")		("Output:\tdefine the offset of captured data, corresponding to a sub-expression which matched zero times, as the artificial value -1 specified by Posix; currently only affects results of 'assert'; default '" ++ show (RegExDot.CompilationOptions.complyStrictlyWithPosix ToolShed.Defaultable.defaultValue) ++ "'.")-		 ] where-			printVersion, printUsage :: IO CommandOptions.CommandOptions--			printVersion	= System.IO.hPutStrLn System.IO.stderr (Distribution.Text.display packageIdentifier ++ "\n\nCopyright (C) 2010-2015 " ++ author ++ ".\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by " ++ author ++ ".")	>> System.Exit.exitWith System.Exit.ExitSuccess	where-				packageIdentifier :: Distribution.Package.PackageIdentifier-				packageIdentifier	= Distribution.Package.PackageIdentifier {-					Distribution.Package.pkgName	= Distribution.Package.PackageName "grecce",-					Distribution.Package.pkgVersion	= Distribution.Version.Version (Data.Version.versionBranch Paths.version) []-				}--				author :: String-				author	= "Dr. Alistair Ward"--			printUsage	= System.IO.hPutStrLn System.IO.stderr usageMessage	>> System.Exit.exitWith System.Exit.ExitSuccess--			printCurrentSettings, runQuickChecks :: CommandLineAction-			printCurrentSettings commandOptions	= print commandOptions	>> System.Exit.exitWith System.Exit.ExitSuccess-			runQuickChecks commandOptions		= Test.QC.QuickChecks.run (CommandOptions.verbose commandOptions)	>> System.Exit.exitWith System.Exit.ExitSuccess--			extendedRegExCharPerformance, readExtendedRegExCharFromFile, assertFromFile, assertPosixFromFile, setExtendedRegExChar :: String -> CommandLineAction-			extendedRegExCharPerformance s commandOptions	= (-				uncurry $ Test.Performance.ExtendedRegEx.run (CommandOptions.executionOptions commandOptions)-			 ) (readCommandArg s)	>> System.Exit.exitWith System.Exit.ExitSuccess--			readExtendedRegExCharFromFile s commandOptions	= ((head . dropWhile null . lines) `fmap` readFile s) >>= (`setExtendedRegExChar` commandOptions)--			assertFromFile fileName commandOptions	= do-				failedTests	<- Test.Assert.RegExOptsChar.findFailures (CommandOptions.compilationOptions commandOptions) (CommandOptions.executionOptions commandOptions) `fmap` Test.Assert.RegExOptsChar.readTests fileName--				if null failedTests-					then System.Exit.exitWith System.Exit.ExitSuccess-					else do-						mapM_ print failedTests--						System.Exit.exitWith $ System.Exit.ExitFailure 2--			assertPosixFromFile fileName _	= do-				failedTests	<- Test.Assert.RegExOptsChar.findFailuresPosix `fmap` Test.Assert.RegExOptsChar.readTests fileName--				if null failedTests-					then System.Exit.exitWith System.Exit.ExitSuccess-					else do-						mapM_ print failedTests--						System.Exit.exitWith $ System.Exit.ExitFailure 2--			setExtendedRegExChar s commandOptions	= case CommandOptions.extendedRegExChar commandOptions of-				Just extendedRegExChar	-> fail $ "The regex has already been defined as /" ++ show extendedRegExChar ++ "/"-				_			-> return {-to IO-monad-} commandOptions { CommandOptions.extendedRegExChar = Just $ readCommandArg s }--			abortTrialRepetitionsOnInherentFailure, {-abortTrialRepetitionsOnZeroConsumption, bypassInputDataForLiberalConsumer,-} catchIncompatibleAnchors, checkExistenceOfInelasticTail, checkForUnconsumableData, moderateGreed, permitReorderingOfAlternatives, preferAlternativesWhichFeedTheGreedy, preferAlternativesWhichMimickUnrolling, preferFewerRepeatedAlternatives, unrollRepeatedSingletonAlternative, useFirstMatchAmongAlternatives, validateMinConsumptionOfAlternatives :: CommandOptions.ExecutionOptionsMutator-			abortTrialRepetitionsOnInherentFailure s e	= e { RegExDot.ExecutionOptions.abortTrialRepetitionsOnInherentFailure = readCommandArg s }---			abortTrialRepetitionsOnZeroConsumption s e	= e { RegExDot.ExecutionOptions.abortTrialRepetitionsOnZeroConsumption = readCommandArg s }---			bypassInputDataForLiberalConsumer s e		= e { RegExDot.ExecutionOptions.bypassInputDataForLiberalConsumer = readCommandArg s }-			catchIncompatibleAnchors s e			= e { RegExDot.ExecutionOptions.catchIncompatibleAnchors = readCommandArg s }-			checkExistenceOfInelasticTail s e		= e { RegExDot.ExecutionOptions.checkExistenceOfInelasticTail = readCommandArg s }-			checkForUnconsumableData s e			= e { RegExDot.ExecutionOptions.checkForUnconsumableData = readCommandArg s }-			moderateGreed s e				= e { RegExDot.ExecutionOptions.moderateGreed = readCommandArg s }-			permitReorderingOfAlternatives s e		= e { RegExDot.ExecutionOptions.permitReorderingOfAlternatives = readCommandArg s }-			preferAlternativesWhichFeedTheGreedy s e	= e { RegExDot.ExecutionOptions.preferAlternativesWhichFeedTheGreedy = readCommandArg s }-			preferAlternativesWhichMimickUnrolling s e	= e { RegExDot.ExecutionOptions.preferAlternativesWhichMimickUnrolling = readCommandArg s }-			preferFewerRepeatedAlternatives s e		= e { RegExDot.ExecutionOptions.preferFewerRepeatedAlternatives = readCommandArg s }-			unrollRepeatedSingletonAlternative s e		= e { RegExDot.ExecutionOptions.unrollRepeatedSingletonAlternative = readCommandArg s }-			useFirstMatchAmongAlternatives s e		= e { RegExDot.ExecutionOptions.useFirstMatchAmongAlternatives = readCommandArg s }-			validateMinConsumptionOfAlternatives s e	= e { RegExDot.ExecutionOptions.validateMinConsumptionOfAlternatives = readCommandArg s }--			complyStrictlyWithPosix :: CommandOptions.CompilationOptionsMutator-			complyStrictlyWithPosix s e	= e { RegExDot.CompilationOptions.complyStrictlyWithPosix = readCommandArg s }--			setCompilationOption :: CommandOptions.CompilationOptionsMutator -> String -> CommandLineAction-			setCompilationOption compilationOptionsMutator s	= return {-to IO-monad-} . CommandOptions.setCompilationOption compilationOptionsMutator s--			setExecutionOption :: CommandOptions.ExecutionOptionsMutator -> String -> CommandLineAction-			setExecutionOption executionOptionsMutator s	= return {-to IO-monad-} . CommandOptions.setExecutionOption executionOptionsMutator s--	args	<- System.Environment.getArgs----	G.getOpt :: G.ArgOrder CommandLineAction -> [G.OptDescr Action] -> [String] -> ([Action], [String], [String])-	case G.getOpt G.RequireOrder optDescrList args of-		(commandLineActions, nonOptions, [])	-> do-			commandOptions	<- Data.List.foldl' (>>=) (return {-to IO-monad-} ToolShed.Defaultable.defaultValue) commandLineActions	-- Sequentially transform the 'CommandOptions', using 'CommandLineAction's corresponding to the specified command-line flags.--			Grep.grep commandOptions nonOptions	-- Perform the requested match, against the list of input-data files.-		(_, _, errors)	-> System.IO.Error.ioError . System.IO.Error.userError $ concat errors ++ usageMessage	-- Throw.-
− src/RegExChar/ExtendedRegExChar.hs
@@ -1,207 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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@]	An 'RegExDot.RegEx.ExtendedRegEx', which has been specialised for 'Char', to create a tradition non-polymorphic /regex/.--}--module RegExChar.ExtendedRegExChar(--- * Types--- ** Type-synonyms-	ExtendedRegExChar(..),-	InputData,--- * Functions--- ** Operators-	(+~),-	(=~),-	(/~)-) where--import Prelude hiding ((<$>), (<*>))	-- The "Prelude" from 'base-4.8' exports this symbol.-import			Control.Applicative((<$>), (<*>))-import qualified	Data.List-import qualified	RegExChar.MetaChar		as MetaChar-import qualified	RegExDot.Anchor-import qualified	RegExDot.Consumer-import			RegExDot.DSL((<~>), (-:))-import qualified	RegExDot.RegEx-import qualified	RegExDot.RegExOpts-import qualified	RegExDot.Repeatable-import qualified	Text.ParserCombinators.Parsec	as Parsec-import			Text.ParserCombinators.Parsec((<?>), (<|>))-import qualified	ToolShed.Data.Pair-import qualified	ToolShed.SelfValidate--infix 4 +~, =~, /~	-- Same as (==) & (/=).---- | Specialise a 'RegExDot.RegEx.ExtendedRegEx' for 'Char', & encapsulate it to permit tailored instance-declarations.-data ExtendedRegExChar	= MkExtendedRegExChar {-	hasNonCapturingTopLevelAlternatives	:: Bool,	-- ^ The string from which a 'RegExDot.RegEx.ExtendedRegEx' is read, may, if data-capture isn't required, omit explicit delimiters around top-level 'RegExDot.RegEx.Alternatives'.-	extendedRegEx				:: RegExDot.RegEx.ExtendedRegEx Char-} deriving Eq---- | Abbreviation.-type InputData	= RegExDot.RegEx.InputData Char--instance ToolShed.SelfValidate.SelfValidator ExtendedRegExChar	where-	getErrors MkExtendedRegExChar {-		hasNonCapturingTopLevelAlternatives	= hasNonCapturingTopLevelAlternatives',-		extendedRegEx				= extendedRegEx'-	}-		| not $ ToolShed.SelfValidate.isValid extendedRegEx'	= ToolShed.SelfValidate.getErrors extendedRegEx'-		| otherwise						= ToolShed.SelfValidate.extractErrors [-			(hasNonCapturingTopLevelAlternatives' && any (not . RegExDot.RegEx.isCaptureGroup . RegExDot.Repeatable.base) (RegExDot.RegEx.concatenation extendedRegEx'), "Invalid NonCapturingTopLevelAlternatives.")-		]--instance RegExDot.Consumer.Consumer ExtendedRegExChar	where-	consumptionProfile	= RegExDot.Consumer.consumptionProfile . extendedRegEx-	starHeight		= RegExDot.Consumer.starHeight . extendedRegEx--instance RegExDot.RegEx.ShortcutExpander Char	where-	expand c	= error $ "RegExDot.RegEx.ShortcutExpander.expand RegExChar.ExtendedRegExChar:\tunrecognised shortcut '" ++ show c ++ "'."--instance Read ExtendedRegExChar	where-	readsPrec _ s-		| s == reverse RegExDot.Anchor.tokens	= [-			(-				MkExtendedRegExChar {-					hasNonCapturingTopLevelAlternatives	= False,-					extendedRegEx				= (Just RegExDot.Anchor.Bow, Just RegExDot.Anchor.Stern) <~> []-				},-				""-			)-		] -- The order of adjacent zero-width assertions is irrelevant.-		| otherwise			= let-			extendedRegExCharParser :: Parsec.Parser ExtendedRegExChar-			extendedRegExCharParser	= reduce {-correct prior assumption-} <$> alternativesParser {-assume non-capturing top-level Alternatives-} where-				reduce :: RegExDot.RegEx.Alternatives Char -> ExtendedRegExChar-				reduce alternatives-					| RegExDot.RegEx.isSingletonAlternatives alternatives	= MkExtendedRegExChar False . head $ RegExDot.RegEx.deconstructAlternatives alternatives-					| otherwise						= MkExtendedRegExChar True $ RegExDot.Anchor.unanchored <~> RegExDot.RegEx.CaptureGroup alternatives -: []	-- Infer non-capturing top-level 'RegExDot.RegEx.Alternatives' from the presence of 'RegExDot.RegEx.alternativeExtendedRegExSeparatorToken's.--				alternativesParser :: Parsec.Parser (RegExDot.RegEx.Alternatives Char)-				alternativesParser	= RegExDot.RegEx.MkAlternatives <$> extendedRegExParser `Parsec.sepBy1` (Parsec.char RegExDot.RegEx.alternativeExtendedRegExSeparatorToken <?> "RegExDot.RegEx.alternativeExtendedRegExSeparatorToken " ++ show RegExDot.RegEx.alternativeExtendedRegExSeparatorToken)	where-					extendedRegExParser :: Parsec.Parser (RegExDot.RegEx.ExtendedRegEx Char)-					extendedRegExParser	= do-						maybeBowAnchor			<- Parsec.option Nothing {-default-} $ (Parsec.char RegExDot.Anchor.bowToken <?> "RegExDot.Anchor.bowToken " ++ show RegExDot.Anchor.bowToken) >> return {-to ParsecT-monad-} (Just RegExDot.Anchor.Bow)-						repeatableRequirementList	<- repeatableRequirementListParser--						(-							do-								repeatableCaptureGroup	<- RegExDot.Repeatable.repeatableParser . RegExDot.RegEx.CaptureGroup =<< uncurry Parsec.between (-									ToolShed.Data.Pair.mirror Parsec.char RegExDot.RegEx.captureGroupDelimiters-								 ) alternativesParser {-recurse-} <?> "RegExDot.RegEx.captureGroupDelimiters " ++ show RegExDot.RegEx.captureGroupDelimiters--								extendedRegEx'		<- extendedRegExParser	-- Recurse.--								return {-to ParsecT-monad-} $ RegExDot.RegEx.transformExtendedRegEx ((repeatableRequirementList ++) . (repeatableCaptureGroup :)) extendedRegEx' { RegExDot.RegEx.bowAnchor = maybeBowAnchor }-						 ) <|> (-							do-								maybeSternAnchor	<- Parsec.option Nothing {-default-} $ (Parsec.char RegExDot.Anchor.sternToken <?> "RegExDot.Anchor.sternToken " ++ show RegExDot.Anchor.sternToken) >> return {-to ParsecT-monad-} (Just RegExDot.Anchor.Stern)--								return {-to ParsecT-monad-} RegExDot.RegEx.MkExtendedRegEx {-									RegExDot.RegEx.bowAnchor	= maybeBowAnchor,-									RegExDot.RegEx.concatenation	= repeatableRequirementList,-									RegExDot.RegEx.sternAnchor	= maybeSternAnchor-								}-						 )-						where-							repeatableRequirementListParser :: Parsec.Parser (RegExDot.RegEx.Concatenation Char)-							repeatableRequirementListParser	= Parsec.choice [-								Parsec.try . Parsec.lookAhead $ (-									Parsec.char RegExDot.Anchor.sternToken <?> "RegExDot.Anchor.sternToken " ++ show RegExDot.Anchor.sternToken-								) >> (-									(-										Parsec.eof >> return {-to ParsecT-monad-} []-									) <|> (-										Parsec.oneOf [RegExDot.RegEx.alternativeExtendedRegExSeparatorToken, snd RegExDot.RegEx.captureGroupDelimiters] >> return {-to ParsecT-monad-} []-									)-								),-								(:) <$> (-									MetaChar.metaCharParser >>= RegExDot.Repeatable.repeatableParser . RegExDot.RegEx.Require . MetaChar.deconstruct-								) <*> repeatableRequirementListParser, {-recurse-}-								return {-to ParsecT-monad-} []-							 ]--		in (-			error . ("readsPrec RegExChar.ExtendedRegExChar:\tparse-error; " ++) . show	-- Failure to parse.-		) `either` (-			\pair@(extendedRegExChar, _)	-> if ToolShed.SelfValidate.isValid extendedRegExChar-				then [pair]-				else error $ ToolShed.SelfValidate.getFirstError extendedRegExChar	-- Parsed OK, but invalid.-		) $ Parsec.parse (-			(,) <$> extendedRegExCharParser <*> Parsec.getInput-		) "ExtendedRegExChar" s--instance Show ExtendedRegExChar	where-	showsPrec _ MkExtendedRegExChar {-		hasNonCapturingTopLevelAlternatives	= hasNonCapturingTopLevelAlternatives',-		extendedRegEx				= RegExDot.RegEx.MkExtendedRegEx {-			RegExDot.RegEx.bowAnchor	= maybeBowAnchor,-			RegExDot.RegEx.concatenation	= concatenation',-			RegExDot.RegEx.sternAnchor	= maybeSternAnchor-		}-	} = RegExDot.RegEx.showsMaybeAnchor maybeBowAnchor . foldl (.) (showString "") (-		(-			let-				showAlternatives :: RegExDot.RegEx.Alternatives Char -> [ShowS]-				showAlternatives	= Data.List.intersperse (showChar RegExDot.RegEx.alternativeExtendedRegExSeparatorToken) . map (shows . MkExtendedRegExChar False) . RegExDot.RegEx.deconstructAlternatives-			in if hasNonCapturingTopLevelAlternatives'-				then map (-					\repeatablePattern	-> case RegExDot.Repeatable.base repeatablePattern of-						RegExDot.RegEx.CaptureGroup alternatives	-> foldr (.) (showString "") $ showAlternatives alternatives-						_						-> error $ "Show RegExChar.ExtendedRegExChar: unexpected " ++ show repeatablePattern-				)-				else map (-					\repeatablePattern	-> (-						case RegExDot.Repeatable.base repeatablePattern of-							RegExDot.RegEx.Require meta			-> shows $ MetaChar.MkMetaChar meta-							RegExDot.RegEx.CaptureGroup alternatives	-> showChar (-								fst RegExDot.RegEx.captureGroupDelimiters-							 ) . foldr (.) (-								showChar $ snd RegExDot.RegEx.captureGroupDelimiters	-- Initial value.-							 ) (-								showAlternatives alternatives-							 )-					) . RegExDot.Repeatable.showSuffix repeatablePattern-				)-		 ) concatenation'-	 ) . RegExDot.RegEx.showsMaybeAnchor maybeSternAnchor---- | A veneer over the underlying polymorphic operator, 'RegExDot.RegEx.+~'.-(+~)-	:: InputData						-- ^ The input-data string.-	-> RegExDot.RegExOpts.RegExOpts ExtendedRegExChar	-- ^ The match-options, parameterised by the regex-specification.-	-> RegExDot.RegEx.Result Char-inputData +~ regExOpts	= inputData RegExDot.RegEx.+~ fmap extendedRegEx regExOpts	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.---- | A veneer over the underlying polymorphic operator, 'RegExDot.RegEx.=~'.-(=~)-	:: InputData						-- ^ The input-data string.-	-> RegExDot.RegExOpts.RegExOpts ExtendedRegExChar	-- ^ The match-options, parameterised by the regex-specification.-	-> Bool-inputData =~ regExOpts	= inputData RegExDot.RegEx.=~ fmap extendedRegEx regExOpts	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.---- | Pattern-mismatch operator.-(/~)-	:: InputData						-- ^ The input-data string.-	-> RegExDot.RegExOpts.RegExOpts ExtendedRegExChar	-- ^ The match-options, parameterised by the regex-specification.-	-> Bool-(/~) inputData	= not . (inputData =~)-
− src/RegExChar/MetaChar.hs
@@ -1,253 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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 'RegExDot.Meta.ShortcutExpander' 'Char', to implement some of the traditional /Perl-style shortcuts/:--	[@\\d@]		=> Any 'Data.Char.isDigit'-character.--	[@\\D@]		=> Any non-'Data.Char.isDigit' character.--	[@\\s@]		=> Any 'Data.Char.isSpace'-character.--	[@\\S@]		=> Any non-'Data.Char.isSpace' character.--	[@\\w@]		=> Any 'Data.Char.isWord' letter.--	[@\\W@]		=> Any non-'Data.Char.isWord' letter.--	* Enables one to compose concise regexen, containing any 'Char' that's a member of one of these predefined sets.--	* Though 'RegExDot.Meta.Meta' is polymorphic, & the type-parameter can't be assumed to implement either 'Enum' or 'Ord',-	'Char' actually does, so this module is able to implement ranges within a /Bracket-expression/.--	* Defines specialised instances of 'Read' & 'Show', to cope with /Perl-style shortcuts/, /Posix Character-classes/ & /Bracket-expression/ range-specifications.-- [@TODO@]	Use @Environment.getLocale@. Regrettably, this returns in the "IO"-monad, & even it didn't, how does one pass that information to 'Read' ?!--}--module RegExChar.MetaChar(--- * Types---	AssociationList,---	Dictionary,--- ** Type-synonyms-	MetaChar(..),--- * Constants---	bracketExpressionRangeToken,---	posixCharacterClassDelimiters,--- * Functions---	implementPerlShortcut,-	metaCharParser,--- ** Accessors (Deconstructors)-	deconstruct-) where--import Prelude hiding ((<$>), (<*>))	-- The "Prelude" from 'base-4.8' exports this symbol.-import			Control.Applicative((<$>), (<*>))-import			Control.Arrow((***))-import qualified	Data.Char-import qualified	Data.Map-import qualified	RegExDot.BracketExpression-import qualified	RegExDot.BracketExpressionMember-import qualified	RegExDot.Consumer-import qualified	RegExDot.Meta-import qualified	RegExDot.RegEx-import qualified	RegExDot.Repeatable-import qualified	RegExDot.ShowablePredicate-import qualified	Text.ParserCombinators.Parsec	as Parsec-import			Text.ParserCombinators.Parsec((<?>))-import qualified	ToolShed.Data.Pair-import qualified	ToolShed.SelfValidate---- | Holds a mapping from an escape-sequence & the predicate via which it is implemented.-type AssociationList key	= [(key, RegExDot.ShowablePredicate.Predicate Char)]---- | Holds a mapping from an escape-sequence & the predicate via which it is implemented.-type Dictionary key		= Data.Map.Map key (RegExDot.ShowablePredicate.Predicate Char)--instance RegExDot.BracketExpressionMember.ShortcutExpander Char	where-	findPredicate shortcut	= RegExDot.ShowablePredicate.MkShowablePredicate [RegExDot.Meta.shortcutToken, shortcut] <$> shortcut `Data.Map.lookup` dictionary where-		dictionary :: Dictionary Char-		dictionary	= Data.Map.fromList $ perlShortcuts ++ invert perlShortcuts	where-			perlShortcuts :: AssociationList Char-			perlShortcuts	= [-				('d',	Data.Char.isDigit),-				('s',	Data.Char.isSpace),-				('w',	\c -> ($ c) `any` [Data.Char.isAlphaNum, (== '_')])-			 ]--			invert :: AssociationList Char -> AssociationList Char-			invert	= map (Data.Char.toUpper *** (not .))--instance RegExDot.Meta.ShortcutExpander Char	where-	expand c	= case RegExDot.BracketExpressionMember.findPredicate c of-		Just showablePredicate	-> RegExDot.Meta.Predicate showablePredicate-		_			-> RegExDot.Meta.Literal c---- | A specialised instance, encapsulated to permit tailored instance-declarations.-newtype MetaChar	= MkMetaChar (RegExDot.Meta.Meta Char)	deriving Eq---- | Accessor.-deconstruct :: MetaChar -> RegExDot.Meta.Meta Char-deconstruct (MkMetaChar metaChar)	= metaChar--instance ToolShed.SelfValidate.SelfValidator MetaChar	where-	getErrors	= ToolShed.SelfValidate.getErrors . deconstruct--instance RegExDot.Consumer.Consumer MetaChar	where-	consumptionProfile	= RegExDot.Consumer.consumptionProfile . deconstruct-	starHeight		= RegExDot.Consumer.starHeight . deconstruct---- | Builds a parser of traditional regex-syntax, which understands 'Char'-specific concepts like /Perl-style shortcuts/ & /Posix Character-classes/.-metaCharParser :: Parsec.Parser MetaChar-metaCharParser	= MkMetaChar <$> Parsec.choice [-	(Parsec.char RegExDot.Meta.anyToken <?> "RegExDot.Meta.anyToken " ++ show RegExDot.Meta.anyToken) >> return {-to ParsecT-monad-} RegExDot.Meta.Any,-	(Parsec.char RegExDot.Meta.shortcutToken <?> "RegExDot.Meta.shortcutToken " ++ show RegExDot.Meta.shortcutToken) >> RegExDot.Meta.expand <$> Parsec.anyChar,-	uncurry Parsec.between (ToolShed.Data.Pair.mirror Parsec.char RegExDot.BracketExpression.delimiterTokens) (-		do-			let-				implementPosixCharacterClass :: String -> Maybe (RegExDot.ShowablePredicate.ShowablePredicate Char)-				implementPosixCharacterClass identifier	= RegExDot.ShowablePredicate.MkShowablePredicate (-					fst posixCharacterClassDelimiters ++ identifier ++ snd posixCharacterClassDelimiters-				 ) <$> identifier `Data.Map.lookup` dictionary	where-					dictionary :: Dictionary String-					dictionary	= Data.Map.fromList $ posixCharacterClasses ++ invert posixCharacterClasses	where-						posixCharacterClasses :: AssociationList String-						posixCharacterClasses	= [-							("alnum",	Data.Char.isAlphaNum),-							("alpha",	Data.Char.isAlpha),-							("ascii",	Data.Char.isAscii),-							("blank",	(`elem` " \t")),-							("cntrl",	Data.Char.isControl),-							("digit",	Data.Char.isDigit),-							("graph",	\c	-> not $ ($ c) `any` [Data.Char.isSpace, Data.Char.isControl]),-							("lower",	Data.Char.isLower),-							("print",	Data.Char.isPrint),-							("punct",	Data.Char.isPunctuation),-							("space",	Data.Char.isSpace),-							("upper",	Data.Char.isUpper),-							("word",	\c	-> ($ c) `any` [Data.Char.isAlphaNum, (== '_')]),-							("xdigit",	Data.Char.isHexDigit)-						 ]--						invert :: AssociationList String -> AssociationList String-						invert	= map $ (RegExDot.BracketExpression.negationToken :) *** (not .)--			cTor	<- Parsec.option RegExDot.Meta.AnyOf {-default-} $ (Parsec.char RegExDot.BracketExpression.negationToken <?> "RegExDot.BracketExpression.negationToken " ++ show RegExDot.BracketExpression.negationToken) >> return {-to ParsecT-monad-} RegExDot.Meta.NoneOf--			literalBracketExpressionTerminator	<- Parsec.option [] {-default-} $ return {-to List-monad-} . RegExDot.BracketExpressionMember.Literal <$> (-				Parsec.char (snd RegExDot.BracketExpression.delimiterTokens)	<?> "Literal Bracket-expression terminator " ++ show (snd RegExDot.BracketExpression.delimiterTokens)-			 ) -- If the first item in a BracketExpression (or negated BracketExpression) is the terminator-token, then it is treated as a 'RegExDot.BracketExpressionMember.Literal'.--			cTor . (literalBracketExpressionTerminator ++) <$> Parsec.many {-potentially zero-} (-				Parsec.choice [-					(-						do-							_	<- Parsec.char RegExDot.Meta.shortcutToken	<?> "RegExDot.Meta.shortcutToken " ++ show RegExDot.Meta.shortcutToken-							c	<- Parsec.anyChar--							return {-to ParsecT-monad-} $ case RegExDot.BracketExpressionMember.findPredicate c of-								Just showablePredicate	-> RegExDot.BracketExpressionMember.Predicate showablePredicate-								_			-> RegExDot.BracketExpressionMember.Literal c	-- Escaped literal.-					) <?> "Perl-style shortcut",-					Parsec.try (-						uncurry Parsec.between (ToolShed.Data.Pair.mirror Parsec.string posixCharacterClassDelimiters) (-							do-								identifier	<- Parsec.many1 $ Parsec.noneOf [head $ snd posixCharacterClassDelimiters]--								case implementPosixCharacterClass identifier of-									Just showablePredicate	-> return {-to ParsecT-monad-} $ RegExDot.BracketExpressionMember.Predicate showablePredicate-									_			-> Parsec.unexpected $ "MetaChar.metaCharParser:\tunrecognised Posix Character-class; " ++ show identifier-						) <?> "Posix Character-class " ++ show posixCharacterClassDelimiters-					), -- Regurgitate erroneously consumed input.-					Parsec.try (-						(-							do-								rangeStart	<- Parsec.noneOf [snd RegExDot.BracketExpression.delimiterTokens]-								_		<- Parsec.char bracketExpressionRangeToken	<?> "bracketExpressionRangeToken " ++ show bracketExpressionRangeToken-								rangeEnd	<- Parsec.noneOf [snd RegExDot.BracketExpression.delimiterTokens]--								return {-to ParsecT-monad-} . RegExDot.BracketExpressionMember.Predicate . RegExDot.ShowablePredicate.MkShowablePredicate [-									rangeStart,-									bracketExpressionRangeToken,-									rangeEnd-								 ] $ \c -> rangeStart <= c && c <= rangeEnd	-- Create custom predicate, utilising "Ord Char".-						) <?> "Bracket-expression range"-					), -- Regurgitate erroneously consumed input.-					RegExDot.BracketExpressionMember.Literal <$> Parsec.noneOf [snd RegExDot.BracketExpression.delimiterTokens]	<?> "RegExDot.BracketExpressionMember.Literal"	-- TODO: the first Char-member can be a literal ']'.-				] <?> "Bracket-expression member"-			 ) <?> "Bracket-expression member-list"-	) <?> "RegExDot.BracketExpression.delimiterTokens " ++ show RegExDot.BracketExpression.delimiterTokens,-	RegExDot.Meta.Literal <$> Parsec.noneOf RegExDot.RegEx.tokens- ]--instance Read MetaChar	where-	readsPrec _	= (-		(fail . ("readsPrec RegExChar.MetaChar:\tparse-error; " ++) . show) `either` return-	 ) . Parsec.parse (-		(,) <$> metaCharParser <*> Parsec.getInput-	 ) "MetaChar"---- | The token used to signify an ordered range of members in a /Bracket-expression/.-bracketExpressionRangeToken :: Char-bracketExpressionRangeToken	= '-'---- | The delimiters of a /Posix Character-class/.-posixCharacterClassDelimiters :: (String, String)-posixCharacterClassDelimiters	= ("[:", ":]")--instance Show MetaChar	where-	showsPrec _ (MkMetaChar RegExDot.Meta.Any)				= showChar RegExDot.Meta.anyToken-	showsPrec _ (MkMetaChar (RegExDot.Meta.Literal c))			= (-		if c `elem` [-			fst RegExDot.BracketExpression.delimiterTokens,-			fst RegExDot.Repeatable.rangeDelimiters,-			RegExDot.Repeatable.oneOrMoreToken,-			RegExDot.Repeatable.zeroOrMoreToken,-			RegExDot.Repeatable.zeroOrOneToken,-			RegExDot.Meta.anyToken,-			RegExDot.Meta.shortcutToken-		] ++ RegExDot.RegEx.tokens-			then showChar RegExDot.Meta.shortcutToken-			else id-	 ) . showChar c-	showsPrec _ (MkMetaChar (RegExDot.Meta.AnyOf bracketExpression))	= showChar (-		fst RegExDot.BracketExpression.delimiterTokens-	 ) . showString (-		foldr (-			\e	-> case e of-				RegExDot.BracketExpressionMember.Predicate showablePredicate	-> shows showablePredicate-				RegExDot.BracketExpressionMember.Literal literal		-> (-					if literal `elem` [-						bracketExpressionRangeToken,		-- CAVEAT: only unambiguously literal when at the start or end of a "BracketExpression".-						RegExDot.Meta.shortcutToken,-						snd RegExDot.BracketExpression.delimiterTokens	-- CAVEAT: only unambiguously literal when at the start of a "BracketExpression".-					]-						then showChar RegExDot.Meta.shortcutToken-						else id-				 ) . showChar literal-		) (-			showChar (snd RegExDot.BracketExpression.delimiterTokens) ""	-- Initial value.-		) bracketExpression-	 )-	showsPrec _ (MkMetaChar (RegExDot.Meta.NoneOf bracketExpression))	= showChar x . showChar RegExDot.BracketExpression.negationToken . showString xs	where (x : xs)	= show . MkMetaChar $ RegExDot.Meta.AnyOf bracketExpression-	showsPrec _ (MkMetaChar m)						= shows m-
− src/RegExChar/RegExOptsChar.hs
@@ -1,219 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances, FlexibleContexts #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--{--	Copyright (C) 2010-2015 Dr. Alistair Ward--	This program is free software: you can redistribute it and/or modify-	it under the terms of the GNU General Public License as published by-	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@]	Creates a /back-end/ implementation, conforming to <http://hackage.haskell.org/packages/archive/regex-base/latest/doc/html/Text-Regex-Base-RegexLike.html>.-- [@CAVEATS@]--	* The underlying polymorphic (in terms of the base-type of the list of input data) 'RegExDot.RegEx.ExtendedRegEx'-engine is never going to be a drop-in replacement for other /regex/-engines,-	so this standard interface has only been implemented for traditional input data-type ['Char'].--	* The standard interface requires many Haskell-extensions, but since this implementation is just a thin layer over the underlying portable polymorphic 'RegExDot.RegEx.ExtendedRegEx'-engine,-	the latter can still be used directly, where any of these extensions are unavailable.--}--module RegExChar.RegExOptsChar(--- * Types--- ** Type-synonyms-	MatchSpan,---	MatchDataSpan,-	RegExOptsChar,--- * Functions---	exciseNonCapturingTopLevelAlternatives,---	matchUntilFailure,---	toMatchDataSpanList,-	toZeroIndexedArray,--- ** Operators-	(=~)--- ** Predicates---	complyStrictlyWithPosix,---	hasNonCapturingTopLevelAlternatives-) where--import qualified	Data.Array.IArray-import qualified	RegExChar.ExtendedRegExChar	as ExtendedRegExChar-import qualified	RegExDot.CompilationOptions-import qualified	RegExDot.ConsumptionBounds-import qualified	RegExDot.DataSpan-import qualified	RegExDot.DataSpanTree-import qualified	RegExDot.ExecutionOptions-import qualified	RegExDot.RegEx-import qualified	RegExDot.RegExOpts-import qualified	RegExDot.Result-import qualified	RegExDot.Tree-import qualified	Text.Regex.Base.RegexLike	as RegexLike-import			Text.Regex.Base.Context()	-- Instance-declarations.-import qualified	ToolShed.Data.List-import qualified	ToolShed.Defaultable-import qualified	ToolShed.Options--infix 4 =~	-- Same as (==).---- | Defines a specific instance of the polymorphic base-type.-type RegExOptsChar	= RegExDot.RegExOpts.RegExOpts ExtendedRegExChar.ExtendedRegExChar---- | Convenience accessor-function.-hasNonCapturingTopLevelAlternatives :: RegExOptsChar -> Bool-hasNonCapturingTopLevelAlternatives	= ExtendedRegExChar.hasNonCapturingTopLevelAlternatives . RegExDot.RegExOpts.regEx---- | Convenience accessor-function.-complyStrictlyWithPosix :: RegExOptsChar -> Bool-complyStrictlyWithPosix	= RegExDot.CompilationOptions.complyStrictlyWithPosix . RegExDot.RegExOpts.compilationOptions--instance RegexLike.RegexOptions RegExOptsChar RegExDot.CompilationOptions.CompilationOptions RegExDot.ExecutionOptions.ExecutionOptions	where-	blankCompOpt	= ToolShed.Options.blankValue-	blankExecOpt	= ToolShed.Options.blankValue-	defaultCompOpt	= ToolShed.Defaultable.defaultValue-	defaultExecOpt	= ToolShed.Defaultable.defaultValue-	setExecOpts e r	= r { RegExDot.RegExOpts.executionOptions = e }-	getExecOpts	= RegExDot.RegExOpts.executionOptions---- Newer versions of this 'Text.Regex.Base.RegexLike.RegexMaker' have additional monadic methods, which can fail on parse-errors.-instance RegexLike.RegexMaker RegExOptsChar RegExDot.CompilationOptions.CompilationOptions RegExDot.ExecutionOptions.ExecutionOptions String	where-	makeRegexOpts c e source = RegExDot.RegExOpts.MkRegExOpts {-		RegExDot.RegExOpts.compilationOptions	= c,-		RegExDot.RegExOpts.executionOptions	= e,-		RegExDot.RegExOpts.regEx		= read source-	}---- | The offset and length of the 'RegExDot.RegEx.InputData' consumed in one 'RegExDot.RegEx.Match'.-type MatchSpan		= (RegexLike.MatchOffset, RegexLike.MatchLength)--{- |-	* The 'MatchSpan' augmented by the consumed 'ExtendedRegExChar.InputData' to which it refers.--	* Similar to 'RegExDot.DataSpan.DataSpan'.--}-type MatchDataSpan	= (ExtendedRegExChar.InputData, MatchSpan)--{- |-	* Convert the 'RegExDot.RegEx.MatchList', into the 'MatchDataSpan's required by "Text.Regex.Base.RegexLike".--	* Treat the whole 'ExtendedRegExChar.ExtendedRegExChar' as an additional implicit capture-group.--	* CAVEAT: @RegExDot.DataSpanTree.extractCaptureGroups True@ may return some 'RegExDot.DataSpan.DataSpan's containing the artificial offset @-1@ specified by Posix => don't use this as the basis for any arithmetic.--}-toMatchDataSpanList-	:: Bool-	-> RegExDot.ConsumptionBounds.DataLength	-- ^ The offset to use for zero-length match.-	-> RegExDot.RegEx.MatchList Char		-- ^ The list of matches.-	-> [MatchDataSpan]-toMatchDataSpanList _ offset []				= [RegExDot.DataSpan.empty offset]	-- The whole regex matched, but consumed nothing.-toMatchDataSpanList strictPosixCompliance _ matchList	= RegExDot.DataSpanTree.extractCaptureGroups strictPosixCompliance . return {-to List-monad-} . RegExDot.Tree.Node . return {-to List-monad-} $ RegExDot.DataSpanTree.toTreeList matchList---- | Optionally remove the 2nd element from the list, where it represents the data captured by a groups of top-level 'Alternatives', which weren't explicitly delimited & therefore are non-capturing.-exciseNonCapturingTopLevelAlternatives :: RegExOptsChar -> [MatchDataSpan] -> [MatchDataSpan]-exciseNonCapturingTopLevelAlternatives regExOptsChar-	| hasNonCapturingTopLevelAlternatives regExOptsChar	= ToolShed.Data.List.excise 1	-- The zeroeth represents the whole regex, the 1st represents the top-level non-capturing group of Alternatives, & the remainder represent explicitly delimited groups.-	| otherwise						= id---- | Convert the specified list, into a zero-indexed array.-toZeroIndexedArray :: [e] -> Data.Array.IArray.Array Int e-toZeroIndexedArray l	= Data.Array.IArray.listArray (0, pred $ length l) l--{- |-	* Repeatedly apply the 'RegExOptsChar' to the 'ExtendedRegExChar.InputData', forwarding unmatched input data to the next match-attempt, until it's all been consumed.--	* The offsets, from the start of the input data, of all matches after the first, are shifted to account for input data already consumed by previous matches.--}-matchUntilFailure-	:: RegExOptsChar		-- ^ The match-criteria.-	-> ExtendedRegExChar.InputData	-- ^ The input-data, to be consumed by repeated matching.-	-> [RegExDot.RegEx.MatchList Char]-matchUntilFailure regExOptsChar inputData	= shiftOffsets 0 $ matchUntilFailure' inputData	where-	matchUntilFailure' :: ExtendedRegExChar.InputData -> [RegExDot.RegEx.MatchList Char]-	matchUntilFailure' unmatchedInputData	= case unmatchedInputData ExtendedRegExChar.+~ regExOptsChar of	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-		(_, Just matchList, maybeSternAnchorResult)	-> matchList : if null (RegExDot.RegEx.extractDataFromMatchList matchList) then [] else matchUntilFailure' (RegExDot.RegEx.extractDataFromMatch' maybeSternAnchorResult)-		_						-> []--	shiftOffsets :: RegExDot.ConsumptionBounds.DataLength -> [RegExDot.RegEx.MatchList Char] -> [RegExDot.RegEx.MatchList Char]-	shiftOffsets offset (matchList : matchLists)	= let-		shiftedMatchList :: RegExDot.RegEx.MatchList Char-		shiftedMatchList	= RegExDot.RegEx.shiftMatchList offset matchList-	 in shiftedMatchList : shiftOffsets (RegExDot.DataSpan.after . last . RegExDot.DataSpanTree.flattenTreeList 0 $ RegExDot.DataSpanTree.toTreeList shiftedMatchList) matchLists {-recurse-}-	shiftOffsets _ _				= []--instance RegexLike.RegexLike RegExOptsChar ExtendedRegExChar.InputData	where-{- E.g.:-	("xabcdxabdxxadx" RegExOptsChar.=~ "a(b(c?))*d") :: [Text.Regex.Base.RegexLike.MatchArray]-	[array (0,2) [(0,(1,4)),(1,(2,2)),(2,(3,1))],array (0,2) [(0,(6,3)),(1,(7,1)),(2,(8,0))],array (0,1) [(0,(11,2)),(1,(-1,0))]]--}---	matchAll :: RegExOptsChar -> ExtendedRegExChar.InputData -> [RegexLike.MatchArray]-	matchAll regExOptsChar	= map (toZeroIndexedArray . map snd {-span-} . exciseNonCapturingTopLevelAlternatives regExOptsChar . toMatchDataSpanList (complyStrictlyWithPosix regExOptsChar) 0) . matchUntilFailure regExOptsChar--{- E.g.:-	("xabcdxabdxxadx" RegExOptsChar.=~ "a(b(c?))*d") :: [Text.Regex.Base.RegexLike.MatchText String]-	[array (0,2) [(0,("abcd",(1,4))),(1,("bc",(2,2))),(2,("c",(3,1)))],array (0,2) [(0,("abd",(6,3))),(1,("b",(7,1))),(2,("",(8,0)))],array (0,1) [(0,("ad",(11,2))),(1,("",(-1,0)))]]--}---	matchAllText :: RegExOptsChar -> ExtendedRegExChar.InputData -> [RegexLike.MatchText ExtendedRegExChar.InputData]-	matchAllText regExOptsChar	= map (toZeroIndexedArray . exciseNonCapturingTopLevelAlternatives regExOptsChar . toMatchDataSpanList (complyStrictlyWithPosix regExOptsChar) 0) . matchUntilFailure regExOptsChar--{- E.g.:-	("xabcdx" RegExOptsChar.=~ "a(b(c?))*d") :: Text.Regex.Base.RegexLike.MatchArray-	array (0,2) [(0,(1,4)),(1,(2,2)),(2,(3,1))]--}---	matchOnce :: RegExOptsChar -> ExtendedRegExChar.InputData -> Maybe RegexLike.MatchArray-	matchOnce regExOptsChar inputData	= (-		toZeroIndexedArray . map snd {-span-} . exciseNonCapturingTopLevelAlternatives regExOptsChar . toMatchDataSpanList (-			complyStrictlyWithPosix regExOptsChar-		) (-			RegExDot.RegEx.externalMatchLength $ RegExDot.Result.getPreMatch extendedRegExResult-		)-	 ) `fmap` RegExDot.Result.getMatchList extendedRegExResult	where-		extendedRegExResult :: RegExDot.RegEx.Result Char-		extendedRegExResult	= inputData ExtendedRegExChar.+~ regExOptsChar	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.--{- E.g.:-	("xabcdx" RegExOptsChar.=~ "a(b(c?))*d") :: (String, Text.Regex.Base.RegexLike.MatchText String, String)-	("x",array (0,2) [(0,("abcd",(1,4))),(1,("bc",(2,2))),(2,("c",(3,1)))],"x")--}---	matchOnceText :: RegExOptsChar -> ExtendedRegExChar.InputData -> Maybe (ExtendedRegExChar.InputData, MatchText ExtendedRegExChar.InputData, ExtendedRegExChar.InputData)-	matchOnceText regExOptsChar inputData	= case inputData ExtendedRegExChar.+~ regExOptsChar of	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.-		(maybeBowAnchorResult, Just matchList, maybeSternAnchorResult)	-> Just (-			RegExDot.RegEx.extractDataFromMatch' maybeBowAnchorResult,-			toZeroIndexedArray . exciseNonCapturingTopLevelAlternatives regExOptsChar $ toMatchDataSpanList (-				complyStrictlyWithPosix regExOptsChar-			) (-				RegExDot.RegEx.externalMatchLength maybeBowAnchorResult-			) matchList,-			RegExDot.RegEx.extractDataFromMatch' maybeSternAnchorResult-		 )-		_								-> Nothing--{- E.g.:-	("xabcdx" RegExOptsChar.=~ "a(b(c?))*d") :: Bool-	True--}---	matchTest :: RegExOptsChar -> ExtendedRegExChar.InputData -> Bool-	matchTest	= flip (ExtendedRegExChar.=~)	-- CAVEAT: <http://hackage.haskell.org/trac/haskell-prime/wiki/QualifiedOperators>.--{- |-	* Match-operator.--	* The polymorphic return-type is resolved by the caller's "RegexLike.RegexContext".--}-(=~) :: RegexLike.RegexContext RegExOptsChar ExtendedRegExChar.InputData target-	=> ExtendedRegExChar.InputData	-- ^ The input data.-	-> String			-- ^ The string from which to read the regex-specification.-	-> target			-- ^ The polymorphic return-type.-inputData =~ s	= (RegexLike.makeRegex s :: RegExOptsChar) `RegexLike.match` inputData-