regex-base (empty) → 0.71
raw patch · 7 files changed
+594/−0 lines, 7 filesdep +basebuild-type:Customsetup-changed
Dependencies added: base
Files
- LICENSE +31/−0
- Setup.hs +6/−0
- Text/Regex/Base.hs +51/−0
- Text/Regex/Base/Context.hs +245/−0
- Text/Regex/Base/Impl.hs +58/−0
- Text/Regex/Base/RegexLike.hs +158/−0
- regex-base.cabal +45/−0
+ LICENSE view
@@ -0,0 +1,31 @@+The Glasgow Haskell Compiler License++Copyright 2004, The University Court of the University of Glasgow. +All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- Neither name of the University nor the names of its contributors may be+used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF+GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH+DAMAGE.
+ Setup.hs view
@@ -0,0 +1,6 @@+#!/usr/bin/env runhaskell++-- I usually compile this with "ghc --make -o setup Setup.hs"++import Distribution.Simple(defaultMain)+main = defaultMain
+ Text/Regex/Base.hs view
@@ -0,0 +1,51 @@+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+-----------------------------------------------------------------------------+-- |+--+-- Module : Text.Regex.Base+-- Copyright : (c) Chris Kuklewicz 2006+-- License : BSD-style (see the file LICENSE)+-- +-- Maintainer : libraries@haskell.org, textregexlazy@personal.mightyreason.com+-- Stability : experimental+-- Portability : non-portable (MPTC+FD)+--+-- Classes and instances for Regex matching.+--+-- +-- This module merely imports and re-exports the common part of the new+-- api: "Text.Regex.Base.RegexLike" and "Text.Regex.Base.Context".+-- +-- To see what result types the instances of RegexContext can produce,+-- please read the "Text.Regex.Base.Context" haddock documentation.+-- +-- This does not provide any of the backends, just the common interface+-- they all use. The modules which provide the backends and their cabal+-- packages are:+-- +-- * @Text.Regex.Posix@ from regex-posix+-- +-- * @Text.Regex@ from regex-compat (uses regex-posix)+-- +-- * @Text.Regex.Parsec@ from regex-parsec+-- +-- * @Text.Regex.DFA@ from regex-dfa+-- +-- * @Text.Regex.PCRE@ from regex-pcre+-- +-- * @Test.Regex.TRE@ from regex-tre+-- +-- In fact, just importing one of the backends is adequate, you do not+-- also need to import this module.+-- +-- TODO: Copy Example*hs files into this haddock comment+-----------------------------------------------------------------------------++module Text.Regex.Base (+ -- | RegexLike defines classes and type, and 'Extract' instances+ module Text.Regex.Base.RegexLike+ -- | Context only exports instances for 'RegexContext'+ ,module Text.Regex.Base.Context) where++import Text.Regex.Base.RegexLike+import Text.Regex.Base.Context
+ Text/Regex/Base/Context.hs view
@@ -0,0 +1,245 @@+{-# OPTIONS_GHC -fglasgow-exts #-}+{-|++Module : Text.Regex.Base.Context+Copyright : (c) Chris Kuklewicz 2006+License : BSD-style (see the file LICENSE)++Maintainer : libraries@haskell.org, textregexlazy@personal.mightyreason.com+Stability : experimental+Portability : non-portable (MPTC+FD)++This is a module of instances of 'RegexContext'. Nothing else is+exported. These work for all the front ends and backends+interchangably. These instances are important because they provide+the different results that can be gotten from a match or matchM+operation (often via the @=~@ and @=~~@ operators). The name is Context+because they are context dependent: use them in a context that expects+an Int and you get a count of matches, use them in a Bool context and+get True if there is a match, etc.++@ +type MatchArray = Array Int (MatchOffset, MatchLength)+type MatchText source = Array Int (source, (MatchOffset, MatchLength))+@++These are for the first match:++(@ RegexLike a b => RegexContext a b Bool @) :+ Whether there is any match or not++(@ RegexLike a b => RegexContext a b () @) :+ Useful using @=~~@ in a monad, since failure to match is via 'fail'++(@ RegexLike a b => RegexContext a b (MatchOffset,MatchLength) @) :+ This returns the initial index and length of the whole match.+ Starting at (-1) indicates failure to match.++(@ RegexLike a b => RegexContext a b b @) :+ This returns the text of the whole match.+ It will return 'empty' from 'Extract' if there is no match.+ These are defined in other modules, but documented here for convenience.++(@ RegexLike a b => RegexContext a b MatchArray @) :+ Where each sub-part the match starts and its length.+ Starting at (-1) indicates unused.++(@ RegexLike a b => RegexContext a b (Array Int b) @) :+ The text of each sub-part of the match.+ Unused matches are 'empty' (defined via 'Extract')++(@ RegexLike a b => RegexContext a b (b, MatchText b, b) @) :+ The text before the match, the details of the match, and the text after the match++(@ RegexLike a b => RegexContext a b (b, b, b) @) :+ The text before the match, the text of the match, the text after the match++(@ RegexLike a b => RegexContext a b (b, b, b, [b]) @) :+ The text before the match, the text of the match, the text after the match, and the text of the 1st and higher sub-parts of the match. This is the same return value as used in Text.Regex.++(@ RegexLike a b => RegexContext a b (MatchResult b) @) :+ The 'MatchResult' structure for the match.++These instances are for all the matches (non-overlapping):++(@ RegexLike a b => RegexContext a b Int @) :+ The number of matches++These instances similar to the single match ones above, but in a List:++(@ RegexLike a b => RegexContext a b [(MatchOffset, MatchLength)] @) :++(@ RegexLike a b => RegexContext a b [b] @) :+ As a policy, I chose [b] to be the list of whole text of each match.++(@ RegexLike a b => RegexContext a b [MatchArray] @) :++(@ RegexLike a b => RegexContext a b [Array Int b] @) :++(@ RegexLike a b => RegexContext a b [MatchText b] @) :++(@ RegexLike a b => RegexContext a b [[b]] @) :+ This is the list of the list of the text of the sub-part of each match.+ Unused matches are 'empty' (defined via 'Extract')++-}++module Text.Regex.Base.Context() where++import Data.Array(Array,(!),elems,listArray)+import Data.Maybe(maybe)+import Text.Regex.Base.RegexLike(RegexLike(..),RegexContext(..)+ ,MatchResult(..),Extract(empty),MatchOffset,MatchLength,MatchArray,MatchText)++{-+-- Get the ByteString type for mood/doom+import Data.ByteString(ByteString)+-- Get the Regex types for the mood/doom workaround+import qualified Text.Regex.Lib.WrapPosix as R1(Regex)+import qualified Text.Regex.Lib.WrapPCRE as R2(Regex)+import qualified Text.Regex.Lib.WrapLazy as R3(Regex)+import qualified Text.Regex.Lib.WrapDFAEngine as R4(Regex)+-- Get the RegexLike instances+import Text.Regex.Lib.StringPosix()+import Text.Regex.Lib.StringPCRE()+import Text.Regex.Lib.StringLazy()+import Text.Regex.Lib.StringDFAEngine()+import Text.Regex.Lib.ByteStringPosix()+import Text.Regex.Lib.ByteStringPCRE()+import Text.Regex.Lib.ByteStringLazy()+import Text.Regex.Lib.ByteStringDFAEngine()+-}+{-++mood :: (RegexLike a b) => a -> b -> b+{-# INLINE mood #-}+mood r s = case matchOnceText r s of+ Nothing -> empty+ Just (_,ma,_) -> fst (ma!0)++doom :: (RegexLike a b,Monad m) => a -> b -> m b+{-# INLINE doom #-}+doom = actOn (\(_,ma,_)->fst (ma!0))++{- These run afoul of various restrictions if I say+ "instance RegexContext a b b where"+ so I am listing these cases explicitly+-}++instance RegexContext R1.Regex String String where match = mood; matchM = doom+instance RegexContext R2.Regex String String where match = mood; matchM = doom+instance RegexContext R3.Regex String String where match = mood; matchM = doom+instance RegexContext R4.Regex String String where match = mood; matchM = doom+instance RegexContext R1.Regex ByteString ByteString where match = mood; matchM = doom+instance RegexContext R2.Regex ByteString ByteString where match = mood; matchM = doom+instance RegexContext R3.Regex ByteString ByteString where match = mood; matchM = doom+instance RegexContext R4.Regex ByteString ByteString where match = mood; matchM = doom+-}+++nullArray :: Array Int a+{-# INLINE nullArray #-}+nullArray = listArray (1,0) []++nullFail :: (RegexContext regex source [target],Monad m) => regex -> source -> m [target]+{-# INLINE nullFail #-}+nullFail r s = case match r s of+ [] -> regexFailed+ xs -> return xs++regexFailed :: (Monad m) => m b+{-# INLINE regexFailed #-}+regexFailed = fail $ "regex failed to match"++actOn :: (RegexLike r s,Monad m) => ((s,MatchText s,s)->t) -> r -> s -> m t+{-# INLINE actOn #-}+actOn f r s = case matchOnceText r s of+ Nothing -> regexFailed+ Just preMApost -> return (f preMApost)++-- ** Instances based on matchTest ()++instance (RegexLike a b) => RegexContext a b Bool where + match = matchTest+ matchM r s = case match r s of+ False -> regexFailed+ True -> return True++instance (RegexLike a b) => RegexContext a b () where+ match _ _ = ()+ matchM r s = case matchTest r s of+ False -> regexFailed+ True -> return ()++-- ** Instance based on matchCount++instance (RegexLike a b) => RegexContext a b Int where+ match = matchCount+ matchM r s = case match r s of+ 0 -> regexFailed+ x -> return x++-- ** Instances based on matchOnce,matchOnceText++instance (RegexLike a b) => RegexContext a b (MatchOffset,MatchLength) where + match r s = maybe (-1,0) (!0) (matchOnce r s)+ matchM r s = maybe regexFailed (return.(!0)) (matchOnce r s)++instance (RegexLike a b) => RegexContext a b MatchArray where + match r s = maybe nullArray id (matchOnce r s)+ matchM r s = maybe regexFailed return (matchOnce r s)++instance (RegexLike a b) => RegexContext a b (b,MatchText b,b) where + match r s = maybe (s,nullArray,empty) id (matchOnceText r s)+ matchM r s = maybe regexFailed return (matchOnceText r s)++instance (RegexLike a b) => RegexContext a b (Array Int b) where + match r s = maybe nullArray id (matchM r s)+ matchM = actOn (\(_,ma,_) -> fmap fst ma)++instance (RegexLike a b) => RegexContext a b (b,b,b) where + match r s = maybe (s,empty,empty) id (matchM r s)+ matchM = actOn (\(pre,ma,post) -> let ((whole,_):_) = elems ma+ in (pre,whole,post))++instance (RegexLike a b) => RegexContext a b (b,b,b,[b]) where + match r s = maybe (s,empty,empty,[]) id (matchM r s)+ matchM = actOn (\(pre,ma,post) -> let ((whole,_):subs) = elems ma+ in (pre,whole,post,map fst subs))++instance (RegexLike a b) => RegexContext a b (MatchResult b) where + match r s = maybe (MR {mrBefore = s,mrMatch = empty,mrAfter = empty+ ,mrSubs = nullArray,mrSubList = []}) id (matchM r s)+ matchM = actOn (\(pre,ma,post) -> + let ((whole,_):subs) = elems ma+ in MR { mrBefore = pre+ , mrMatch = whole+ , mrAfter = post+ , mrSubs = fmap fst ma+ , mrSubList = tail (map fst subs) })++-- ** Instances based on matchAll,matchAllText++instance (RegexLike a b) => RegexContext a b [MatchArray] where+ match = matchAll+ matchM = nullFail++instance (RegexLike a b) => RegexContext a b [MatchText b] where+ match = matchAllText+ matchM = nullFail+ +instance (RegexLike a b) => RegexContext a b [(MatchOffset,MatchLength)] where+ match r s = [ ma!0 | ma <- matchAll r s ]+ matchM = nullFail++instance (RegexLike a b) => RegexContext a b [b] where+ match r s = [ fst (ma!0) | ma <- matchAllText r s ]+ matchM = nullFail++instance (RegexLike a b) => RegexContext a b [Array Int b] where+ match r s = [ fmap fst ma | ma <- matchAllText r s ]+ matchM = nullFail++instance (RegexLike a b) => RegexContext a b [[b]] where+ match r s = [ map fst (elems ma) | ma <- matchAllText r s ]+ matchM = nullFail
+ Text/Regex/Base/Impl.hs view
@@ -0,0 +1,58 @@+-----------------------------------------------------------------------------+-- |+-- Module : Text.Regex.Impl+-- Copyright : (c) Chris Kuklewicz 2006+-- License : BSD-style (see the file LICENSE)+-- +-- Maintainer : libraries@haskell.org, textregexlazy@personal.mightyreason.com+-- Stability : experimental+-- Portability : non-portable (Text.Regex.Base needs MPTC+FD)+-- +-- Helper functions for defining certain instances of+-- RegexContext. These help when defining instances of RegexContext+-- with repeated types:+-- +-- @+-- instance (RegexLike regex source) => RegexContext regex source source where+-- @+-- +-- runs into overlapping restrictions. To avoid this I have each backend+-- define, for its own Regex type:+-- +-- @+-- instance RegexContext Regex String String where+-- match = polymatch+-- matchM = polymatchM+-- @+-- +-- @+-- instance RegexContext Regex ByteString ByteString where+-- match = polymatch+-- matchM = polymatchM+-- @+-------------------------------------------------------------------------------++module Text.Regex.Base.Impl(polymatch,polymatchM) where++import Text.Regex.Base+import Data.Array((!))++regexFailed :: (Monad m) => m b+{-# INLINE regexFailed #-}+regexFailed = fail $ "regex failed to match"++actOn :: (RegexLike r s,Monad m) => ((s,MatchText s,s)->t) -> r -> s -> m t+{-# INLINE actOn #-}+actOn f r s = case matchOnceText r s of+ Nothing -> regexFailed+ Just preMApost -> return (f preMApost)++polymatch :: (RegexLike a b) => a -> b -> b+{-# INLINE polymatch #-}+polymatch r s = case matchOnceText r s of+ Nothing -> empty+ Just (_,ma,_) -> fst (ma!0)++polymatchM :: (RegexLike a b,Monad m) => a -> b -> m b+{-# INLINE polymatchM #-}+polymatchM = actOn (\(_,ma,_)->fst (ma!0))
+ Text/Regex/Base/RegexLike.hs view
@@ -0,0 +1,158 @@+{-# OPTIONS_GHC -fglasgow-exts #-}+-----------------------------------------------------------------------------+-- |+-- Module : Text.Regex.Base.RegexLike+-- Copyright : (c) Chris Kuklewicz 2006+-- License : BSD-style (see the file LICENSE)+-- +-- Maintainer : libraries@haskell.org, textregexlazy@personal.mightyreason.com+-- Stability : experimental+-- Portability : non-portable (MPTC+FD)+--+-- Classes and instances for Regex matching.+--+-- +-- All the classes are declared here, and some common type aliases, and+-- the MatchResult data type.+-- +-- The only instances here are for Extract String and Extract ByteString.+-- There are no data values. The 'RegexContext' instances are in+-- "Text.Regex.Base.Context", except for ones which run afoul of a+-- repeated variable (RegexContext regex a a), which are defined in each+-- modules' String and ByteString modules.+-----------------------------------------------------------------------------++module Text.Regex.Base.RegexLike (+ -- ** Type aliases+ MatchOffset,+ MatchLength,+ MatchArray,+ MatchText,+ -- ** Data types+ MatchResult(..),+ -- ** Classes+ RegexOptions(..),+ RegexMaker(..),+ RegexLike(..),+ RegexContext(..),+ Extract(..),+ ) where++import Data.Array(Array,(!))+import Data.Maybe(isJust)+import Data.ByteString(ByteString)+import qualified Data.ByteString as B (take,drop,empty)++-- | 0 based index from start of source, or (-1) for unused+type MatchOffset = Int+-- | non-negative length of a match+type MatchLength = Int+-- | 0 based array, with 0th index indicating the full match. If the+-- full match location is not available, represent as (0,0).+type MatchArray = Array Int (MatchOffset,MatchLength)+type MatchText source = Array Int (source,(MatchOffset,MatchLength))+++-- | This is the same as the type from JRegex.+data MatchResult a = MR {+ mrBefore :: a,+ mrMatch :: a,+ mrAfter :: a,+ mrSubList :: [a],+ mrSubs :: Array Int a+}++----------------+-- | Rather than carry them around spearately, the options for how to+-- execute a regex are kept as part of the regex. There are two types+-- of options. Those that can only be specified at compilation time+-- and never changed are CompOpt. Those that can be changed later and+-- affect how matching is performed are ExecOpt. The actually types+-- for these depend on the backend.+class RegexOptions regex compOpt execOpt + | regex->compOpt execOpt, compOpt->regex execOpt, execOpt->regex compOpt where+ blankCompOpt :: compOpt -- ^ no options set at all in the backend+ blankExecOpt :: execOpt -- ^ no options set at all in the backend+ defaultCompOpt :: compOpt -- ^ reasonable options (extended,caseSensitive,multiline regex)+ defaultExecOpt :: execOpt -- ^ reasonable options (extended,caseSensitive,multiline regex)+ setExecOpts :: execOpt -> regex -> regex+ -- ^ forget old flags and use new ones+ getExecOpts :: regex -> execOpt+ -- ^ retrieve the current flags++----------------+-- | RegexMaker captures the creation of the compiled regular+-- expression from a source type and an option type. The 'makeRegex'+-- function has a default implementation that depends on makeRegexOpts+-- and used 'defaultCompOpt' and 'defaultExecOpt'.+class (RegexOptions regex compOpt execOpt) => RegexMaker regex compOpt execOpt source + | regex -> compOpt execOpt, compOpt -> regex execOpt, execOpt -> regex compOpt where+ -- | make using the defaultCompOpt and defaultExecOpt+ makeRegex :: source -> regex+ -- | Specify your own options+ makeRegexOpts :: compOpt -> execOpt -> source -> regex++ makeRegex = makeRegexOpts defaultCompOpt defaultExecOpt++----------------+-- | RegexLike is parametrized on a regular expression type and a+-- source type to run the matching on.+--+-- There are default implementations: matchTest and matchOnceText+-- using matchOnce; matchCount and matchAllText using+-- matchAll. matchOnce uses matchOnceText and matchAll uses+-- matchAllText. So a minimal complete instance need to provide+-- (matchOnce or matchOnceText) and (matchAll or matchAllText).+class (Extract source)=> RegexLike regex source where+ matchAll :: regex -> source-> [MatchArray]+ -- | This can return an array of (offset,length) index pairs for the+ -- match and captured substrings.+ matchOnce :: regex -> source-> Maybe MatchArray+ matchCount :: regex -> source-> Int+ matchTest :: regex -> source-> Bool+ matchAllText :: regex -> source-> [MatchText source]+ -- | This can return a tuple of three items: the source before the+ -- match, an array of the match and captured substrings (with their+ -- indices), and the source after the match.+ matchOnceText :: regex -> source-> Maybe (source,MatchText source,source)++ matchAll regex source = map (fmap snd) (matchAllText regex source)+ matchOnce regex source = fmap (\(_,mt,_) -> fmap snd mt) (matchOnceText regex source)+ matchTest regex source = isJust (matchOnce regex source)+ matchCount regex source = length (matchAll regex source)+ matchOnceText regex source = + fmap (\ma -> let (o,l) = ma!0+ in (before o source+ ,fmap (\ol -> (extract ol source,ol)) ma+ ,after (o+l) source))+ (matchOnce regex source)+ matchAllText regex source =+ map (fmap (\ol -> (extract ol source,ol)))+ (matchAll regex source)++----------------+-- | RegexContext is the polymorphic interface to do matching+class (RegexLike regex source) => RegexContext regex source target where+ match :: regex -> source -> target+ matchM :: (Monad m) => regex -> source -> m target++----------------+-- | Extract allows for indexing operations on String or ByteString.+class Extract source where+ -- | before is a renamed "take"+ before :: Int -> source -> source+ -- | after is a renamed "drop"+ after :: Int -> source -> source+ -- | For when there is no match, this can construct an empty data value+ empty :: source+ -- | extract takes an offset and length and has a default+ -- implementation of @extract (off,len) source = before len (after+ -- off source)@+ extract :: (Int,Int) -> source -> source+ extract (off,len) source = before len (after off source)++instance Extract String where+ before = take; after = drop; empty = []++instance Extract ByteString where+ before = B.take; after = B.drop; empty = B.empty
+ regex-base.cabal view
@@ -0,0 +1,45 @@+-- ****************************************************************+-- To fix for cabal < 1.1.4 comment out the Extra-Source-Files line+-- ****************************************************************+Name: regex-base+Version: 0.71+-- Cabal-Version: >=1.1.4+License: BSD3+License-File: LICENSE+Copyright: Copyright (c) 2006, Christopher Kuklewicz+Author: Christopher Kuklewicz+Maintainer: TextRegexLazy@personal.mightyreason.com+Stability: Seems to work, passes a few tests+Homepage: http://sourceforge.net/projects/lazy-regex+-- Package-URL:+Synopsis: Replaces/Enhances Text.Regex+Description: Interface API for regex-posix,pcre,parsec,dfa+Category: Text+Tested-With: GHC+Build-Depends: base >= 2.0+-- Data-Files:+-- Extra-Source-Files: Text/Regex/Lazy/TestCompat.hs, Text/Regex/Lazy/TestFull.hs, Text/Regex/Impl/TestContext.hs, TestTextRegexLazy.hs, Example.hs, Example2.hs, lazy.html, README, Makefile+-- Extra-Tmp-Files:+Exposed-Modules: Text.Regex.Base+ Text.Regex.Base.RegexLike+ Text.Regex.Base.Context+ Text.Regex.Base.Impl+Buildable: True+-- Other-Modules:+-- ********* Be backward compatible until 6.4.2 is futher deployed+-- HS-Source-Dirs: "."+Extensions: MultiParamTypeClasses, FunctionalDependencies+-- GHC-Options: -Wall -Werror+GHC-Options: -Wall -Werror -O2+-- GHC-Options: -Wall -ddump-minimal-imports+-- GHC-Prog-Options: +-- Hugs-Options:+-- NHC-Options:+-- Includes:+-- Include-Dirs:+-- C-Sources:+-- Extra-Libraries:+-- Extra-Lib-Dirs:+-- CC-Options:+-- LD-Options:+-- Frameworks: