Parser.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. /*
  2. * Copyright (c) 2020-2021, the SerenityOS developers.
  3. * Copyright (c) 2021, Sam Atkins <atkinssj@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/NonnullRefPtrVector.h>
  8. #include <AK/SourceLocation.h>
  9. #include <LibWeb/CSS/CSSStyleDeclaration.h>
  10. #include <LibWeb/CSS/CSSStyleRule.h>
  11. #include <LibWeb/CSS/CSSStyleSheet.h>
  12. #include <LibWeb/CSS/Parser/AtStyleRule.h>
  13. #include <LibWeb/CSS/Parser/DeclarationOrAtRule.h>
  14. #include <LibWeb/CSS/Parser/Parser.h>
  15. #include <LibWeb/CSS/Parser/QualifiedStyleRule.h>
  16. #include <LibWeb/CSS/Parser/StyleBlockRule.h>
  17. #include <LibWeb/CSS/Parser/StyleComponentValueRule.h>
  18. #include <LibWeb/CSS/Parser/StyleFunctionRule.h>
  19. #include <LibWeb/CSS/Selector.h>
  20. #include <LibWeb/Dump.h>
  21. #define CSS_PARSER_TRACE 1
  22. static void log_parse_error(const SourceLocation& location = SourceLocation::current())
  23. {
  24. dbgln_if(CSS_PARSER_TRACE, "Parse error (CSS) {}", location);
  25. }
  26. namespace Web::CSS {
  27. Parser::Parser(const StringView& input, const String& encoding)
  28. : m_tokenizer(input, encoding)
  29. {
  30. m_tokens = m_tokenizer.parse();
  31. }
  32. Parser::~Parser()
  33. {
  34. }
  35. Token Parser::peek_token()
  36. {
  37. size_t next_offset = m_iterator_offset + 1;
  38. if (next_offset < m_tokens.size()) {
  39. return m_tokens.at(next_offset);
  40. }
  41. return m_tokens.at(m_iterator_offset);
  42. }
  43. Token Parser::next_token()
  44. {
  45. if (m_iterator_offset < (int)m_tokens.size() - 1) {
  46. ++m_iterator_offset;
  47. }
  48. auto token = m_tokens.at(m_iterator_offset);
  49. return token;
  50. }
  51. Token Parser::current_token()
  52. {
  53. return m_tokens.at(m_iterator_offset);
  54. }
  55. NonnullRefPtr<CSSStyleSheet> Parser::parse_as_stylesheet()
  56. {
  57. auto parser_rules = consume_a_list_of_rules(true);
  58. NonnullRefPtrVector<CSSRule> rules;
  59. dbgln("Printing rules:");
  60. for (auto& rule : parser_rules) {
  61. dbgln("PRE:");
  62. for (auto& pre : rule.m_prelude) {
  63. dbgln("{}", pre.to_string());
  64. }
  65. dbgln("BLOCK:");
  66. dbgln("{}", rule.block().to_string());
  67. dbgln("");
  68. auto css_rule = convert_rule(rule);
  69. if (css_rule)
  70. rules.append(*css_rule);
  71. }
  72. return CSSStyleSheet::create(rules);
  73. }
  74. Vector<CSS::Selector::ComplexSelector> Parser::parse_selectors(Vector<StyleComponentValueRule> parts)
  75. {
  76. Vector<CSS::Selector::ComplexSelector> selectors;
  77. size_t index = 0;
  78. auto parse_simple_selector = [&]() -> Optional<CSS::Selector::SimpleSelector> {
  79. if (index >= parts.size())
  80. return {};
  81. auto& current_value = parts.at(index);
  82. index++;
  83. CSS::Selector::SimpleSelector::Type type;
  84. String value;
  85. // FIXME: Handle namespace prefixes.
  86. if (current_value.is(Token::TokenType::Delim) && current_value.token().delim() == "*") {
  87. // FIXME: Handle selectors like `*.foo`.
  88. type = CSS::Selector::SimpleSelector::Type::Universal;
  89. CSS::Selector::SimpleSelector result;
  90. result.type = type;
  91. return result;
  92. }
  93. if (current_value.is(Token::TokenType::Hash)) {
  94. if (current_value.token().m_hash_type != Token::HashType::Id) {
  95. dbgln("Selector contains hash token that is not an id: {}", current_value.to_string());
  96. return {};
  97. }
  98. type = CSS::Selector::SimpleSelector::Type::Id;
  99. value = current_value.token().m_value.to_string();
  100. } else if (current_value.is(Token::TokenType::Delim) && current_value.token().delim() == ".") {
  101. if (index >= parts.size())
  102. return {};
  103. current_value = parts.at(index);
  104. index++;
  105. if (!current_value.is(Token::TokenType::Ident)) {
  106. dbgln("Expected an ident after '.', got: {}", current_value.to_string());
  107. return {};
  108. }
  109. type = CSS::Selector::SimpleSelector::Type::Class;
  110. value = current_value.to_string();
  111. } else if (current_value.is(Token::TokenType::Delim) && current_value.token().delim() == "*") {
  112. type = CSS::Selector::SimpleSelector::Type::Universal;
  113. } else {
  114. type = CSS::Selector::SimpleSelector::Type::TagName;
  115. value = current_value.to_string().to_lowercase();
  116. }
  117. CSS::Selector::SimpleSelector simple_selector;
  118. simple_selector.type = type;
  119. simple_selector.value = value;
  120. if (index >= parts.size())
  121. return simple_selector;
  122. current_value = parts.at(index);
  123. index++;
  124. // FIXME: Attribute selectors want to be their own Selector::SimpleSelector::Type according to the spec.
  125. if (current_value.is_block() && current_value.block().is_square()) {
  126. Vector<StyleComponentValueRule> const& attribute_parts = current_value.block().values();
  127. // FIXME: Handle namespace prefix for attribute name.
  128. auto& attribute_part = attribute_parts.first();
  129. if (!attribute_part.is(Token::TokenType::Ident)) {
  130. dbgln("Expected ident for attribute name, got: '{}'", attribute_part.to_string());
  131. return {};
  132. }
  133. simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::HasAttribute;
  134. simple_selector.attribute_name = attribute_part.token().ident();
  135. size_t attribute_index = 1;
  136. while (attribute_parts.at(attribute_index).is(Token::TokenType::Whitespace)) {
  137. attribute_index++;
  138. if (attribute_index >= attribute_parts.size())
  139. return simple_selector;
  140. }
  141. auto& delim_part = attribute_parts.at(attribute_index);
  142. if (!delim_part.is(Token::TokenType::Delim)) {
  143. dbgln("Expected a delim for attribute comparison, got: '{}'", delim_part.to_string());
  144. return {};
  145. }
  146. if (delim_part.token().delim() == "=") {
  147. simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::ExactValueMatch;
  148. attribute_index++;
  149. } else {
  150. attribute_index++;
  151. auto& delim_second_part = attribute_parts.at(attribute_index);
  152. if (!(delim_part.is(Token::TokenType::Delim) && delim_part.token().delim() == "=")) {
  153. dbgln("Expected a double delim for attribute comparison, got: '{}{}'", delim_part.to_string(), delim_second_part.to_string());
  154. return {};
  155. }
  156. if (delim_part.token().delim() == "~") {
  157. simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::ContainsWord;
  158. attribute_index++;
  159. } else if (delim_part.token().delim() == "*") {
  160. simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::ContainsString;
  161. attribute_index++;
  162. } else if (delim_part.token().delim() == "|") {
  163. simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::StartsWithSegment;
  164. attribute_index++;
  165. } else if (delim_part.token().delim() == "^") {
  166. simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::StartsWithString;
  167. attribute_index++;
  168. } else if (delim_part.token().delim() == "$") {
  169. simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::EndsWithString;
  170. attribute_index++;
  171. }
  172. }
  173. while (attribute_parts.at(attribute_index).is(Token::TokenType::Whitespace)) {
  174. attribute_index++;
  175. if (attribute_index >= attribute_parts.size()) {
  176. dbgln("Attribute selector ended without a value to match.");
  177. return {};
  178. }
  179. }
  180. auto& value_part = attribute_parts.at(attribute_index);
  181. if (!value_part.is(Token::TokenType::Ident) && !value_part.is(Token::TokenType::String)) {
  182. dbgln("Expected a string or ident for the value to match attribute against, got: '{}'", value_part.to_string());
  183. return {};
  184. }
  185. simple_selector.attribute_value = value_part.token().is_ident() ? value_part.token().ident() : value_part.token().string();
  186. // FIXME: Handle case-sensitivity suffixes. https://www.w3.org/TR/selectors-4/#attribute-case
  187. return simple_selector;
  188. }
  189. // FIXME: Pseudo-class selectors want to be their own Selector::SimpleSelector::Type according to the spec.
  190. if (current_value.is(Token::TokenType::Colon)) {
  191. bool is_pseudo = false;
  192. current_value = parts.at(index);
  193. index++;
  194. if (index >= parts.size())
  195. return {};
  196. if (current_value.is(Token::TokenType::Colon)) {
  197. is_pseudo = true;
  198. current_value = parts.at(index);
  199. index++;
  200. if (index >= parts.size())
  201. return {};
  202. }
  203. // Ignore for now, otherwise we produce a "false positive" selector
  204. // and apply styles to the element itself, not its pseudo element
  205. if (is_pseudo)
  206. return {};
  207. current_value = parts.at(index);
  208. index++;
  209. if (current_value.is(Token::TokenType::Ident)) {
  210. auto pseudo_name = current_value.token().ident();
  211. if (pseudo_name.equals_ignoring_case("link")) {
  212. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Link;
  213. } else if (pseudo_name.equals_ignoring_case("visited")) {
  214. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Visited;
  215. } else if (pseudo_name.equals_ignoring_case("active")) {
  216. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Active;
  217. } else if (pseudo_name.equals_ignoring_case("hover")) {
  218. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Hover;
  219. } else if (pseudo_name.equals_ignoring_case("focus")) {
  220. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Focus;
  221. } else if (pseudo_name.equals_ignoring_case("first-child")) {
  222. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::FirstChild;
  223. } else if (pseudo_name.equals_ignoring_case("last-child")) {
  224. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::LastChild;
  225. } else if (pseudo_name.equals_ignoring_case("only-child")) {
  226. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::OnlyChild;
  227. } else if (pseudo_name.equals_ignoring_case("empty")) {
  228. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Empty;
  229. } else if (pseudo_name.equals_ignoring_case("root")) {
  230. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Root;
  231. } else if (pseudo_name.equals_ignoring_case("first-of-type")) {
  232. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::FirstOfType;
  233. } else if (pseudo_name.equals_ignoring_case("last-of-type")) {
  234. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::LastOfType;
  235. } else if (pseudo_name.equals_ignoring_case("before")) {
  236. simple_selector.pseudo_element = CSS::Selector::SimpleSelector::PseudoElement::Before;
  237. } else if (pseudo_name.equals_ignoring_case("after")) {
  238. simple_selector.pseudo_element = CSS::Selector::SimpleSelector::PseudoElement::After;
  239. } else if (pseudo_name.equals_ignoring_case("disabled")) {
  240. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Disabled;
  241. } else if (pseudo_name.equals_ignoring_case("enabled")) {
  242. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Enabled;
  243. } else if (pseudo_name.equals_ignoring_case("checked")) {
  244. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Checked;
  245. } else {
  246. dbgln("Unknown pseudo class: '{}'", pseudo_name);
  247. return simple_selector;
  248. }
  249. } else if (current_value.is_function()) {
  250. auto& pseudo_function = current_value.function();
  251. if (pseudo_function.name().equals_ignoring_case("nth-child")) {
  252. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::NthChild;
  253. simple_selector.nth_child_pattern = CSS::Selector::SimpleSelector::NthChildPattern::parse(pseudo_function.values_as_string());
  254. } else if (pseudo_function.name().equals_ignoring_case("nth-last-child")) {
  255. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::NthLastChild;
  256. simple_selector.nth_child_pattern = CSS::Selector::SimpleSelector::NthChildPattern::parse(pseudo_function.values_as_string());
  257. } else if (pseudo_function.name().equals_ignoring_case("not")) {
  258. simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::Not;
  259. simple_selector.not_selector = pseudo_function.values_as_string();
  260. } else {
  261. dbgln("Unknown pseudo class: '{}'()", pseudo_function.name());
  262. return simple_selector;
  263. }
  264. } else {
  265. dbgln("Unexpected Block in pseudo-class name, expected a function or identifier. '{}'", current_value.to_string());
  266. return simple_selector;
  267. }
  268. }
  269. return simple_selector;
  270. };
  271. auto parse_complex_selector = [&]() -> Optional<CSS::Selector::ComplexSelector> {
  272. auto relation = CSS::Selector::ComplexSelector::Relation::Descendant;
  273. if (index >= parts.size())
  274. return {};
  275. auto current_value = parts.at(index);
  276. if (current_value.is(Token::TokenType::Delim)) {
  277. auto delim = current_value.token().delim();
  278. if (delim == ">") {
  279. relation = CSS::Selector::ComplexSelector::Relation::ImmediateChild;
  280. index++;
  281. } else if (delim == "+") {
  282. relation = CSS::Selector::ComplexSelector::Relation::AdjacentSibling;
  283. index++;
  284. } else if (delim == "~") {
  285. relation = CSS::Selector::ComplexSelector::Relation::GeneralSibling;
  286. index++;
  287. } else if (delim == "|") {
  288. if (index + 1 >= parts.size())
  289. return {};
  290. auto next = parts.at(index + 1);
  291. if (next.is(Token::TokenType::Delim) && next.token().delim() == "|") {
  292. relation = CSS::Selector::ComplexSelector::Relation::Column;
  293. index += 2;
  294. }
  295. }
  296. }
  297. Vector<CSS::Selector::SimpleSelector> simple_selectors;
  298. for (;;) {
  299. auto component = parse_simple_selector();
  300. if (!component.has_value())
  301. break;
  302. simple_selectors.append(component.value());
  303. }
  304. if (simple_selectors.is_empty())
  305. return {};
  306. return CSS::Selector::ComplexSelector { relation, move(simple_selectors) };
  307. };
  308. for (;;) {
  309. auto complex = parse_complex_selector();
  310. if (complex.has_value())
  311. selectors.append(complex.value());
  312. if (index >= parts.size())
  313. break;
  314. auto current_value = parts.at(index);
  315. if (current_value.is(Token::TokenType::Comma))
  316. break;
  317. index++;
  318. }
  319. if (selectors.is_empty())
  320. return {};
  321. selectors.first().relation = CSS::Selector::ComplexSelector::Relation::None;
  322. return selectors;
  323. }
  324. void Parser::dump_all_tokens()
  325. {
  326. dbgln("Dumping all tokens:");
  327. for (auto& token : m_tokens)
  328. dbgln("{}", token.to_string());
  329. }
  330. void Parser::reconsume_current_input_token()
  331. {
  332. --m_iterator_offset;
  333. }
  334. NonnullRefPtrVector<QualifiedStyleRule> Parser::consume_a_list_of_rules(bool top_level)
  335. {
  336. NonnullRefPtrVector<QualifiedStyleRule> rules;
  337. for (;;) {
  338. auto token = next_token();
  339. if (token.is_whitespace()) {
  340. continue;
  341. }
  342. if (token.is_eof()) {
  343. break;
  344. }
  345. if (token.is_cdo() || token.is_cdc()) {
  346. if (top_level) {
  347. continue;
  348. }
  349. reconsume_current_input_token();
  350. auto maybe_qualified = consume_a_qualified_rule();
  351. if (maybe_qualified) {
  352. rules.append(maybe_qualified.release_nonnull());
  353. }
  354. continue;
  355. }
  356. if (token.is_at()) {
  357. reconsume_current_input_token();
  358. rules.append(consume_an_at_rule());
  359. continue;
  360. }
  361. reconsume_current_input_token();
  362. auto maybe_qualified = consume_a_qualified_rule();
  363. if (maybe_qualified) {
  364. rules.append(maybe_qualified.release_nonnull());
  365. }
  366. }
  367. return rules;
  368. }
  369. NonnullRefPtr<AtStyleRule> Parser::consume_an_at_rule()
  370. {
  371. auto initial = next_token();
  372. AtStyleRule rule;
  373. rule.m_name = initial.m_value.to_string();
  374. for (;;) {
  375. auto token = next_token();
  376. if (token.is_semicolon()) {
  377. return rule;
  378. }
  379. if (token.is_eof()) {
  380. log_parse_error();
  381. return rule;
  382. }
  383. if (token.is_open_curly()) {
  384. rule.m_block = consume_a_simple_block();
  385. return rule;
  386. }
  387. // how is "simple block with an associated token of <{-token>" a valid token?
  388. reconsume_current_input_token();
  389. auto value = consume_a_component_value();
  390. rule.m_prelude.append(value);
  391. }
  392. }
  393. RefPtr<QualifiedStyleRule> Parser::consume_a_qualified_rule()
  394. {
  395. NonnullRefPtr<QualifiedStyleRule> rule = create<QualifiedStyleRule>();
  396. for (;;) {
  397. auto token = next_token();
  398. if (token.is_eof()) {
  399. log_parse_error();
  400. return {};
  401. }
  402. if (token.is_open_curly()) {
  403. rule->m_block = consume_a_simple_block();
  404. return rule;
  405. }
  406. // how is "simple block with an associated token of <{-token>" a valid token?
  407. reconsume_current_input_token();
  408. auto value = consume_a_component_value();
  409. rule->m_prelude.append(value);
  410. }
  411. return rule;
  412. }
  413. StyleComponentValueRule Parser::consume_a_component_value()
  414. {
  415. auto token = next_token();
  416. if (token.is_open_curly() || token.is_open_square() || token.is_open_paren()) {
  417. auto component = StyleComponentValueRule(StyleComponentValueRule::ComponentType::Block);
  418. component.m_block = consume_a_simple_block();
  419. return component;
  420. }
  421. if (token.is_function()) {
  422. auto component = StyleComponentValueRule(StyleComponentValueRule::ComponentType::Function);
  423. component.m_function = consume_a_function();
  424. return component;
  425. }
  426. auto component = StyleComponentValueRule(StyleComponentValueRule::ComponentType::Token);
  427. component.m_token = token;
  428. return component;
  429. }
  430. NonnullRefPtr<StyleBlockRule> Parser::consume_a_simple_block()
  431. {
  432. auto ending_token = current_token().mirror_variant();
  433. NonnullRefPtr<StyleBlockRule> block = create<StyleBlockRule>();
  434. block->m_token = current_token();
  435. for (;;) {
  436. auto token = next_token();
  437. if (token.m_type == ending_token) {
  438. return block;
  439. }
  440. if (token.is_eof()) {
  441. log_parse_error();
  442. return block;
  443. }
  444. reconsume_current_input_token();
  445. auto value = consume_a_component_value();
  446. if (value.m_type == StyleComponentValueRule::ComponentType::Token) {
  447. if (value.m_token.is_whitespace()) {
  448. continue;
  449. }
  450. }
  451. block->m_values.append(value);
  452. }
  453. }
  454. NonnullRefPtr<StyleFunctionRule> Parser::consume_a_function()
  455. {
  456. NonnullRefPtr<StyleFunctionRule> function = create<StyleFunctionRule>(current_token().m_value.to_string());
  457. for (;;) {
  458. auto token = next_token();
  459. if (token.is_close_paren()) {
  460. return function;
  461. }
  462. if (token.is_eof()) {
  463. log_parse_error();
  464. return function;
  465. }
  466. reconsume_current_input_token();
  467. auto value = consume_a_component_value();
  468. if (value.m_type == StyleComponentValueRule::ComponentType::Token) {
  469. if (value.m_token.is_whitespace()) {
  470. continue;
  471. }
  472. }
  473. function->m_values.append(value.to_string());
  474. }
  475. return function;
  476. }
  477. Optional<StyleDeclarationRule> Parser::consume_a_declaration(Vector<StyleComponentValueRule>)
  478. {
  479. TODO();
  480. }
  481. Optional<StyleDeclarationRule> Parser::consume_a_declaration()
  482. {
  483. auto token = next_token();
  484. StyleDeclarationRule declaration;
  485. declaration.m_name = token.m_value.to_string();
  486. for (;;) {
  487. if (!peek_token().is_whitespace()) {
  488. break;
  489. }
  490. next_token();
  491. }
  492. auto colon = next_token();
  493. if (!colon.is_colon()) {
  494. log_parse_error();
  495. return {};
  496. }
  497. for (;;) {
  498. if (!peek_token().is_whitespace()) {
  499. break;
  500. }
  501. next_token();
  502. }
  503. for (;;) {
  504. if (peek_token().is_eof()) {
  505. break;
  506. }
  507. declaration.m_values.append(consume_a_component_value());
  508. }
  509. auto second_last = declaration.m_values.at(declaration.m_values.size() - 2);
  510. auto last = declaration.m_values.at(declaration.m_values.size() - 1);
  511. if (second_last.m_type == StyleComponentValueRule::ComponentType::Token && last.m_type == StyleComponentValueRule::ComponentType::Token) {
  512. auto last_token = last.m_token;
  513. auto second_last_token = second_last.m_token;
  514. if (second_last_token.is_delim() && second_last_token.m_value.to_string().equals_ignoring_case("!")) {
  515. if (last_token.is_ident() && last_token.m_value.to_string().equals_ignoring_case("important")) {
  516. declaration.m_values.remove(declaration.m_values.size() - 2);
  517. declaration.m_values.remove(declaration.m_values.size() - 1);
  518. declaration.m_important = true;
  519. }
  520. }
  521. }
  522. for (;;) {
  523. auto maybe_whitespace = declaration.m_values.at(declaration.m_values.size() - 1);
  524. if (!(maybe_whitespace.m_type == StyleComponentValueRule::ComponentType::Token && maybe_whitespace.m_token.is_whitespace())) {
  525. break;
  526. }
  527. declaration.m_values.remove(declaration.m_values.size() - 1);
  528. }
  529. return declaration;
  530. }
  531. Vector<DeclarationOrAtRule> Parser::consume_a_list_of_declarations()
  532. {
  533. Vector<DeclarationOrAtRule> list;
  534. for (;;) {
  535. auto token = next_token();
  536. if (token.is_whitespace() || token.is_semicolon()) {
  537. continue;
  538. }
  539. if (token.is_eof()) {
  540. return list;
  541. }
  542. if (token.is_at()) {
  543. reconsume_current_input_token();
  544. list.append(DeclarationOrAtRule(consume_an_at_rule()));
  545. continue;
  546. }
  547. if (token.is_ident()) {
  548. Vector<StyleComponentValueRule> temp;
  549. auto component = StyleComponentValueRule(StyleComponentValueRule::ComponentType::Token);
  550. component.m_token = token;
  551. temp.append(component);
  552. for (;;) {
  553. auto peek = peek_token();
  554. if (peek.is_semicolon() || peek.is_eof()) {
  555. break;
  556. }
  557. temp.append(consume_a_component_value());
  558. }
  559. auto maybe_declaration = consume_a_declaration(temp);
  560. if (maybe_declaration.has_value()) {
  561. list.append(DeclarationOrAtRule(maybe_declaration.value()));
  562. }
  563. }
  564. log_parse_error();
  565. reconsume_current_input_token();
  566. auto peek = peek_token();
  567. if (!(peek.is_semicolon() || peek.is_eof())) {
  568. consume_a_component_value();
  569. }
  570. }
  571. return list;
  572. }
  573. RefPtr<CSSRule> Parser::parse_as_rule()
  574. {
  575. RefPtr<CSSRule> rule;
  576. for (;;) {
  577. auto maybe_whitespace = peek_token();
  578. if (!maybe_whitespace.is_whitespace()) {
  579. break;
  580. }
  581. next_token();
  582. }
  583. auto token = peek_token();
  584. if (token.is_eof()) {
  585. return {};
  586. } else if (token.is_at()) {
  587. auto at_rule = consume_an_at_rule();
  588. rule = convert_rule(at_rule);
  589. } else {
  590. auto qualified_rule = consume_a_qualified_rule();
  591. if (!qualified_rule)
  592. return {};
  593. rule = convert_rule(*qualified_rule);
  594. }
  595. for (;;) {
  596. auto maybe_whitespace = peek_token();
  597. if (!maybe_whitespace.is_whitespace()) {
  598. break;
  599. }
  600. next_token();
  601. }
  602. auto maybe_eof = peek_token();
  603. if (maybe_eof.is_eof()) {
  604. return rule;
  605. }
  606. return {};
  607. }
  608. NonnullRefPtrVector<CSSRule> Parser::parse_as_list_of_rules()
  609. {
  610. auto parsed_rules = consume_a_list_of_rules(false);
  611. NonnullRefPtrVector<CSSRule> rules;
  612. for (auto& rule : parsed_rules) {
  613. auto converted_rule = convert_rule(rule);
  614. if (converted_rule)
  615. rules.append(*converted_rule);
  616. }
  617. return rules;
  618. }
  619. Optional<StyleProperty> Parser::parse_as_declaration()
  620. {
  621. for (;;) {
  622. auto maybe_whitespace = peek_token();
  623. if (!maybe_whitespace.is_whitespace()) {
  624. break;
  625. }
  626. next_token();
  627. }
  628. auto token = peek_token();
  629. if (!token.is_ident()) {
  630. return {};
  631. }
  632. auto declaration = consume_a_declaration();
  633. // FIXME: Return the declaration.
  634. return {};
  635. }
  636. Vector<StyleProperty> Parser::parse_as_list_of_declarations()
  637. {
  638. auto declarations = consume_a_list_of_declarations();
  639. // FIXME: Return the declarations.
  640. return {};
  641. }
  642. Optional<StyleComponentValueRule> Parser::parse_as_component_value()
  643. {
  644. for (;;) {
  645. auto maybe_whitespace = peek_token();
  646. if (!maybe_whitespace.is_whitespace()) {
  647. break;
  648. }
  649. next_token();
  650. }
  651. auto token = peek_token();
  652. if (token.is_eof()) {
  653. return {};
  654. }
  655. auto value = consume_a_component_value();
  656. for (;;) {
  657. auto maybe_whitespace = peek_token();
  658. if (!maybe_whitespace.is_whitespace()) {
  659. break;
  660. }
  661. next_token();
  662. }
  663. auto maybe_eof = peek_token();
  664. if (maybe_eof.is_eof()) {
  665. return value;
  666. }
  667. return {};
  668. }
  669. Vector<StyleComponentValueRule> Parser::parse_as_list_of_component_values()
  670. {
  671. Vector<StyleComponentValueRule> rules;
  672. for (;;) {
  673. if (peek_token().is_eof()) {
  674. break;
  675. }
  676. rules.append(consume_a_component_value());
  677. }
  678. return rules;
  679. }
  680. Vector<StyleComponentValueRule> Parser::parse_as_list_of_comma_separated_component_values()
  681. {
  682. Vector<StyleComponentValueRule> rules;
  683. for (;;) {
  684. rules.append(consume_a_component_value());
  685. if (peek_token().is_comma())
  686. continue;
  687. if (peek_token().is_eof())
  688. break;
  689. }
  690. return rules;
  691. }
  692. RefPtr<CSSRule> Parser::convert_rule(NonnullRefPtr<QualifiedStyleRule>)
  693. {
  694. return {};
  695. }
  696. }