css-selectors-0.5.0.0: src/Css3/Selector/Parser.y
-- vim:ft=haskell
{
module Css3.Selector.Parser where
import Css3.Selector.Core
import Css3.Selector.Lexer(
AlexPosn(AlexPn), TokenLoc(TokenLoc)
, Token(
TIncludes, TEqual, TDashMatch, TPrefixMatch, TSuffixMatch, TSubstringMatch, Ident, String, THash, Decimal
, Integer, Comma, Plus, Greater, Tilde, Dot, Pipe, Asterisk, Space, BOpen, BClose, PseudoClass, PseudoFunction
, PseudoElement, TN, TNth, TPM, TInt, TClose, TNot, TLang
)
)
import Data.List.NonEmpty(NonEmpty((:|)), (<|))
import Data.Default.Class(def)
#if __GLASGOW_HASKELL__ < 803
import Data.Semigroup((<>))
#endif
import Data.Text(pack)
}
%name cssselector
%tokentype { TokenLoc }
%error { happyError }
%token
',' { TokenLoc Comma _ _ }
'>' { TokenLoc Greater _ _ }
'+' { TokenLoc Plus _ _ }
'~' { TokenLoc Tilde _ _ }
'.' { TokenLoc Dot _ _ }
' ' { TokenLoc Space _ _ }
'|' { TokenLoc Pipe _ _ }
'*' { TokenLoc Asterisk _ _ }
'[' { TokenLoc BOpen _ _ }
']' { TokenLoc BClose _ _ }
'=' { TokenLoc TEqual _ _ }
'^=' { TokenLoc TPrefixMatch _ _ }
'$=' { TokenLoc TSuffixMatch _ _ }
'*=' { TokenLoc TSubstringMatch _ _ }
'|=' { TokenLoc TDashMatch _ _ }
'~=' { TokenLoc TIncludes _ _ }
ident { TokenLoc (Ident $$) _ _ }
string { TokenLoc (String $$) _ _ }
hash { TokenLoc (THash $$) _ _ }
pseude { TokenLoc (PseudoElement $$) _ _ }
pseudc { TokenLoc (PseudoClass $$) _ _ }
pseudf { TokenLoc (PseudoFunction $$) _ _ }
pm { TokenLoc (TPM $$) _ _ }
'n' { TokenLoc TN _ _ }
int { TokenLoc (TInt $$) _ _ }
nth { TokenLoc (TNth $$) _ _ }
'not(' { TokenLoc TNot _ _ }
'lang(' { TokenLoc TLang _ _ }
')' { TokenLoc TClose _ _ }
%%
SelectorsGroup
: SelectorGroupList { SelectorGroup $1 }
;
SelectorGroupList
: Selector { $1 :| [] }
| Selector ',' SelectorGroupList { $1 <| $3 }
;
Selector
: PseudoSelectorSequence { Selector $1 }
| PseudoSelectorSequence Combinator Selector { Combined $1 $2 $3 }
;
Combinator
: '+' { DirectlyPreceded }
| '>' { Child }
| '~' { Preceded }
| ' ' { Descendant }
;
PseudoSelectorSequence
: SimpleSelectorSequence { Sequence $1 }
| SimpleSelectorSequence pseude { $1 :.:: $2 }
| pseude { def :.:: $1 }
;
SimpleSelectorSequence
: Type FilterList { addFilters (SimpleSelector $1) $2 }
| SelectorAddition FilterList { addFilters (SimpleSelector Universal) ($1:$2) }
;
FilterList
: { [] }
| SelectorAddition FilterList { $1 : $2 }
;
SelectorAddition
: hash { SHash (Hash (pack $1)) }
| pseudc { SPseudo $1 }
| pseudf OptSpace Nth { SPseudo ($1 $3) }
| Class { SClass $1 }
| AttribBox { SAttrib $1 }
| 'not(' Negation ')' { SNot $2 }
| 'lang(' string ')' { SPseudo (Lang (pack $2)) }
;
Negation
: hash { NHash (Hash (pack $1)) }
| Class { NClass $1 }
| AttribBox { NAttrib $1 }
| pseudc { NPseudo $1 }
| pseudf OptSpace Nth { NPseudo ($1 $3) }
| Type { NTypeSelector $1 }
| pseude { NPseudoElement $1 }
| 'lang(' string ')' { NPseudo (Lang (pack $2)) }
;
Nth
: nth OptSpace ')' { $1 }
| PMOpt IntOpt 'n' OptSpace ')' { Nth ($1 $2) 0 }
| PMOpt IntOpt 'n' OptSpace pm OptSpace int OptSpace ')' { Nth ($1 $2) ($5 $7) }
| PMOpt int OptSpace ')' { Nth 0 ($1 $2) }
;
PMOpt
: { id }
| pm { $1 }
;
IntOpt
: { 1 }
| int { $1 }
;
OptSpace
: { () }
| ' ' { () }
;
AttribBox
: '[' Attrib ']' { $2 }
;
Attrib
: AttribName { Exist $1 }
| AttribName AttribOp Ident { Attrib $1 $2 $3 }
| AttribName AttribOp string { Attrib $1 $2 (pack $3) }
;
AttribName
: NamespacePrefix '|' Ident { AttributeName $1 $3 }
| '|' Ident { AttributeName NEmpty $2 }
| Ident { AttributeName NAny $1 }
;
AttribOp
: '=' { Exact }
| '~=' { Include }
| '|=' { DashMatch }
| '^=' { PrefixMatch }
| '$=' { SuffixMatch }
| '*=' { SubstringMatch }
;
Type
: ElementName { NAny .| $1 }
| '|' ElementName { NEmpty .| $2 }
| NamespacePrefix '|' ElementName { $1 .| $3 }
;
ElementName
: Ident { ElementName $1 }
| '*' { EAny }
;
Class
: '.' Ident { Class $2 }
;
NamespacePrefix
: Ident { Namespace $1 }
| '*' { NAny }
;
Ident
: ident { pack $1 }
;
{
happyError :: [TokenLoc] -> a
happyError (~(TokenLoc t s ~(Just (AlexPn _ l c))):_) = error ("Can not parse the CSS selector: unpexected token \"" <> s <> "\" at location (" <> show l <> ", " <> show c <> ")")
happyError _ = error "Unexpected end of string when parsing a css selector."
}