/*
* SEEKS TO BE CSS3 SYNTAX COMPLIANT ACCORDING TO:
* https://drafts.csswg.org/css-syntax/
*/
/// BEGIN CONVENIENCE PARSER RULES
CSS = { STYLESHEET ~ EOI }
SELECTOR = { SELECTOR_REPR }
SELECTOR_REPR = _{ (SELECTOR_COMBINATORS | SIMPLE_BLOCK | FUNCTION_BLOCK | PRESERVED_TOKEN)+ }
COMPONENT_VALUE_LIST = { (COMPONENT_VALUE ~ WS*)+ }
// COMPONENT_VALUE_LIST = { (COMPONENT_VALUE ~ WS* ~ "," ~ WS*)+ }
/// BEGIN CSS PARSER RULES SPEC
// https://drafts.csswg.org/css-syntax/#stylesheet-diagram
// COMPLIANT
STYLESHEET = { (CDO | CDC | QUALIFIED_RULE | AT_RULE | WS)* }
// https://drafts.csswg.org/css-syntax/#at-rule-diagram
// DEVIATION: PEDANTIC
// REASON: uses short-hand
AT_RULE = { AT_KEYWORD ~ COMPONENT_VALUE_LIST? ~ (DECL_BLOCK | ";") }
// https://drafts.csswg.org/css-syntax/#qualified-rule-diagram
// DEVIATION: PEDANTIC
// REASON: uses short-hand
QUALIFIED_RULE = { WS* ~ SELECTOR ~ WS* ~ DECL_BLOCK }
// https://drafts.csswg.org/css-syntax/#declaration-list-diagram
// COMPLIANT
DECL_BLOCK = { "{" ~ WS* ~ (
( (DECLARATION ~ WS* ~ ";") | AT_RULE | QUALIFIED_RULE ) ~ WS*
)* ~ WS* ~ "}"
}
// https://drafts.csswg.org/css-syntax/#declaration-diagram
// UNCOMPLIANT
// REASON: Abstracts declaration value groupings for easier parsing
DECLARATION = {
IDENT ~ WS* ~ ":" ~ WS* ~ DECLARATION_GROUPS ~ (WS+ ~ IMPORTANT)?
}
DECLARATION_GROUPS = { DECLARATION_VALUES ~ (WS* ~ "," ~ WS* ~ DECLARATION_VALUES)* }
DECLARATION_VALUES = {
(DECLARATION_SHORTHAND | DECLARATION_VALUE)
~ (WS+ ~ (DECLARATION_SHORTHAND | DECLARATION_VALUE))*
}
DECLARATION_SHORTHAND = { DECLARATION_VALUE ~ WS* ~ "/" ~ WS* ~ DECLARATION_VALUE }
DECLARATION_VALUE = { !WS ~ !"," ~ COMPONENT_VALUE }
// https://drafts.csswg.org/css-syntax/#!important-diagram
// COMPLIANT
IMPORTANT = { "!important" }
// https://drafts.csswg.org/css-syntax/#component-value-diagram
// WEAKLY COMPLIANT
// REASON: uses concrete representation of an abstract definition (PRESERVED_TOKEN)
COMPONENT_VALUE = { PRESERVED_TOKEN | SIMPLE_BLOCK | FUNCTION_BLOCK | SELECTOR }
// https://drafts.csswg.org/css-syntax/#simple-block-diagram
// DEVIATION: PEDANTIC
// REASON: uses short-hand
SIMPLE_BLOCK = {
("{" ~ COMPONENT_VALUE_LIST ~ "}")
| ("(" ~ COMPONENT_VALUE_LIST ~ ")")
| ("[" ~ COMPONENT_VALUE_LIST ~ "]")
}
// https://drafts.csswg.org/css-syntax/#function-block-diagram
// DEVIATION: PEDANTIC
// REASON: uses short-hand
FUNCTION_BLOCK = {
FUNCTION
~ (COMPONENT_VALUE ~ (WS* ~ "," ~ WS* ~ COMPONENT_VALUE)*)*
~ ")"
}
/// BEGIN CONVENIENCE GRAMMAR TOKENS
UNQUOTED_URL = {
(!ESCAPE ~ !NEWLINE ~ !"\"" ~ !"'" ~ !"(" ~ !")" ~ NON_PRINTABLE)* ~ ESCAPE*
}
WILDCARD = { "*" }
CLASS = { "." ~ IDENT }
ATTRIBUTE_OPERATOR = _{
"="
| "~="
| "|="
| "^="
| "$="
| "*="
}
SELECTOR_COMBINATORS = _{
"+"
| ">"
| "||"
| "~"
| " "
| "|"
| ":"
| ","
}
PRESERVED_TOKEN = _{ !FUNCTION ~ !"{" ~ !"(" ~ !"[" ~ !";" ~ (
DIMENSION
| PERCENTAGE
| NUMBER
| IDENT
| STRING
| HASH
| URL
| CLASS
| WILDCARD
| WS
| ATTRIBUTE_OPERATOR
// | ","
)}
/// BEGIN CSS GRAMMAR TOKENS SPEC
// https://drafts.csswg.org/css-syntax/#percentage-token-diagram
// COMPLIANT
PERCENTAGE = { NUMBER ~ "%" }
// https://drafts.csswg.org/css-syntax/#dimension-token-diagram
// COMPLIANT
DIMENSION = { NUMBER ~ IDENT }
// 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/#url-token-diagram
// DEVIATION: UNCOMPLIANT
// REASON: allows a quoted or un-quoted url rather than only an unquoted url
URL = { "url(" ~ WS* ~ (STRING | UNQUOTED_URL)? ~ WS* ~ ")" }
// 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
)+
}
// https://drafts.csswg.org/css-syntax/#at-keyword-token-diagram
// COMPLIANT
AT_KEYWORD = { "@" ~ IDENT }
// https://drafts.csswg.org/css-syntax/#function-token-diagram
// COMPLIANT
FUNCTION = { IDENT ~ "(" }
// 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
)*
}
// These are technically defined and referenced in the spec,
// but I was unable to determine what makes them compliant or not.
// As such, their compliance cannot be graded. Best I can tell is
// that, because their consumption is documented to expect discarding
// a token, they should be ignored. For this reason, they are silenced.
// This means that they won't cause a syntax error in the highest
// scope, but they will not generate a token.
CDO = _{ "<!--" }
CDC = _{ "-->" }
// 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}" }