hxt-css-0.1.0.0: Text/XML/HXT/CSS/TypeDefs.hs
{- |
Module : Text.XML.HXT.CSS.TypeDefs
Stability : provisional
Data types for the abstract syntax tree of CSS selectors. We (mostly)
follow the naming conventions of the CSS Level 3 specification document
(<http://www.w3.org/TR/css3-selectors/>). The type hierarchy tries to
strike a balance between correctness and complexity. As a result, it is
possible to construct values that correspond to invalid selectors.
For example,
@
'Negation' ('Negation' 'UniversalSelector')
@
is not valid according to the spec, as double negation is not allowed.
Note that 'Text.XML.HXT.CSS.Parser.parseCSS' never produces invalid
selectors.
-}
module Text.XML.HXT.CSS.TypeDefs where
import Data.Char
-- | The top-level selector type.
newtype SelectorsGroup = SelectorsGroup [Selector] -- ^ @E, F@
deriving (Show, Eq)
data Selector
= Selector SimpleSelectorSeq -- ^ @E@
| Descendant SimpleSelectorSeq Selector -- ^ @E F@
| Child SimpleSelectorSeq Selector -- ^ @E > F@
| AdjSibling SimpleSelectorSeq Selector -- ^ @E + F@
| FolSibling SimpleSelectorSeq Selector -- ^ @E ~ F@
deriving (Show, Eq)
newtype SimpleSelectorSeq =
SimpleSelectorSeq [SimpleSelector] -- ^ @tag#id.class:pseudo@
deriving (Show, Eq)
data SimpleSelector
= UniversalSelector -- ^ @*@
| TypeSelector String -- ^ @tag@
| IdSelector String -- ^ @#id@
| ClassSelector String -- ^ @.class@
| AttrSelector String AttrTest -- ^ @[..]@
| Pseudo PseudoClass -- ^ @:pseudo@
| PseudoNth PseudoNthClass -- ^ @:pseudo(2)@
| Negation SimpleSelector -- ^ @:not(..)@
deriving (Show, Eq)
data AttrTest
= AttrExists -- ^ @[attr]@
| AttrEq String -- ^ @[attr=var]@
| AttrContainsSp String -- ^ @[attr~=var]@
| AttrBeginHy String -- ^ @[attr|=var]@
| AttrPrefix String -- ^ @[attr^=var]@
| AttrSuffix String -- ^ @[attr$=var]@
| AttrSubstr String -- ^ @[attr*=var]@
deriving (Show, Eq)
-- | Pseudo classes.
data PseudoClass
= PseudoFirstChild -- ^ @:first-child@
| PseudoLastChild -- ^ @:last-child@
| PseudoOnlyChild -- ^ @:only-child@
| PseudoFirstOfType -- ^ @:first-of-type@
| PseudoLastOfType -- ^ @:last-of-type@
| PseudoOnlyOfType -- ^ @:only-of-type@
| PseudoEmpty -- ^ @:empty@
| PseudoRoot -- ^ @:root@
deriving (Show, Eq)
-- | Pseudo classes that expect a argument of type 'Nth'.
data PseudoNthClass
= PseudoNthChild Nth -- ^ @:nth-child(..)@
| PseudoNthLastChild Nth -- ^ @:nth-last-child(..)@
| PseudoNthOfType Nth -- ^ @:nth-of-type(..)@
| PseudoNthLastOfType Nth -- ^ @:nth-last-of-type(..)@
deriving (Show, Eq)
-- | Type of the argument of the @:nth-child@ ('PseudoNthClass')
-- family of pseudo classes. @'Nth' a b@ matches with all integers that can
-- be written in the form @an+b@ for some nonnegative integer @n@.
data Nth
= Nth Int Int -- ^ @an+b@
| Odd -- ^ @odd@
| Even -- ^ @even@
deriving (Show, Eq)
-- | Find a 'PseudoClass' given its name (without the colon).
findPseudoClass :: String -> Maybe PseudoClass
findPseudoClass = flip lookup h . map toLower
where
h = [ ("first-child", PseudoFirstChild)
, ("last-child", PseudoLastChild)
, ("only-child", PseudoOnlyChild)
, ("first-of-type", PseudoFirstOfType)
, ("last-of-type", PseudoLastOfType)
, ("only-of-type", PseudoOnlyOfType)
, ("empty", PseudoEmpty)
, ("root", PseudoRoot)
]
-- | Find a 'PseudoNthClass' given its name (without the colon).
findPseudoNthClass :: String -> Maybe (Nth -> PseudoNthClass)
findPseudoNthClass = flip lookup h . map toLower
where
h = [ ("nth-child", PseudoNthChild)
, ("nth-last-child", PseudoNthLastChild)
, ("nth-of-type", PseudoNthOfType)
, ("nth-last-of-type", PseudoNthLastOfType)
]
-- | Check whether an integer satisfies a \"Diophantine\" constraint
-- given in form of a value of type 'Nth'.
testNth :: Nth -> Int -> Bool
testNth (Nth 0 b) k = k == b
testNth (Nth a b) k = r == 0 && n >= 0
where
(n, r) = (k - b) `quotRem` a
testNth Odd k = odd k
testNth Even k = even k