packages feed

css-selectors-0.4.0.2: src/Css3/Selector/Parser.y

-- vim:ft=haskell
{
module Css3.Selector.Parser where

import Css3.Selector.Core
import Css3.Selector.Lexer(AlexPosn(..), Token(..), TokenLoc(..))

import Data.List.NonEmpty(NonEmpty((:|)), (<|))

#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 $$) _ _ }

%%

SelectorsGroup
    : SelectorGroupList                           { SelectorGroup $1 }
    ;

SelectorGroupList
    : Selector                                    { $1 :| [] }
    | Selector ',' SelectorGroupList              { $1 <| $3 }
    ;

Selector
    : SimpleSelectorSequence                      { Selector $1 }
    | SimpleSelectorSequence Combinator Selector  { Combined $1 $2 $3 }
    ;

Combinator
    : '+'          { DirectlyPreceded }
    | '>'          { Child }
    | '~'          { Preceded }
    | ' '          { Descendant }
    ;

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)) }
    | Class                       { SClass $1 }
    | AttribBox                   { SAttrib $1 }
    ;

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 [] = error "Unexpected end of string when parsing a css selector."
happyError (~(TokenLoc _ s ~(AlexPn _ l c)):_) = error ("Can not parse the CSS selector: unpexected token \"" <> s <> "\" at location (" <> show l <> ", " <> show c <> ")")

}