regexdot-0.11.1.2: src-lib/RegExDot/BracketExpressionMember.hs
{-
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@]
Permits /Perl-style shortcut/s to be canned & assigned a single-'Char' mnemonic for subsequent reference;
the implementation of 'Read' looks for a back-slashed 'Char', for which it expects there to be a corresponding canned 'ShowablePredicate.ShowablePredicate'.
[@CAVEATS@]
Since the underlying polymorphic data-type isn't required to implement neither 'Enum' nor 'Ord', the implementation of 'Read' can't cope with range-specifications.
Lacking this, Bracket-expression members must be enumerated exhaustively.
-}
module RegExDot.BracketExpressionMember(
-- * Type-classes
ShortcutExpander(..),
-- * Types
-- ** Data-types
Member(..),
-- * Functions
-- ** Operators
(=~)
) where
import qualified Control.Arrow
import qualified Control.DeepSeq
import qualified RegExDot.ShowablePredicate as ShowablePredicate
infix 4 =~ -- Same as (==).
{- |
* The interface via which /Perl-style shortcut/s are expanded (when they occur within a /bracket-expression/), in a manner appropriate to the chosen type-parameter.
* The expansion of /Perl-style shortcut/s, is more restricted inside than outside, a /bracket-expression/,
& consequently are merely represented here by a 'ShowablePredicate.ShowablePredicate', rather than providing a more general form suitable also for those /Perl-style shortcuts/ found outside /bracket-expression/s.
* This interface is implemented elsewhere, where the specific type-parameter & consequently the appropriate set of /Perl-style shortcut/s, are defined.
-}
class ShortcutExpander a where
findPredicate :: Char -> Maybe (ShowablePredicate.ShowablePredicate a) -- ^ Attempt to find the appropriate 'ShowablePredicate.ShowablePredicate' to implement this /Perl-style shortcut/.
{- |
* A /BracketExpression/ can contain either a literal, a range of literals given @(Enum a, Ord a)@, a /Perl-style shortcut/, or when 'Char' is the type-parameter, a /POSIX Character-class/.
* This data-type reduces the representation of all these possibilities to either a predicate or a literal.
-}
data Member m =
Predicate (ShowablePredicate.ShowablePredicate m) -- ^ This 'Member' is described using a /predicate/, which is run to determine whether the datum conforms & is a member of the "BracketExpression".
| Literal m -- ^ This 'Member' is defined literally, using an item of the polymorphic type.
deriving Eq
instance Show m => Show (Member m) where
showsPrec _ (Predicate showablePredicate) = shows showablePredicate
showsPrec _ (Literal literal) = shows literal
instance (ShortcutExpander m, Read m) => Read (Member m) where
readsPrec _ [] = [] -- No parse.
readsPrec _ (' ' : s) = reads s -- Consume white-space.
readsPrec _ ('\t' : s) = reads s -- Consume white-space.
readsPrec _ ('\\' : shortcut : s) = case findPredicate shortcut of
Just showablePredicate -> [(Predicate showablePredicate, s)]
_ -> error $ "readsPrec RegExDot.BracketExpressionMember.Member:\tfindPredicate failed for shortcut " ++ show shortcut
readsPrec _ literal = Control.Arrow.first Literal `map` reads literal
instance Control.DeepSeq.NFData m => Control.DeepSeq.NFData (Member m) where
rnf (Predicate showablePredicate) = Control.DeepSeq.rnf showablePredicate
rnf (Literal literal) = Control.DeepSeq.rnf literal
-- | Match-operator.
(=~) :: Eq m
=> m -- ^ The input datum.
-> Member m -- ^ The member of the bracket-expression against which the input-datum is to be matched.
-> Bool -- ^ The result of the match-operation.
datum =~ Predicate showablePredicate = ShowablePredicate.predicate showablePredicate datum
datum =~ Literal literal = datum == literal