/// BEGIN SELECTOR GRAMMAR SPEC
// each rule is defined in accordance to their corresponding rule at:
// https://www.w3.org/TR/selectors/#grammar
SELECTOR_LIST = { WS* ~ SELECTOR_COMPLEX_LIST }
SELECTOR_COMPLEX_LIST = { SELECTOR_COMPLEX ~ WS* ~ ("," ~ WS* ~ SELECTOR_COMPLEX ~ WS*)* }
SELECTOR_COMPOUND_LIST = { SELECTOR_COMPOUND ~ WS* ~ ("," ~ WS* ~ SELECTOR_COMPOUND ~ WS*)* }
SELECTOR_SIMPLE_LIST = { SELECTOR_SIMPLE ~ WS* ~ ("," ~ WS* ~ SELECTOR_SIMPLE ~ WS*)* }
SELECTOR_RELATIVE_LIST = { SELECTOR_RELATIVE ~ WS* ~ ("," ~ WS* ~ SELECTOR_RELATIVE ~ WS*)* }
SELECTOR_COMPLEX = { SELECTOR_COMPOUND ~ ((SELECTOR_COMBINATOR ~ SELECTOR_COMPOUND) | (SELECTOR_COMBINATOR__NAMESPACE))* }
SELECTOR_RELATIVE = { SELECTOR_COMBINATOR? ~ SELECTOR_COMPLEX }
SELECTOR_COMPOUND = {
(
(SELECTOR_TYPE ~ (SELECTOR_SUBCLASS*) ~ (SELECTOR_PSEUDOELEMENT_TAIL*))
| ((SELECTOR_SUBCLASS+) ~ (SELECTOR_PSEUDOELEMENT_TAIL*))
| SELECTOR_PSEUDOELEMENT_TAIL
)+
}
SELECTOR_PSEUDOELEMENT_TAIL = { SELECTOR_PSEUDOELEMENT ~ SELECTOR_PSEUDOCLASS* }
SELECTOR_SIMPLE = { SELECTOR_SUBCLASS | SELECTOR_TYPE }
SELECTOR_COMBINATOR = {
SELECTOR_COMBINATOR__NEXT_SIBLING
| SELECTOR_COMBINATOR__CHILD
| SELECTOR_COMBINATOR__COLUMN
| SELECTOR_COMBINATOR__SUBSEQUENT_SIBLING
| SELECTOR_COMBINATOR__DESCENDENT
}
SELECTOR_TYPE = { WQ_NAME | (PREFIX_NAMESPACE? ~ "*") }
PREFIX_NAMESPACE = { (IDENT | "*")? ~ "|" }
WQ_NAME = { PREFIX_NAMESPACE? ~ IDENT }
SELECTOR_SUBCLASS = { SELECTOR_ID | SELECTOR_CLASS | SELECTOR_ATTRIBUTE | SELECTOR_PSEUDOCLASS }
SELECTOR_ID = { HASH }
SELECTOR_CLASS = { "." ~ IDENT }
SELECTOR_ATTRIBUTE = {
("[" ~ WS* ~ IDENT ~ WS* ~ "]")
| ("[" ~ WS* ~ IDENT ~ WS* ~ ATTR_MATCHER ~ WS* ~ (ATTR_MODIFIER ~ WS*)? ~ "]")
}
ATTR_MATCHER = {
(
ATTR_MATCHER__EXACT_MATCH
| ATTR_MATCHER__LIST_CONTAINS
| ATTR_MATCHER__STARTS_WITH
| ATTR_MATCHER__STARTS_WITH_DASHED
| ATTR_MATCHER__ENDS_WITH
| ATTR_MATCHER__CONTAINS
) ~ WS* ~ (STRING | IDENT)
}
ATTR_MODIFIER = { "i" | "I" | "s" | "S" }
SELECTOR_PSEUDOCLASS = { ":" ~ (IDENT | FUNCTION_BLOCK) }
SELECTOR_PSEUDOELEMENT = { ":" ~ SELECTOR_PSEUDOCLASS }
ATTR_MATCHER__EXACT_MATCH = { "=" }
ATTR_MATCHER__LIST_CONTAINS = { "~=" }
ATTR_MATCHER__STARTS_WITH = { "^=" }
ATTR_MATCHER__STARTS_WITH_DASHED = { "|=" }
ATTR_MATCHER__ENDS_WITH = { "$=" }
ATTR_MATCHER__CONTAINS = { "*=" }
// CONVENIENCE TOKENS
SELECTOR_COMBINATOR__NEXT_SIBLING = { WS* ~ "+" ~ WS* }
SELECTOR_COMBINATOR__CHILD = { WS* ~ ">" ~ WS* }
SELECTOR_COMBINATOR__COLUMN = { WS* ~ "||" ~ WS* }
SELECTOR_COMBINATOR__SUBSEQUENT_SIBLING = { WS* ~ "~" ~ WS* }
SELECTOR_COMBINATOR__DESCENDENT = { " "+ }
SELECTOR_COMBINATOR__NAMESPACE = { WS* ~ "|" ~ WS* ~ IDENT }
// BEGIN CSS GRAMMAR TOKENS SPEC
// https://drafts.csswg.org/css-syntax/#string-token-diagram
// COMPLIANT
STRING = {
("'" ~ (
(!"'" ~ !NEWLINE ~ !"\\" ~ ANY)
| ESCAPE
| ("\\" ~ NEWLINE)
)*
~ "'")
|
("\"" ~ (
(!"\"" ~ !NEWLINE ~ !"\\" ~ ANY)
| ESCAPE
| ("\\" ~ NEWLINE)
)*
~ "\"")
}
// https://drafts.csswg.org/css-syntax/#hash-token-diagram
// COMPLIANT
HASH = {
"#" ~ (
('0'..'9' | 'a'..'z' | 'A'..'Z' | "_" | "-" | NON_ASCII)
| ESCAPE
)+
}
FUNCTION_BLOCK = { (FUNCTION ~ FUNCTION__CONTENTS ~ ")") }
// https://drafts.csswg.org/css-syntax/#function-token-diagram
// COMPLIANT
FUNCTION = { IDENT ~ "(" }
FUNCTION__CONTENTS = { FUNCTION__PARAMS ~ (((WS+) | (WS* ~ "," ~ WS*)) ~ FUNCTION__PARAMS)* }
FUNCTION__PARAMS = { IDENT | STRING | NUMBER | HASH }
// https://drafts.csswg.org/css-syntax/#number-token-diagram
// COMPLIANT
NUMBER = { ("+" | "-")? ~ ((ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+) | ASCII_DIGIT+ | ("." ~ ASCII_DIGIT+)) ~ (("e" | "E") ~ ("+" | "-")? ~ ASCII_DIGIT+)? }
// https://drafts.csswg.org/css-syntax/#ident-token-diagram
// COMPLIANT
IDENT = { (
"--" | (
"-"? ~ (
('a'..'z' | 'A'..'Z' | "_" | NON_ASCII)
| ESCAPE
)
))
~ (
('0'..'9' | 'a'..'z' | 'A'..'Z' | "_" | "-" | NON_ASCII)
| ESCAPE
)*
}
// https://drafts.csswg.org/css-syntax/#comment-diagram
// https://drafts.csswg.org/css-syntax/#whitespace-diagram
// https://drafts.csswg.org/css-syntax/#ws*-diagram
// DEVIATION: PEDANTIC
// REASON: simplifies multiple token types into a single definition.
// doesn't repeat so usage mirrors "ws*" syntax used in spec
WS = _{ (" " | "\t" | NEWLINE) | ("/*" ~ (!"*/" ~ ANY)* ~ "*/") }
// https://drafts.csswg.org/css-syntax/#non-printable-code-point
// COMPLIANT
NON_PRINTABLE = _{ '\u{0000}'..'\u{0008}' | "\u{000B}" | '\u{000E}'..'\u{001F}' | "\u{007F}" }
// https://drafts.csswg.org/css-syntax/#non-ascii-ident-code-point
// COMPLIANT
NON_ASCII = _{
"\u{00B7}"
| '\u{00C0}'..'\u{00D6}' | '\u{00F8}'..'\u{037D}' | '\u{037F}'..'\u{1FFF}'
| "\u{200C}" | "\u{200D}" | "\u{203F}" | "\u{2040}"
| '\u{2070}'..'\u{218F}' | '\u{2C00}'..'\u{2FEF}' | '\u{3001}'..'\u{D7FF}'
| '\u{F900}'..'\u{FDCF}' | '\u{FDF0}'..'\u{FFFD}' | '\u{10000}'..'\u{10FFFF}'
}
// https://drafts.csswg.org/css-syntax/#escape-diagram
// COMPLIANT
ESCAPE = _{
"\\" ~ (
(!NEWLINE ~ !HEX_DIGIT)
| (HEX_DIGIT{1, 6} ~ WS?)
)
}
// https://drafts.csswg.org/css-syntax/#hex-digit-diagram
// COMPLIANT
HEX_DIGIT = _{ '0'..'9' | 'a'..'f' | 'A'..'F' }
// https://drafts.csswg.org/css-syntax/#newline-diagram
// COMPLIANT
NEWLINE = _{ "\n" | "\r" | "\r\n" | "\u{000C}" }