SelectorParsing.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. /*
  2. * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2020-2021, the SerenityOS developers.
  4. * Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
  5. * Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
  6. * Copyright (c) 2022, MacDue <macdue@dueutil.tech>
  7. *
  8. * SPDX-License-Identifier: BSD-2-Clause
  9. */
  10. #include <AK/Debug.h>
  11. #include <LibWeb/CSS/Parser/Parser.h>
  12. #include <LibWeb/Infra/Strings.h>
  13. namespace Web::CSS::Parser {
  14. Optional<SelectorList> Parser::parse_as_selector(SelectorParsingMode parsing_mode)
  15. {
  16. auto selector_list = parse_a_selector_list(m_token_stream, SelectorType::Standalone, parsing_mode);
  17. if (!selector_list.is_error())
  18. return selector_list.release_value();
  19. return {};
  20. }
  21. Optional<SelectorList> Parser::parse_as_relative_selector(SelectorParsingMode parsing_mode)
  22. {
  23. auto selector_list = parse_a_selector_list(m_token_stream, SelectorType::Relative, parsing_mode);
  24. if (!selector_list.is_error())
  25. return selector_list.release_value();
  26. return {};
  27. }
  28. template<typename T>
  29. Parser::ParseErrorOr<SelectorList> Parser::parse_a_selector_list(TokenStream<T>& tokens, SelectorType mode, SelectorParsingMode parsing_mode)
  30. {
  31. auto comma_separated_lists = parse_a_comma_separated_list_of_component_values(tokens);
  32. Vector<NonnullRefPtr<Selector>> selectors;
  33. for (auto& selector_parts : comma_separated_lists) {
  34. auto stream = TokenStream(selector_parts);
  35. auto selector = parse_complex_selector(stream, mode);
  36. if (selector.is_error()) {
  37. if (parsing_mode == SelectorParsingMode::Forgiving)
  38. continue;
  39. return selector.error();
  40. }
  41. selectors.append(selector.release_value());
  42. }
  43. if (selectors.is_empty() && parsing_mode != SelectorParsingMode::Forgiving)
  44. return ParseError::SyntaxError;
  45. return selectors;
  46. }
  47. template Parser::ParseErrorOr<SelectorList> Parser::parse_a_selector_list(TokenStream<ComponentValue>&, SelectorType, SelectorParsingMode);
  48. template Parser::ParseErrorOr<SelectorList> Parser::parse_a_selector_list(TokenStream<Token>&, SelectorType, SelectorParsingMode);
  49. Parser::ParseErrorOr<NonnullRefPtr<Selector>> Parser::parse_complex_selector(TokenStream<ComponentValue>& tokens, SelectorType mode)
  50. {
  51. Vector<Selector::CompoundSelector> compound_selectors;
  52. auto first_selector = TRY(parse_compound_selector(tokens));
  53. if (!first_selector.has_value())
  54. return ParseError::SyntaxError;
  55. if (mode == SelectorType::Standalone) {
  56. if (first_selector->combinator != Selector::Combinator::Descendant)
  57. return ParseError::SyntaxError;
  58. first_selector->combinator = Selector::Combinator::None;
  59. }
  60. compound_selectors.append(first_selector.release_value());
  61. while (tokens.has_next_token()) {
  62. auto compound_selector = TRY(parse_compound_selector(tokens));
  63. if (!compound_selector.has_value())
  64. break;
  65. compound_selectors.append(compound_selector.release_value());
  66. }
  67. if (compound_selectors.is_empty())
  68. return ParseError::SyntaxError;
  69. return Selector::create(move(compound_selectors));
  70. }
  71. Parser::ParseErrorOr<Optional<Selector::CompoundSelector>> Parser::parse_compound_selector(TokenStream<ComponentValue>& tokens)
  72. {
  73. tokens.skip_whitespace();
  74. auto combinator = parse_selector_combinator(tokens).value_or(Selector::Combinator::Descendant);
  75. tokens.skip_whitespace();
  76. Vector<Selector::SimpleSelector> simple_selectors;
  77. while (tokens.has_next_token()) {
  78. auto component = TRY(parse_simple_selector(tokens));
  79. if (!component.has_value())
  80. break;
  81. simple_selectors.append(component.release_value());
  82. }
  83. if (simple_selectors.is_empty())
  84. return Optional<Selector::CompoundSelector> {};
  85. return Selector::CompoundSelector { combinator, move(simple_selectors) };
  86. }
  87. Optional<Selector::Combinator> Parser::parse_selector_combinator(TokenStream<ComponentValue>& tokens)
  88. {
  89. auto const& current_value = tokens.next_token();
  90. if (current_value.is(Token::Type::Delim)) {
  91. switch (current_value.token().delim()) {
  92. case '>':
  93. return Selector::Combinator::ImmediateChild;
  94. case '+':
  95. return Selector::Combinator::NextSibling;
  96. case '~':
  97. return Selector::Combinator::SubsequentSibling;
  98. case '|': {
  99. auto const& next = tokens.peek_token();
  100. if (next.is(Token::Type::EndOfFile))
  101. return {};
  102. if (next.is_delim('|')) {
  103. tokens.next_token();
  104. return Selector::Combinator::Column;
  105. }
  106. }
  107. }
  108. }
  109. tokens.reconsume_current_input_token();
  110. return {};
  111. }
  112. Optional<Selector::SimpleSelector::QualifiedName> Parser::parse_selector_qualified_name(TokenStream<ComponentValue>& tokens, AllowWildcardName allow_wildcard_name)
  113. {
  114. auto is_name = [](ComponentValue const& token) {
  115. return token.is_delim('*') || token.is(Token::Type::Ident);
  116. };
  117. auto get_name = [](ComponentValue const& token) {
  118. if (token.is_delim('*'))
  119. return "*"_fly_string;
  120. return token.token().ident();
  121. };
  122. // There are 3 possibilities here:
  123. // (Where <name> and <namespace> are either an <ident> or a `*` delim)
  124. // 1) `|<name>`
  125. // 2) `<namespace>|<name>`
  126. // 3) `<name>`
  127. // Whitespace is forbidden between any of these parts. https://www.w3.org/TR/selectors-4/#white-space
  128. auto transaction = tokens.begin_transaction();
  129. auto first_token = tokens.next_token();
  130. if (first_token.is_delim('|')) {
  131. // Case 1: `|<name>`
  132. if (is_name(tokens.peek_token())) {
  133. auto name_token = tokens.next_token();
  134. if (allow_wildcard_name == AllowWildcardName::No && name_token.is_delim('*'))
  135. return {};
  136. transaction.commit();
  137. return Selector::SimpleSelector::QualifiedName {
  138. .namespace_type = Selector::SimpleSelector::QualifiedName::NamespaceType::None,
  139. .name = get_name(name_token),
  140. };
  141. }
  142. return {};
  143. }
  144. if (!is_name(first_token))
  145. return {};
  146. if (tokens.peek_token().is_delim('|') && is_name(tokens.peek_token(1))) {
  147. // Case 2: `<namespace>|<name>`
  148. (void)tokens.next_token(); // `|`
  149. auto namespace_ = get_name(first_token);
  150. auto name = get_name(tokens.next_token());
  151. if (allow_wildcard_name == AllowWildcardName::No && name == "*"sv)
  152. return {};
  153. auto namespace_type = namespace_ == "*"sv
  154. ? Selector::SimpleSelector::QualifiedName::NamespaceType::Any
  155. : Selector::SimpleSelector::QualifiedName::NamespaceType::Named;
  156. transaction.commit();
  157. return Selector::SimpleSelector::QualifiedName {
  158. .namespace_type = namespace_type,
  159. .namespace_ = namespace_,
  160. .name = name,
  161. };
  162. }
  163. // Case 3: `<name>`
  164. auto& name_token = first_token;
  165. if (allow_wildcard_name == AllowWildcardName::No && name_token.is_delim('*'))
  166. return {};
  167. transaction.commit();
  168. return Selector::SimpleSelector::QualifiedName {
  169. .namespace_type = Selector::SimpleSelector::QualifiedName::NamespaceType::Default,
  170. .name = get_name(name_token),
  171. };
  172. }
  173. Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_attribute_simple_selector(ComponentValue const& first_value)
  174. {
  175. auto attribute_tokens = TokenStream { first_value.block().values() };
  176. attribute_tokens.skip_whitespace();
  177. if (!attribute_tokens.has_next_token()) {
  178. dbgln_if(CSS_PARSER_DEBUG, "CSS attribute selector is empty!");
  179. return ParseError::SyntaxError;
  180. }
  181. auto maybe_qualified_name = parse_selector_qualified_name(attribute_tokens, AllowWildcardName::No);
  182. if (!maybe_qualified_name.has_value()) {
  183. dbgln_if(CSS_PARSER_DEBUG, "Expected qualified-name for attribute name, got: '{}'", attribute_tokens.peek_token().to_debug_string());
  184. return ParseError::SyntaxError;
  185. }
  186. auto qualified_name = maybe_qualified_name.release_value();
  187. Selector::SimpleSelector simple_selector {
  188. .type = Selector::SimpleSelector::Type::Attribute,
  189. .value = Selector::SimpleSelector::Attribute {
  190. .match_type = Selector::SimpleSelector::Attribute::MatchType::HasAttribute,
  191. // FIXME: Case-sensitivity is defined by the document language.
  192. // HTML is insensitive with attribute names, and our code generally assumes
  193. // they are converted to lowercase, so we do that here too. If we want to be
  194. // correct with XML later, we'll need to keep the original case and then do
  195. // a case-insensitive compare later.
  196. .qualified_name = qualified_name,
  197. .case_type = case_insensitive_html_attributes.contains_slow(qualified_name.name.lowercase_name)
  198. ? Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch
  199. : Selector::SimpleSelector::Attribute::CaseType::DefaultMatch,
  200. }
  201. };
  202. attribute_tokens.skip_whitespace();
  203. if (!attribute_tokens.has_next_token())
  204. return simple_selector;
  205. auto const& delim_part = attribute_tokens.next_token();
  206. if (!delim_part.is(Token::Type::Delim)) {
  207. dbgln_if(CSS_PARSER_DEBUG, "Expected a delim for attribute comparison, got: '{}'", delim_part.to_debug_string());
  208. return ParseError::SyntaxError;
  209. }
  210. if (delim_part.token().delim() == '=') {
  211. simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch;
  212. } else {
  213. if (!attribute_tokens.has_next_token()) {
  214. dbgln_if(CSS_PARSER_DEBUG, "Attribute selector ended part way through a match type.");
  215. return ParseError::SyntaxError;
  216. }
  217. auto const& delim_second_part = attribute_tokens.next_token();
  218. if (!delim_second_part.is_delim('=')) {
  219. dbgln_if(CSS_PARSER_DEBUG, "Expected a double delim for attribute comparison, got: '{}{}'", delim_part.to_debug_string(), delim_second_part.to_debug_string());
  220. return ParseError::SyntaxError;
  221. }
  222. switch (delim_part.token().delim()) {
  223. case '~':
  224. simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::ContainsWord;
  225. break;
  226. case '*':
  227. simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::ContainsString;
  228. break;
  229. case '|':
  230. simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::StartsWithSegment;
  231. break;
  232. case '^':
  233. simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::StartsWithString;
  234. break;
  235. case '$':
  236. simple_selector.attribute().match_type = Selector::SimpleSelector::Attribute::MatchType::EndsWithString;
  237. break;
  238. default:
  239. attribute_tokens.reconsume_current_input_token();
  240. }
  241. }
  242. attribute_tokens.skip_whitespace();
  243. if (!attribute_tokens.has_next_token()) {
  244. dbgln_if(CSS_PARSER_DEBUG, "Attribute selector ended without a value to match.");
  245. return ParseError::SyntaxError;
  246. }
  247. auto const& value_part = attribute_tokens.next_token();
  248. if (!value_part.is(Token::Type::Ident) && !value_part.is(Token::Type::String)) {
  249. dbgln_if(CSS_PARSER_DEBUG, "Expected a string or ident for the value to match attribute against, got: '{}'", value_part.to_debug_string());
  250. return ParseError::SyntaxError;
  251. }
  252. auto const& value_string = value_part.token().is(Token::Type::Ident) ? value_part.token().ident() : value_part.token().string();
  253. simple_selector.attribute().value = value_string.to_string();
  254. attribute_tokens.skip_whitespace();
  255. // Handle case-sensitivity suffixes. https://www.w3.org/TR/selectors-4/#attribute-case
  256. if (attribute_tokens.has_next_token()) {
  257. auto const& case_sensitivity_part = attribute_tokens.next_token();
  258. if (case_sensitivity_part.is(Token::Type::Ident)) {
  259. auto case_sensitivity = case_sensitivity_part.token().ident();
  260. if (case_sensitivity.equals_ignoring_ascii_case("i"sv)) {
  261. simple_selector.attribute().case_type = Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch;
  262. } else if (case_sensitivity.equals_ignoring_ascii_case("s"sv)) {
  263. simple_selector.attribute().case_type = Selector::SimpleSelector::Attribute::CaseType::CaseSensitiveMatch;
  264. } else {
  265. dbgln_if(CSS_PARSER_DEBUG, "Expected a \"i\" or \"s\" attribute selector case sensitivity identifier, got: '{}'", case_sensitivity_part.to_debug_string());
  266. return ParseError::SyntaxError;
  267. }
  268. } else {
  269. dbgln_if(CSS_PARSER_DEBUG, "Expected an attribute selector case sensitivity identifier, got: '{}'", case_sensitivity_part.to_debug_string());
  270. return ParseError::SyntaxError;
  271. }
  272. }
  273. if (attribute_tokens.has_next_token()) {
  274. dbgln_if(CSS_PARSER_DEBUG, "Was not expecting anything else inside attribute selector.");
  275. return ParseError::SyntaxError;
  276. }
  277. return simple_selector;
  278. }
  279. Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_pseudo_simple_selector(TokenStream<ComponentValue>& tokens)
  280. {
  281. auto peek_token_ends_selector = [&]() -> bool {
  282. auto const& value = tokens.peek_token();
  283. return (value.is(Token::Type::EndOfFile) || value.is(Token::Type::Whitespace) || value.is(Token::Type::Comma));
  284. };
  285. if (peek_token_ends_selector())
  286. return ParseError::SyntaxError;
  287. bool is_pseudo = false;
  288. if (tokens.peek_token().is(Token::Type::Colon)) {
  289. is_pseudo = true;
  290. tokens.next_token();
  291. if (peek_token_ends_selector())
  292. return ParseError::SyntaxError;
  293. }
  294. if (is_pseudo) {
  295. auto const& name_token = tokens.next_token();
  296. if (!name_token.is(Token::Type::Ident)) {
  297. dbgln_if(CSS_PARSER_DEBUG, "Expected an ident for pseudo-element, got: '{}'", name_token.to_debug_string());
  298. return ParseError::SyntaxError;
  299. }
  300. auto pseudo_name = name_token.token().ident();
  301. // Note: We allow the "ignored" -webkit prefix here for -webkit-progress-bar/-webkit-progress-bar
  302. if (auto pseudo_element = Selector::PseudoElement::from_string(pseudo_name); pseudo_element.has_value()) {
  303. return Selector::SimpleSelector {
  304. .type = Selector::SimpleSelector::Type::PseudoElement,
  305. .value = pseudo_element.release_value()
  306. };
  307. }
  308. // https://www.w3.org/TR/selectors-4/#compat
  309. // All other pseudo-elements whose names begin with the string “-webkit-” (matched ASCII case-insensitively)
  310. // and that are not functional notations must be treated as valid at parse time. (That is, ::-webkit-asdf is
  311. // valid at parse time, but ::-webkit-jkl() is not.) If they’re not otherwise recognized and supported, they
  312. // must be treated as matching nothing, and are unknown -webkit- pseudo-elements.
  313. if (pseudo_name.starts_with_bytes("-webkit-"sv, CaseSensitivity::CaseInsensitive)) {
  314. return Selector::SimpleSelector {
  315. .type = Selector::SimpleSelector::Type::PseudoElement,
  316. // Unknown -webkit- pseudo-elements must be serialized in ASCII lowercase.
  317. .value = Selector::PseudoElement { Selector::PseudoElement::Type::UnknownWebKit, MUST(Infra::to_ascii_lowercase(pseudo_name.to_string())) },
  318. };
  319. }
  320. if (has_ignored_vendor_prefix(pseudo_name))
  321. return ParseError::IncludesIgnoredVendorPrefix;
  322. dbgln_if(CSS_PARSER_DEBUG, "Unrecognized pseudo-element: '::{}'", pseudo_name);
  323. return ParseError::SyntaxError;
  324. }
  325. if (peek_token_ends_selector())
  326. return ParseError::SyntaxError;
  327. auto const& pseudo_class_token = tokens.next_token();
  328. if (pseudo_class_token.is(Token::Type::Ident)) {
  329. auto pseudo_name = pseudo_class_token.token().ident();
  330. if (has_ignored_vendor_prefix(pseudo_name))
  331. return ParseError::IncludesIgnoredVendorPrefix;
  332. auto make_pseudo_class_selector = [](auto pseudo_class) {
  333. return Selector::SimpleSelector {
  334. .type = Selector::SimpleSelector::Type::PseudoClass,
  335. .value = Selector::SimpleSelector::PseudoClassSelector { .type = pseudo_class }
  336. };
  337. };
  338. if (auto pseudo_class = pseudo_class_from_string(pseudo_name); pseudo_class.has_value()) {
  339. if (!pseudo_class_metadata(pseudo_class.value()).is_valid_as_identifier) {
  340. dbgln_if(CSS_PARSER_DEBUG, "Pseudo-class ':{}' is only valid as a function", pseudo_name);
  341. return ParseError::SyntaxError;
  342. }
  343. return make_pseudo_class_selector(pseudo_class.value());
  344. }
  345. // Single-colon syntax allowed for ::after, ::before, ::first-letter and ::first-line for compatibility.
  346. // https://www.w3.org/TR/selectors/#pseudo-element-syntax
  347. if (auto pseudo_element = Selector::PseudoElement::from_string(pseudo_name); pseudo_element.has_value()) {
  348. switch (pseudo_element.value().type()) {
  349. case Selector::PseudoElement::Type::After:
  350. case Selector::PseudoElement::Type::Before:
  351. case Selector::PseudoElement::Type::FirstLetter:
  352. case Selector::PseudoElement::Type::FirstLine:
  353. return Selector::SimpleSelector {
  354. .type = Selector::SimpleSelector::Type::PseudoElement,
  355. .value = pseudo_element.value()
  356. };
  357. default:
  358. break;
  359. }
  360. }
  361. dbgln_if(CSS_PARSER_DEBUG, "Unrecognized pseudo-class: ':{}'", pseudo_name);
  362. return ParseError::SyntaxError;
  363. }
  364. if (pseudo_class_token.is_function()) {
  365. auto parse_nth_child_selector = [this](auto pseudo_class, Vector<ComponentValue> const& function_values, bool allow_of = false) -> ParseErrorOr<Selector::SimpleSelector> {
  366. auto tokens = TokenStream<ComponentValue>(function_values);
  367. auto nth_child_pattern = parse_a_n_plus_b_pattern(tokens);
  368. if (!nth_child_pattern.has_value()) {
  369. dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid An+B format for {}", pseudo_class_name(pseudo_class));
  370. return ParseError::SyntaxError;
  371. }
  372. tokens.skip_whitespace();
  373. if (!tokens.has_next_token()) {
  374. return Selector::SimpleSelector {
  375. .type = Selector::SimpleSelector::Type::PseudoClass,
  376. .value = Selector::SimpleSelector::PseudoClassSelector {
  377. .type = pseudo_class,
  378. .nth_child_pattern = nth_child_pattern.release_value() }
  379. };
  380. }
  381. if (!allow_of)
  382. return ParseError::SyntaxError;
  383. // Parse the `of <selector-list>` syntax
  384. auto const& maybe_of = tokens.next_token();
  385. if (!maybe_of.is_ident("of"sv))
  386. return ParseError::SyntaxError;
  387. tokens.skip_whitespace();
  388. auto selector_list = TRY(parse_a_selector_list(tokens, SelectorType::Standalone));
  389. tokens.skip_whitespace();
  390. if (tokens.has_next_token())
  391. return ParseError::SyntaxError;
  392. return Selector::SimpleSelector {
  393. .type = Selector::SimpleSelector::Type::PseudoClass,
  394. .value = Selector::SimpleSelector::PseudoClassSelector {
  395. .type = pseudo_class,
  396. .nth_child_pattern = nth_child_pattern.release_value(),
  397. .argument_selector_list = move(selector_list) }
  398. };
  399. };
  400. auto const& pseudo_function = pseudo_class_token.function();
  401. auto maybe_pseudo_class = pseudo_class_from_string(pseudo_function.name());
  402. if (!maybe_pseudo_class.has_value()) {
  403. dbgln_if(CSS_PARSER_DEBUG, "Unrecognized pseudo-class function: ':{}'()", pseudo_function.name());
  404. return ParseError::SyntaxError;
  405. }
  406. auto pseudo_class = maybe_pseudo_class.value();
  407. auto metadata = pseudo_class_metadata(pseudo_class);
  408. if (!metadata.is_valid_as_function) {
  409. dbgln_if(CSS_PARSER_DEBUG, "Pseudo-class ':{}' is not valid as a function", pseudo_function.name());
  410. return ParseError::SyntaxError;
  411. }
  412. if (pseudo_function.values().is_empty()) {
  413. dbgln_if(CSS_PARSER_DEBUG, "Empty :{}() selector", pseudo_function.name());
  414. return ParseError::SyntaxError;
  415. }
  416. switch (metadata.parameter_type) {
  417. case PseudoClassMetadata::ParameterType::ANPlusB:
  418. return parse_nth_child_selector(pseudo_class, pseudo_function.values(), false);
  419. case PseudoClassMetadata::ParameterType::ANPlusBOf:
  420. return parse_nth_child_selector(pseudo_class, pseudo_function.values(), true);
  421. case PseudoClassMetadata::ParameterType::CompoundSelector: {
  422. auto function_token_stream = TokenStream(pseudo_function.values());
  423. auto compound_selector_or_error = parse_compound_selector(function_token_stream);
  424. if (compound_selector_or_error.is_error() || !compound_selector_or_error.value().has_value()) {
  425. dbgln_if(CSS_PARSER_DEBUG, "Failed to parse :{}() parameter as a compound selector", pseudo_function.name());
  426. return ParseError::SyntaxError;
  427. }
  428. auto compound_selector = compound_selector_or_error.release_value().release_value();
  429. compound_selector.combinator = Selector::Combinator::None;
  430. Vector compound_selectors { move(compound_selector) };
  431. auto selector = Selector::create(move(compound_selectors));
  432. return Selector::SimpleSelector {
  433. .type = Selector::SimpleSelector::Type::PseudoClass,
  434. .value = Selector::SimpleSelector::PseudoClassSelector {
  435. .type = pseudo_class,
  436. .argument_selector_list = { move(selector) } }
  437. };
  438. }
  439. case PseudoClassMetadata::ParameterType::ForgivingRelativeSelectorList:
  440. case PseudoClassMetadata::ParameterType::ForgivingSelectorList: {
  441. auto function_token_stream = TokenStream(pseudo_function.values());
  442. auto selector_type = metadata.parameter_type == PseudoClassMetadata::ParameterType::ForgivingSelectorList
  443. ? SelectorType::Standalone
  444. : SelectorType::Relative;
  445. // NOTE: Because it's forgiving, even complete garbage will parse OK as an empty selector-list.
  446. auto argument_selector_list = MUST(parse_a_selector_list(function_token_stream, selector_type, SelectorParsingMode::Forgiving));
  447. return Selector::SimpleSelector {
  448. .type = Selector::SimpleSelector::Type::PseudoClass,
  449. .value = Selector::SimpleSelector::PseudoClassSelector {
  450. .type = pseudo_class,
  451. .argument_selector_list = move(argument_selector_list) }
  452. };
  453. }
  454. case PseudoClassMetadata::ParameterType::Ident: {
  455. auto function_token_stream = TokenStream(pseudo_function.values());
  456. function_token_stream.skip_whitespace();
  457. auto maybe_ident_token = function_token_stream.next_token();
  458. function_token_stream.skip_whitespace();
  459. if (!maybe_ident_token.is(Token::Type::Ident) || function_token_stream.has_next_token()) {
  460. dbgln_if(CSS_PARSER_DEBUG, "Failed to parse :{}() parameter as an ident: not an ident", pseudo_function.name());
  461. return ParseError::SyntaxError;
  462. }
  463. auto maybe_ident = value_id_from_string(maybe_ident_token.token().ident());
  464. if (!maybe_ident.has_value()) {
  465. dbgln_if(CSS_PARSER_DEBUG, "Failed to parse :{}() parameter as an ident: unrecognized ident", pseudo_function.name());
  466. return ParseError::SyntaxError;
  467. }
  468. return Selector::SimpleSelector {
  469. .type = Selector::SimpleSelector::Type::PseudoClass,
  470. .value = Selector::SimpleSelector::PseudoClassSelector {
  471. .type = pseudo_class,
  472. .identifier = maybe_ident.value() }
  473. };
  474. }
  475. case PseudoClassMetadata::ParameterType::LanguageRanges: {
  476. Vector<FlyString> languages;
  477. auto function_token_stream = TokenStream(pseudo_function.values());
  478. auto language_token_lists = parse_a_comma_separated_list_of_component_values(function_token_stream);
  479. for (auto language_token_list : language_token_lists) {
  480. auto language_token_stream = TokenStream(language_token_list);
  481. language_token_stream.skip_whitespace();
  482. auto language_token = language_token_stream.next_token();
  483. if (!(language_token.is(Token::Type::Ident) || language_token.is(Token::Type::String))) {
  484. dbgln_if(CSS_PARSER_DEBUG, "Invalid language range in :{}() - not a string/ident", pseudo_function.name());
  485. return ParseError::SyntaxError;
  486. }
  487. auto language_string = language_token.is(Token::Type::String) ? language_token.token().string() : language_token.token().ident();
  488. languages.append(language_string);
  489. language_token_stream.skip_whitespace();
  490. if (language_token_stream.has_next_token()) {
  491. dbgln_if(CSS_PARSER_DEBUG, "Invalid language range in :{}() - trailing tokens", pseudo_function.name());
  492. return ParseError::SyntaxError;
  493. }
  494. }
  495. return Selector::SimpleSelector {
  496. .type = Selector::SimpleSelector::Type::PseudoClass,
  497. .value = Selector::SimpleSelector::PseudoClassSelector {
  498. .type = pseudo_class,
  499. .languages = move(languages) }
  500. };
  501. }
  502. case PseudoClassMetadata::ParameterType::SelectorList: {
  503. auto function_token_stream = TokenStream(pseudo_function.values());
  504. auto not_selector = TRY(parse_a_selector_list(function_token_stream, SelectorType::Standalone));
  505. return Selector::SimpleSelector {
  506. .type = Selector::SimpleSelector::Type::PseudoClass,
  507. .value = Selector::SimpleSelector::PseudoClassSelector {
  508. .type = pseudo_class,
  509. .argument_selector_list = move(not_selector) }
  510. };
  511. }
  512. case PseudoClassMetadata::ParameterType::None:
  513. // `None` means this is not a function-type pseudo-class, so this state should be impossible.
  514. VERIFY_NOT_REACHED();
  515. }
  516. }
  517. dbgln_if(CSS_PARSER_DEBUG, "Unexpected Block in pseudo-class name, expected a function or identifier. '{}'", pseudo_class_token.to_debug_string());
  518. return ParseError::SyntaxError;
  519. }
  520. Parser::ParseErrorOr<Optional<Selector::SimpleSelector>> Parser::parse_simple_selector(TokenStream<ComponentValue>& tokens)
  521. {
  522. auto peek_token_ends_selector = [&]() -> bool {
  523. auto const& value = tokens.peek_token();
  524. return (value.is(Token::Type::EndOfFile) || value.is(Token::Type::Whitespace) || value.is(Token::Type::Comma));
  525. };
  526. if (peek_token_ends_selector())
  527. return Optional<Selector::SimpleSelector> {};
  528. // Handle universal and tag-name types together, since both can be namespaced
  529. if (auto qualified_name = parse_selector_qualified_name(tokens, AllowWildcardName::Yes); qualified_name.has_value()) {
  530. if (qualified_name->name.name == "*"sv) {
  531. return Selector::SimpleSelector {
  532. .type = Selector::SimpleSelector::Type::Universal,
  533. .value = qualified_name.release_value(),
  534. };
  535. }
  536. return Selector::SimpleSelector {
  537. .type = Selector::SimpleSelector::Type::TagName,
  538. .value = qualified_name.release_value(),
  539. };
  540. }
  541. auto const& first_value = tokens.next_token();
  542. if (first_value.is(Token::Type::Delim)) {
  543. u32 delim = first_value.token().delim();
  544. switch (delim) {
  545. case '*':
  546. // Handled already
  547. VERIFY_NOT_REACHED();
  548. case '.': {
  549. if (peek_token_ends_selector())
  550. return ParseError::SyntaxError;
  551. auto const& class_name_value = tokens.next_token();
  552. if (!class_name_value.is(Token::Type::Ident)) {
  553. dbgln_if(CSS_PARSER_DEBUG, "Expected an ident after '.', got: {}", class_name_value.to_debug_string());
  554. return ParseError::SyntaxError;
  555. }
  556. return Selector::SimpleSelector {
  557. .type = Selector::SimpleSelector::Type::Class,
  558. .value = Selector::SimpleSelector::Name { class_name_value.token().ident() }
  559. };
  560. }
  561. case '>':
  562. case '+':
  563. case '~':
  564. case '|':
  565. // Whitespace is not required between the compound-selector and a combinator.
  566. // So, if we see a combinator, return that this compound-selector is done, instead of a syntax error.
  567. tokens.reconsume_current_input_token();
  568. return Optional<Selector::SimpleSelector> {};
  569. default:
  570. dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid simple selector!");
  571. return ParseError::SyntaxError;
  572. }
  573. }
  574. if (first_value.is(Token::Type::Hash)) {
  575. if (first_value.token().hash_type() != Token::HashType::Id) {
  576. dbgln_if(CSS_PARSER_DEBUG, "Selector contains hash token that is not an id: {}", first_value.to_debug_string());
  577. return ParseError::SyntaxError;
  578. }
  579. return Selector::SimpleSelector {
  580. .type = Selector::SimpleSelector::Type::Id,
  581. .value = Selector::SimpleSelector::Name { first_value.token().hash_value() }
  582. };
  583. }
  584. if (first_value.is_block() && first_value.block().is_square())
  585. return TRY(parse_attribute_simple_selector(first_value));
  586. if (first_value.is(Token::Type::Colon))
  587. return TRY(parse_pseudo_simple_selector(tokens));
  588. dbgln_if(CSS_PARSER_DEBUG, "!!! Invalid simple selector!");
  589. return ParseError::SyntaxError;
  590. }
  591. Optional<Selector::SimpleSelector::ANPlusBPattern> Parser::parse_a_n_plus_b_pattern(TokenStream<ComponentValue>& values)
  592. {
  593. auto transaction = values.begin_transaction();
  594. auto syntax_error = [&]() -> Optional<Selector::SimpleSelector::ANPlusBPattern> {
  595. if constexpr (CSS_PARSER_DEBUG) {
  596. dbgln_if(CSS_PARSER_DEBUG, "Invalid An+B value:");
  597. values.dump_all_tokens();
  598. }
  599. return {};
  600. };
  601. auto is_sign = [](ComponentValue const& value) -> bool {
  602. return value.is(Token::Type::Delim) && (value.token().delim() == '+' || value.token().delim() == '-');
  603. };
  604. auto is_n_dimension = [](ComponentValue const& value) -> bool {
  605. if (!value.is(Token::Type::Dimension))
  606. return false;
  607. if (!value.token().number().is_integer())
  608. return false;
  609. if (!value.token().dimension_unit().equals_ignoring_ascii_case("n"sv))
  610. return false;
  611. return true;
  612. };
  613. auto is_ndash_dimension = [](ComponentValue const& value) -> bool {
  614. if (!value.is(Token::Type::Dimension))
  615. return false;
  616. if (!value.token().number().is_integer())
  617. return false;
  618. if (!value.token().dimension_unit().equals_ignoring_ascii_case("n-"sv))
  619. return false;
  620. return true;
  621. };
  622. auto is_ndashdigit_dimension = [](ComponentValue const& value) -> bool {
  623. if (!value.is(Token::Type::Dimension))
  624. return false;
  625. if (!value.token().number().is_integer())
  626. return false;
  627. auto dimension_unit = value.token().dimension_unit();
  628. if (!dimension_unit.starts_with_bytes("n-"sv, CaseSensitivity::CaseInsensitive))
  629. return false;
  630. for (size_t i = 2; i < dimension_unit.bytes_as_string_view().length(); ++i) {
  631. if (!is_ascii_digit(dimension_unit.bytes_as_string_view()[i]))
  632. return false;
  633. }
  634. return true;
  635. };
  636. auto is_ndashdigit_ident = [](ComponentValue const& value) -> bool {
  637. if (!value.is(Token::Type::Ident))
  638. return false;
  639. auto ident = value.token().ident();
  640. if (!ident.starts_with_bytes("n-"sv, CaseSensitivity::CaseInsensitive))
  641. return false;
  642. for (size_t i = 2; i < ident.bytes_as_string_view().length(); ++i) {
  643. if (!is_ascii_digit(ident.bytes_as_string_view()[i]))
  644. return false;
  645. }
  646. return true;
  647. };
  648. auto is_dashndashdigit_ident = [](ComponentValue const& value) -> bool {
  649. if (!value.is(Token::Type::Ident))
  650. return false;
  651. auto ident = value.token().ident();
  652. if (!ident.starts_with_bytes("-n-"sv, CaseSensitivity::CaseInsensitive))
  653. return false;
  654. if (ident.bytes_as_string_view().length() == 3)
  655. return false;
  656. for (size_t i = 3; i < ident.bytes_as_string_view().length(); ++i) {
  657. if (!is_ascii_digit(ident.bytes_as_string_view()[i]))
  658. return false;
  659. }
  660. return true;
  661. };
  662. auto is_integer = [](ComponentValue const& value) -> bool {
  663. return value.is(Token::Type::Number) && value.token().number().is_integer();
  664. };
  665. auto is_signed_integer = [](ComponentValue const& value) -> bool {
  666. return value.is(Token::Type::Number) && value.token().number().is_integer_with_explicit_sign();
  667. };
  668. auto is_signless_integer = [](ComponentValue const& value) -> bool {
  669. return value.is(Token::Type::Number) && !value.token().number().is_integer_with_explicit_sign();
  670. };
  671. // https://www.w3.org/TR/css-syntax-3/#the-anb-type
  672. // Unfortunately these can't be in the same order as in the spec.
  673. values.skip_whitespace();
  674. auto const& first_value = values.next_token();
  675. // odd | even
  676. if (first_value.is(Token::Type::Ident)) {
  677. auto ident = first_value.token().ident();
  678. if (ident.equals_ignoring_ascii_case("odd"sv)) {
  679. transaction.commit();
  680. return Selector::SimpleSelector::ANPlusBPattern { 2, 1 };
  681. }
  682. if (ident.equals_ignoring_ascii_case("even"sv)) {
  683. transaction.commit();
  684. return Selector::SimpleSelector::ANPlusBPattern { 2, 0 };
  685. }
  686. }
  687. // <integer>
  688. if (is_integer(first_value)) {
  689. int b = first_value.token().to_integer();
  690. transaction.commit();
  691. return Selector::SimpleSelector::ANPlusBPattern { 0, b };
  692. }
  693. // <n-dimension>
  694. // <n-dimension> <signed-integer>
  695. // <n-dimension> ['+' | '-'] <signless-integer>
  696. if (is_n_dimension(first_value)) {
  697. int a = first_value.token().dimension_value_int();
  698. values.skip_whitespace();
  699. // <n-dimension> <signed-integer>
  700. if (is_signed_integer(values.peek_token())) {
  701. int b = values.next_token().token().to_integer();
  702. transaction.commit();
  703. return Selector::SimpleSelector::ANPlusBPattern { a, b };
  704. }
  705. // <n-dimension> ['+' | '-'] <signless-integer>
  706. {
  707. auto child_transaction = transaction.create_child();
  708. auto const& second_value = values.next_token();
  709. values.skip_whitespace();
  710. auto const& third_value = values.next_token();
  711. if (is_sign(second_value) && is_signless_integer(third_value)) {
  712. int b = third_value.token().to_integer() * (second_value.is_delim('+') ? 1 : -1);
  713. child_transaction.commit();
  714. return Selector::SimpleSelector::ANPlusBPattern { a, b };
  715. }
  716. }
  717. // <n-dimension>
  718. transaction.commit();
  719. return Selector::SimpleSelector::ANPlusBPattern { a, 0 };
  720. }
  721. // <ndash-dimension> <signless-integer>
  722. if (is_ndash_dimension(first_value)) {
  723. values.skip_whitespace();
  724. auto const& second_value = values.next_token();
  725. if (is_signless_integer(second_value)) {
  726. int a = first_value.token().dimension_value_int();
  727. int b = -second_value.token().to_integer();
  728. transaction.commit();
  729. return Selector::SimpleSelector::ANPlusBPattern { a, b };
  730. }
  731. return syntax_error();
  732. }
  733. // <ndashdigit-dimension>
  734. if (is_ndashdigit_dimension(first_value)) {
  735. auto const& dimension = first_value.token();
  736. int a = dimension.dimension_value_int();
  737. auto maybe_b = dimension.dimension_unit().bytes_as_string_view().substring_view(1).to_number<int>();
  738. if (maybe_b.has_value()) {
  739. transaction.commit();
  740. return Selector::SimpleSelector::ANPlusBPattern { a, maybe_b.value() };
  741. }
  742. return syntax_error();
  743. }
  744. // <dashndashdigit-ident>
  745. if (is_dashndashdigit_ident(first_value)) {
  746. auto maybe_b = first_value.token().ident().bytes_as_string_view().substring_view(2).to_number<int>();
  747. if (maybe_b.has_value()) {
  748. transaction.commit();
  749. return Selector::SimpleSelector::ANPlusBPattern { -1, maybe_b.value() };
  750. }
  751. return syntax_error();
  752. }
  753. // -n
  754. // -n <signed-integer>
  755. // -n ['+' | '-'] <signless-integer>
  756. if (first_value.is_ident("-n"sv)) {
  757. values.skip_whitespace();
  758. // -n <signed-integer>
  759. if (is_signed_integer(values.peek_token())) {
  760. int b = values.next_token().token().to_integer();
  761. transaction.commit();
  762. return Selector::SimpleSelector::ANPlusBPattern { -1, b };
  763. }
  764. // -n ['+' | '-'] <signless-integer>
  765. {
  766. auto child_transaction = transaction.create_child();
  767. auto const& second_value = values.next_token();
  768. values.skip_whitespace();
  769. auto const& third_value = values.next_token();
  770. if (is_sign(second_value) && is_signless_integer(third_value)) {
  771. int b = third_value.token().to_integer() * (second_value.is_delim('+') ? 1 : -1);
  772. child_transaction.commit();
  773. return Selector::SimpleSelector::ANPlusBPattern { -1, b };
  774. }
  775. }
  776. // -n
  777. transaction.commit();
  778. return Selector::SimpleSelector::ANPlusBPattern { -1, 0 };
  779. }
  780. // -n- <signless-integer>
  781. if (first_value.is_ident("-n-"sv)) {
  782. values.skip_whitespace();
  783. auto const& second_value = values.next_token();
  784. if (is_signless_integer(second_value)) {
  785. int b = -second_value.token().to_integer();
  786. transaction.commit();
  787. return Selector::SimpleSelector::ANPlusBPattern { -1, b };
  788. }
  789. return syntax_error();
  790. }
  791. // All that's left now are these:
  792. // '+'?† n
  793. // '+'?† n <signed-integer>
  794. // '+'?† n ['+' | '-'] <signless-integer>
  795. // '+'?† n- <signless-integer>
  796. // '+'?† <ndashdigit-ident>
  797. // In all of these cases, the + is optional, and has no effect.
  798. // So, we just skip the +, and carry on.
  799. if (!first_value.is_delim('+')) {
  800. values.reconsume_current_input_token();
  801. // We do *not* skip whitespace here.
  802. }
  803. auto const& first_after_plus = values.next_token();
  804. // '+'?† n
  805. // '+'?† n <signed-integer>
  806. // '+'?† n ['+' | '-'] <signless-integer>
  807. if (first_after_plus.is_ident("n"sv)) {
  808. values.skip_whitespace();
  809. // '+'?† n <signed-integer>
  810. if (is_signed_integer(values.peek_token())) {
  811. int b = values.next_token().token().to_integer();
  812. transaction.commit();
  813. return Selector::SimpleSelector::ANPlusBPattern { 1, b };
  814. }
  815. // '+'?† n ['+' | '-'] <signless-integer>
  816. {
  817. auto child_transaction = transaction.create_child();
  818. auto const& second_value = values.next_token();
  819. values.skip_whitespace();
  820. auto const& third_value = values.next_token();
  821. if (is_sign(second_value) && is_signless_integer(third_value)) {
  822. int b = third_value.token().to_integer() * (second_value.is_delim('+') ? 1 : -1);
  823. child_transaction.commit();
  824. return Selector::SimpleSelector::ANPlusBPattern { 1, b };
  825. }
  826. }
  827. // '+'?† n
  828. transaction.commit();
  829. return Selector::SimpleSelector::ANPlusBPattern { 1, 0 };
  830. }
  831. // '+'?† n- <signless-integer>
  832. if (first_after_plus.is_ident("n-"sv)) {
  833. values.skip_whitespace();
  834. auto const& second_value = values.next_token();
  835. if (is_signless_integer(second_value)) {
  836. int b = -second_value.token().to_integer();
  837. transaction.commit();
  838. return Selector::SimpleSelector::ANPlusBPattern { 1, b };
  839. }
  840. return syntax_error();
  841. }
  842. // '+'?† <ndashdigit-ident>
  843. if (is_ndashdigit_ident(first_after_plus)) {
  844. auto maybe_b = first_after_plus.token().ident().bytes_as_string_view().substring_view(1).to_number<int>();
  845. if (maybe_b.has_value()) {
  846. transaction.commit();
  847. return Selector::SimpleSelector::ANPlusBPattern { 1, maybe_b.value() };
  848. }
  849. return syntax_error();
  850. }
  851. return syntax_error();
  852. }
  853. }