{- 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 . -} {- | [@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