libwordring
parsing.hpp
1 #pragma once
2 
3 #include <wordring/wwwc/css_syntax/input_stream.hpp>
4 #include <wordring/wwwc/css_syntax/tokenization.hpp>
5 
6 #include <wordring/wwwc/css_defs.hpp>
7 
8 #include <wordring/compatibility.hpp>
9 #include <wordring/whatwg/infra/infra.hpp>
10 
11 #include <algorithm>
12 #include <memory>
13 #include <optional>
14 #include <string>
15 #include <type_traits>
16 #include <vector>
17 
18 namespace wordring::wwwc::css
19 {
20 
21  // --------------------------------------------------------------------------------------------
22  // 5. Parsing
23  //
24  // https://drafts.csswg.org/css-syntax-3/#parsing
25  // https://triple-underscore.github.io/css-syntax-ja.html#parsing
26  // --------------------------------------------------------------------------------------------
27 
28 
29  // --------------------------------------------------------------------------------------------
30  // 5.2. Definitions
31  //
32  // https://drafts.csswg.org/css-syntax-3/#parser-definitions
33  // https://triple-underscore.github.io/css-syntax-ja.html#parser-definitions
34  // --------------------------------------------------------------------------------------------
35 
44  {
45  public:
46  using container = std::vector<syntax_primitive>;
47  using const_iterator = typename container::const_iterator;
48 
49  public:
50  token_stream(container&& c)
51  : m_v(std::move(c))
52  , m_i(-1)
53  {
54  m_v.emplace_back(eof_token{});
55  }
56 
57  syntax_primitive const& current_input_token()
58  {
59  if (!(0 <= m_i && m_i < static_cast<std::int32_t>(m_v.size()))) return m_v.back();
60  return m_v[m_i];
61  }
62 
63  syntax_primitive const& next_input_token()
64  {
65  assert(m_i < int(m_v.size()) - 1);
66  return m_v[m_i + 1];
67  }
68 
69  syntax_primitive const& consume()
70  {
71  ++m_i;
72  return current_input_token();
73  }
74 
75  void reconsume()
76  {
77  --m_i;
78  }
79 
80  private:
81  container m_v;
82  std::int32_t m_i;
83  };
84 
85  // --------------------------------------------------------------------------------------------
86  // 5.3. Parser Entry Points
87  //
88  // https://drafts.csswg.org/css-syntax-3/#parser-entry-points
89  // https://triple-underscore.github.io/css-syntax-ja.html#parser-entry-points
90  // --------------------------------------------------------------------------------------------
91 
92  template <typename Syntax, typename ErrorHandler>
93  inline std::vector<Syntax> parse_comma_list(token_stream& in, parse_context& ctx, ErrorHandler handler);
94 
95  template <typename ErrorHandler>
96  inline std::vector<syntax_primitive> parse_list_of_component_values(token_stream& in, ErrorHandler handler);
97 
112  template <typename ErrorHandler = std::nullptr_t>
113  inline std::vector<syntax_primitive>
114  normalize_into_token_stream(std::vector<syntax_primitive>&& in, ErrorHandler handler = nullptr)
115  {
116  return std::move(in);
117  }
118 
139  template <typename ErrorHandler = std::nullptr_t>
140  inline std::vector<syntax_primitive> normalize_into_token_stream(std::u32string&& in, ErrorHandler handler = nullptr)
141  {
142  std::vector<syntax_primitive> out;
143 
144  in.erase(filter_code_points(in.begin(), in.end()), in.end());
145  tokenize(in.begin(), in.end(), std::back_inserter(out), handler);
146 
147  return out;
148  }
149 
150  // --------------------------------------------------------------------------------------------
151  // 5.3.1. Parse something according to a CSS grammar
152  //
153  // https://drafts.csswg.org/css-syntax-3/#parse-grammar
154  // https://triple-underscore.github.io/css-syntax-ja.html#parse-grammar
155  // --------------------------------------------------------------------------------------------
156 
189  template <typename Syntax, typename ErrorHandler = std::nullptr_t>
190  inline Syntax parse_grammar(token_stream& in, parse_context& ctx, ErrorHandler handler = nullptr)
191  {
192  std::vector<syntax_primitive> v = parse_list_of_component_values(in, handler);
194  return Syntax::consume(s, ctx);
195  }
196 
197  template <typename Syntax>
198  inline Syntax parse_grammar(std::vector<syntax_primitive>&& in, parse_context& ctx)
199  {
200  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
201  return parse_grammar<Syntax>(s, ctx, nullptr);
202  }
203 
204  template <typename Syntax>
205  inline Syntax parse_grammar(std::u32string&& in, parse_context& ctx)
206  {
207  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
208  return parse_grammar<Syntax>(s, ctx, nullptr);
209  }
210 
211  // --------------------------------------------------------------------------------------------
212  // 5.3.2. Parse A Comma-Separated List According To A CSS Grammar
213  //
214  // https://drafts.csswg.org/css-syntax-3/#parse-comma-list
215  // https://triple-underscore.github.io/css-syntax-ja.html#parse-comma-list
216  // --------------------------------------------------------------------------------------------
217 
251  template <typename Syntax, typename ErrorHandler>
252  inline std::vector<Syntax> parse_comma_list(token_stream& in, parse_context& ctx, ErrorHandler handler)
253  {
254  std::vector<Syntax> result;
255 
256  std::vector<std::vector<syntax_primitive>> v = parse_comma_separated_list_of_component_values(in, handler);
257  auto it1 = v.begin();
258  auto it2 = v.end();
259  while (it1 != it2)
260  {
261  std::vector<syntax_primitive> tmp;
262  std::swap(*it1++, tmp);
263  token_stream s(std::move(tmp));
264  result.emplace_back(parse_grammar<Syntax>(s, ctx, handler));
265  }
266 
267  return result;
268  }
269 
270  template <typename Syntax>
271  inline std::vector<Syntax> parse_comma_list(std::vector<syntax_primitive>&& in, parse_context& ctx)
272  {
273  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
274  return parse_comma_list<Syntax>(s, ctx, nullptr);
275  }
276 
277  template <typename Syntax>
278  inline std::vector<Syntax> parse_comma_list(std::u32string&& in, parse_context& ctx)
279  {
280  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
281  return parse_comma_list<Syntax>(s, ctx, nullptr);
282  }
283 
284  // --------------------------------------------------------------------------------------------
285  // 5.3.3. Parse a stylesheet
286  //
287  // https://drafts.csswg.org/css-syntax-3/#parse-stylesheet
288  // https://triple-underscore.github.io/css-syntax-ja.html#parse-stylesheet
289  // --------------------------------------------------------------------------------------------
290 
315  template <typename ErrorHandler>
316  inline std::vector<syntax_primitive> parse_stylesheet(token_stream& in, ErrorHandler handler)
317  {
318  std::vector<syntax_primitive> v = consume_list_of_rules(in, true, handler);
319  return v;
320  }
321 
322  inline std::vector<syntax_primitive> parse_stylesheet(std::vector<syntax_primitive>&& in)
323  {
324  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
325  return parse_stylesheet(s, nullptr);
326  }
327 
330  inline std::vector<syntax_primitive> parse_stylesheet(std::u32string&& in)
331  {
332  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
333  return parse_stylesheet(s, nullptr);
334  }
335 
341  inline std::vector<syntax_primitive>
342  parse_stylesheet(std::string const& in, encoding_name fallback = static_cast<encoding_name>(0))
343  {
344  std::u32string buf;
345  decode(in.begin(), in.end(), std::back_inserter(buf), fallback);
346  token_stream s(normalize_into_token_stream(std::move(buf), nullptr));
347  return parse_stylesheet(s, nullptr);
348  }
349 
350  // --------------------------------------------------------------------------------------------
351  // 5.3.4. Parse a list of rules
352  //
353  // https://drafts.csswg.org/css-syntax-3/#parse-list-of-rules
354  // https://triple-underscore.github.io/css-syntax-ja.html#parse-list-of-rules
355  // --------------------------------------------------------------------------------------------
356 
381  template <typename ErrorHandler>
382  inline std::vector<syntax_primitive> parse_list_of_rules(token_stream& in, ErrorHandler handler)
383  {
384  std::vector<syntax_primitive> v = consume_list_of_rules(in, true, handler);
385  return v;
386  }
387 
388  inline std::vector<syntax_primitive> parse_list_of_rules(std::vector<syntax_primitive>&& in)
389  {
390  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
391  return parse_list_of_rules(s, nullptr);
392  }
393 
394  inline std::vector<syntax_primitive> parse_list_of_rules(std::u32string&& in)
395  {
396  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
397  return parse_list_of_rules(s, nullptr);
398  }
399 
400  // --------------------------------------------------------------------------------------------
401  // 5.3.5. Parse a rule
402  //
403  // https://drafts.csswg.org/css-syntax-3/#parse-rule
404  // https://triple-underscore.github.io/css-syntax-ja.html#parse-rule
405  // --------------------------------------------------------------------------------------------
406 
431  template <typename ErrorHandler>
432  inline std::optional<syntax_primitive> parse_rule(token_stream& in, ErrorHandler handler)
433  {
434  while (in.next_input_token().type() == syntax_primitive_name::WhitespaceToken) in.consume();
435  if (in.next_input_token().type() == syntax_primitive_name::EofToken) return std::optional<syntax_primitive>();
436 
437  syntax_primitive rule;
438  if (in.next_input_token().type() == syntax_primitive_name::AtKeywordToken)
439  {
440  rule = consume_at_rule(in, handler);
441  }
442  else
443  {
444  std::optional<qualified_rule> q = consume_qualified_rule(in, handler);
445  if (!q) return std::optional<syntax_primitive>();
446  rule = std::move(*q);
447  }
448 
449  while (in.next_input_token().type() == syntax_primitive_name::WhitespaceToken) in.consume();
450  if (in.next_input_token().type() == syntax_primitive_name::EofToken)
451  {
452  return std::make_optional<syntax_primitive>(std::move(rule));
453  }
454 
455  return std::optional<syntax_primitive>();
456  }
457 
458  inline std::optional<syntax_primitive> parse_rule(std::vector<syntax_primitive>&& in)
459  {
460  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
461  return parse_rule(s, nullptr);
462  }
463 
464  inline std::optional<syntax_primitive> parse_rule(std::u32string&& in)
465  {
466  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
467  return parse_rule(s, nullptr);
468  }
469 
470  // --------------------------------------------------------------------------------------------
471  // 5.3.6. Parse a declaration
472  //
473  // https://drafts.csswg.org/css-syntax-3/#parse-declaration
474  // https://triple-underscore.github.io/css-syntax-ja.html#parse-declaration
475  // --------------------------------------------------------------------------------------------
476 
501  template <typename ErrorHandler>
502  inline std::optional<declaration> parse_declaration(token_stream& in, ErrorHandler handler)
503  {
504  while (in.next_input_token().type() == syntax_primitive_name::WhitespaceToken) in.consume();
505  if (in.next_input_token().type() != syntax_primitive_name::IdentToken) return std::make_optional<declaration>();
506 
507  std::optional<declaration> decl = consume_declaration(in, handler);
508  if (decl) return decl;
509 
510  return std::optional<declaration>();
511  }
512 
513  inline std::optional<declaration> parse_declaration(std::vector<syntax_primitive>&& in)
514  {
515  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
516  return parse_declaration(s, nullptr);
517  }
518 
519  inline std::optional<declaration> parse_declaration(std::u32string&& in)
520  {
521  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
522  return parse_declaration(s, nullptr);
523  }
524 
525  // --------------------------------------------------------------------------------------------
526  // 5.3.7. Parse a list of declarations
527  //
528  // https://drafts.csswg.org/css-syntax-3/#parse-list-of-declarations
529  // https://triple-underscore.github.io/css-syntax-ja.html#parse-list-of-declarations
530  // --------------------------------------------------------------------------------------------
531 
556  template <typename ErrorHandler>
557  inline std::vector<syntax_primitive> parse_list_of_declarations(token_stream& in, ErrorHandler handler)
558  {
559  return consume_list_of_declarations(in, handler);
560  }
561 
562  inline std::vector<syntax_primitive> parse_list_of_declarations(std::vector<syntax_primitive>&& in)
563  {
564  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
565  return parse_list_of_declarations(s, nullptr);
566  }
567 
568  inline std::vector<syntax_primitive> parse_list_of_declarations(std::u32string&& in)
569  {
570  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
571  return parse_list_of_declarations(s, nullptr);
572  }
573 
574  // --------------------------------------------------------------------------------------------
575  // 5.3.8. Parse a component value
576  //
577  // https://drafts.csswg.org/css-syntax-3/#parse-component-value
578  // https://triple-underscore.github.io/css-syntax-ja.html#parse-component-value
579  // --------------------------------------------------------------------------------------------
580 
605  template <typename ErrorHandler>
606  inline std::optional<component_value> parse_component_value(token_stream& in, ErrorHandler handler)
607  {
608  using result_type = std::optional<component_value>;
609 
610  while (in.next_input_token().type() == syntax_primitive_name::WhitespaceToken) in.consume();
611  if (in.next_input_token().type() == syntax_primitive_name::EofToken) return result_type();
612 
613  component_value c = consume_component_value(in, handler);
614 
615  while (in.next_input_token().type() == syntax_primitive_name::WhitespaceToken) in.consume();
616  if (in.next_input_token().type() == syntax_primitive_name::EofToken) return result_type(std::move(c));
617 
618  return result_type();
619  }
620 
621  inline std::optional<component_value> parse_component_value(std::vector<syntax_primitive>&& in)
622  {
623  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
624  return parse_component_value(s, nullptr);
625  }
626 
627  inline std::optional<component_value> parse_component_value(std::u32string&& in)
628  {
629  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
630  return parse_component_value(s, nullptr);
631  }
632 
633  // --------------------------------------------------------------------------------------------
634  // 5.3.9. Parse a list of component values
635  //
636  // https://drafts.csswg.org/css-syntax-3/#parse-list-of-component-values
637  // https://triple-underscore.github.io/css-syntax-ja.html#parse-list-of-component-values
638  // --------------------------------------------------------------------------------------------
639 
664  template <typename ErrorHandler>
665  inline std::vector<syntax_primitive> parse_list_of_component_values(token_stream& in, ErrorHandler handler)
666  {
667  std::vector<syntax_primitive> list;
668 
669  while (true)
670  {
671  component_value c = consume_component_value(in, handler);
672  if (c.type() == syntax_primitive_name::EofToken) break;
673  list.push_back(c);
674  }
675 
676  return list;
677  }
678 
679  inline std::vector<syntax_primitive> parse_list_of_component_values(std::vector<syntax_primitive>&& in)
680  {
681  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
682  return parse_list_of_component_values(s, nullptr);
683  }
684 
685  inline std::vector<syntax_primitive> parse_list_of_component_values(std::u32string&& in)
686  {
687  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
688  return parse_list_of_component_values(s, nullptr);
689  }
690 
691  // --------------------------------------------------------------------------------------------
692  // 5.3.10. Parse a comma-separated list of component values
693  //
694  // https://drafts.csswg.org/css-syntax-3/#parse-comma-separated-list-of-component-values
695  //
696  // --------------------------------------------------------------------------------------------
697 
722  template <typename ErrorHandler>
723  inline std::vector<std::vector<syntax_primitive>>
725  {
726  std::vector<std::vector<syntax_primitive>> lists;
727 
728  while(true)
729  {
730  std::vector<syntax_primitive> v;
731  while (true)
732  {
733  component_value c = consume_component_value(in, handler);
734  switch (c.type())
735  {
737  lists.push_back(std::move(v));
738  return lists;
740  lists.push_back(std::move(v));
741  break;
742  default:
743  v.push_back(c);
744  }
745  }
746  }
747 
748  return lists;
749  }
750 
759  inline std::vector<std::vector<syntax_primitive>>
760  parse_comma_separated_list_of_component_values(std::vector<syntax_primitive>&& in)
761  {
762  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
764  }
765 
774  inline std::vector<std::vector<syntax_primitive>>
776  {
777  token_stream s(normalize_into_token_stream(std::move(in), nullptr));
779  }
780 
781  // --------------------------------------------------------------------------------------------
782  // 5.4. Parser Algorithms
783  //
784  // https://drafts.csswg.org/css-syntax-3/#parser-algorithms
785  // https://triple-underscore.github.io/css-syntax-ja.html#parser-algorithms
786  // --------------------------------------------------------------------------------------------
787 
788  template <typename ErrorHandler>
789  inline std::vector<syntax_primitive> consume_list_of_rules(token_stream& in, bool top_level = false, ErrorHandler handler = nullptr);
790 
791  template <typename ErrorHandler>
792  inline at_rule consume_at_rule(token_stream& in, ErrorHandler handler);
793 
794  template <typename ErrorHandler>
795  inline std::optional<qualified_rule> consume_qualified_rule(token_stream& in, ErrorHandler handler);
796 
797  template <typename ErrorHandler>
798  inline std::vector<syntax_primitive> consume_list_of_declarations(token_stream& in, ErrorHandler handler);
799 
800  template <typename ErrorHandler>
801  inline std::optional<declaration> consume_declaration(token_stream& in, ErrorHandler handler);
802 
803  template <typename ErrorHandler>
804  inline component_value consume_component_value(token_stream& in, ErrorHandler handler);
805 
806  template <typename ErrorHandler>
807  inline simple_block consume_simple_block(token_stream& in, ErrorHandler handler);
808 
809  template <typename ErrorHandler>
810  inline function consume_function(token_stream& in, ErrorHandler handler);
811 
812  // --------------------------------------------------------------------------------------------
813  // 5.4.1. Consume a list of rules
814  //
815  // https://drafts.csswg.org/css-syntax-3/#consume-list-of-rules
816  // https://triple-underscore.github.io/css-syntax-ja.html#consume-list-of-rules
817  // --------------------------------------------------------------------------------------------
818 
832  template <typename ErrorHandler>
833  inline std::vector<syntax_primitive>
834  consume_list_of_rules(token_stream& in, bool top_level, ErrorHandler handler)
835 
836  {
837  std::vector<syntax_primitive> rules;
838 
839  while (true)
840  {
841  syntax_primitive const& tkn = in.consume();
842 
843  switch (tkn.type())
844  {
846  continue;
848  return rules;
851  if (top_level)
852  {
853  continue;
854  }
855  else
856  {
857  in.reconsume();
858  std::optional<qualified_rule> rule = consume_qualified_rule(in, handler);
859  if (rule.has_value()) rules.push_back(std::move(*rule));
860  }
862  in.reconsume();
863  rules.push_back(consume_at_rule(in, handler));
864  continue;
865  default:
866  in.reconsume();
867  std::optional<qualified_rule> rule = consume_qualified_rule(in, handler);
868  if (rule.has_value()) rules.push_back(std::move(*rule));
869  }
870  }
871 
872  assert(false);
873  return rules;
874  }
875 
876  // --------------------------------------------------------------------------------------------
877  // 5.4.2. Consume an at-rule
878  //
879  // https://drafts.csswg.org/css-syntax-3/#consume-at-rule
880  // https://triple-underscore.github.io/css-syntax-ja.html#consume-at-rule
881  // --------------------------------------------------------------------------------------------
882 
899  template <typename ErrorHandler>
900  inline at_rule consume_at_rule(token_stream& in, ErrorHandler handler)
901  {
902  syntax_primitive const& tkn = in.consume();
903  assert(in.current_input_token().type() == syntax_primitive_name::AtKeywordToken);
904 
905  at_rule rule;
906  rule.m_name = tkn.get<at_keyword_token>().m_value;
907 
908  while (true)
909  {
910  syntax_primitive const& tkn = in.consume();
911  switch (tkn.type())
912  {
914  return rule;
916  if constexpr (std::is_invocable_v<ErrorHandler, token_stream&>) handler(in);
917  return rule;
919  rule.m_block = std::make_unique<simple_block>(consume_simple_block(in, handler));
920  return rule;
922  if (tkn.get<simple_block>().m_associated_token == U'{')
923  {
924  rule.m_block = std::make_unique<simple_block>(tkn.get<simple_block>());
925  return rule;
926  }
927  default:
928  in.reconsume();
929  rule.m_prelude.push_back(consume_component_value(in, handler));
930  }
931  }
932 
933  assert(false);
934  return at_rule();
935  }
936 
937  // --------------------------------------------------------------------------------------------
938  // 5.4.3. Consume a qualified rule
939  //
940  // https://drafts.csswg.org/css-syntax-3/#consume-qualified-rule
941  // https://triple-underscore.github.io/css-syntax-ja.html#consume-qualified-rule
942  // --------------------------------------------------------------------------------------------
943 
958  template <typename ErrorHandler>
959  inline std::optional<qualified_rule> consume_qualified_rule(token_stream& in, ErrorHandler handler)
960  {
961  qualified_rule rule;
962 
963  while (true)
964  {
965  syntax_primitive const& tkn = in.consume();
966  switch (tkn.type())
967  {
969  if constexpr (std::is_invocable_v<ErrorHandler, token_stream&>) handler(in);
970  return std::optional<qualified_rule>();
972  rule.m_block = consume_simple_block(in, handler);
973  return std::make_optional(std::move(rule));
975  if (tkn.get<simple_block>().m_associated_token == U'{')
976  {
977  rule.m_block = tkn.get<simple_block>();
978  return std::make_optional(std::move(rule));
979  }
980  default:
981  in.reconsume();
982  rule.m_prelude.push_back(consume_component_value(in, handler));
983  }
984  }
985 
986  assert(false);
987  return std::optional<qualified_rule>();
988  }
989 
990  // --------------------------------------------------------------------------------------------
991  // 5.4.4. Consume a list of declarations
992  //
993  // https://drafts.csswg.org/css-syntax-3/#consume-list-of-declarations
994  // https://triple-underscore.github.io/css-syntax-ja.html#consume-list-of-declarations
995  // --------------------------------------------------------------------------------------------
996 
1017  template <typename ErrorHandler>
1018  inline std::vector<syntax_primitive> consume_list_of_declarations(token_stream& in, ErrorHandler handler)
1019  {
1020  std::vector<syntax_primitive> declarations;
1021 
1022  while (true)
1023  {
1024  syntax_primitive const& tkn = in.consume();
1025  switch (tkn.type())
1026  {
1029  continue;
1031  return declarations;
1033  in.reconsume();
1034  declarations.push_back(consume_at_rule(in, handler));
1035  continue;
1037  {
1038  std::vector<syntax_primitive> tmp(1, tkn);
1039 
1040  while (true)
1041  {
1042  syntax_primitive_name type = in.next_input_token().type();
1043 
1045  || type == syntax_primitive_name::EofToken) break;
1046 
1047  tmp.push_back(consume_component_value(in, handler));
1048  }
1049 
1050  token_stream in2(std::move(tmp));
1051  std::optional<declaration> decl = consume_declaration(in2, handler);
1052  if (decl.has_value()) declarations.push_back(std::move(*decl));
1053 
1054  continue;
1055  }
1056  default:
1057  if constexpr (std::is_invocable_v<ErrorHandler, token_stream&>) handler(in);
1058  in.reconsume();
1059  while (true)
1060  {
1061  syntax_primitive_name type = in.next_input_token().type();
1062 
1064  || type == syntax_primitive_name::EofToken) break;
1065 
1066  consume_component_value(in, handler);
1067  }
1068  continue;
1069  }
1070  }
1071 
1072  assert(false);
1073  return std::vector<syntax_primitive>();
1074  }
1075 
1076  // --------------------------------------------------------------------------------------------
1077  // 5.4.5. Consume a declaration
1078  //
1079  // https://drafts.csswg.org/css-syntax-3/#consume-declaration
1080  // https://triple-underscore.github.io/css-syntax-ja.html#consume-declaration
1081  // --------------------------------------------------------------------------------------------
1082 
1091  inline bool process_important(std::vector<component_value>& v)
1092  {
1093  std::u32string_view const sv = U"important";
1094 
1095  std::uint32_t st = 0;
1096  for (std::uint32_t i = v.size() - 1; 0 <= i; --i)
1097  {
1099 
1100  if (v[i].type() == syntax_primitive_name::WhitespaceToken)
1101  {
1102  continue;
1103  }
1104  else if (st == 0 && v[i].type() == syntax_primitive_name::IdentToken)
1105  {
1106  ident_token const& tkn = v[i].get<ident_token>();
1107  if (is_ascii_case_insensitive_match(tkn.m_value.begin(), tkn.m_value.end(), sv.begin(), sv.end()))
1108  {
1109  st = 1;
1110  }
1111  else break;
1112  }
1113  else if (st == 1 && v[i].type() == syntax_primitive_name::DelimToken)
1114  {
1115  delim_token const& tkn = v[i].get<delim_token>();
1116  if (tkn.m_value == U'!')
1117  {
1118  v.erase(std::next(v.begin(), i), v.end());
1119  return true;
1120  }
1121  else break;
1122  }
1123  else break;
1124  }
1125 
1126  return false;
1127  }
1128 
1143  template <typename ErrorHandler>
1144  inline std::optional<declaration> consume_declaration(token_stream& in, ErrorHandler handler)
1145  {
1146  in.consume();
1147  assert(in.current_input_token().type() == syntax_primitive_name::IdentToken);
1148  declaration decl;
1149  decl.m_name = in.current_input_token().get<ident_token>().m_value;
1150 
1151  while (in.next_input_token().type() == syntax_primitive_name::WhitespaceToken) in.consume();
1152 
1153  if (in.next_input_token().type() != syntax_primitive_name::ColonToken)
1154  {
1155  if constexpr (std::is_invocable_v<ErrorHandler, token_stream&>) handler(in);
1156  return std::optional<declaration>();
1157  }
1158 
1159  in.consume();
1160 
1161  while (in.next_input_token().type() == syntax_primitive_name::WhitespaceToken) in.consume();
1162 
1163  while (in.next_input_token().type() != syntax_primitive_name::EofToken)
1164  {
1165  decl.m_value.push_back(consume_component_value(in, handler));
1166  }
1167 
1168  std::vector<component_value>& v = decl.m_value;
1169  if (process_important(v))
1170  {
1171  decl.m_important_flag = true;
1172  }
1173 
1174  while (!v.empty() && v.back().type() == syntax_primitive_name::WhitespaceToken) v.pop_back();
1175 
1176  return std::make_optional(std::move(decl));
1177  }
1178 
1179  // --------------------------------------------------------------------------------------------
1180  // 5.4.6. Consume a component value
1181  //
1182  // https://drafts.csswg.org/css-syntax-3/#consume-component-value
1183  // https://triple-underscore.github.io/css-syntax-ja.html#consume-component-value
1184  // --------------------------------------------------------------------------------------------
1185 
1186  template <typename ErrorHandler>
1187  inline component_value consume_component_value(token_stream& in, ErrorHandler handler)
1188  {
1189  in.consume();
1190 
1191  syntax_primitive const& tkn = in.current_input_token();
1192  switch (tkn.type())
1193  {
1197  return component_value(consume_simple_block(in, handler));
1199  return component_value(consume_function(in, handler));
1200  default:
1201  break;
1202  }
1203 
1204  return component_value(tkn);
1205  }
1206 
1207  // --------------------------------------------------------------------------------------------
1208  // 5.4.7. Consume a simple block
1209  //
1210  // https://drafts.csswg.org/css-syntax-3/#consume-simple-block
1211  //
1212  // --------------------------------------------------------------------------------------------
1213 
1214  template <typename ErrorHandler>
1215  inline simple_block consume_simple_block(token_stream& in, ErrorHandler handler)
1216  {
1217  simple_block block;
1218 
1219  syntax_primitive_name ending = static_cast<syntax_primitive_name>(0);
1220 
1221  switch (in.current_input_token().type())
1222  {
1224  block.m_associated_token = U'{';
1226  break;
1228  block.m_associated_token = U'[';
1230  break;
1232  block.m_associated_token = U'(';
1234  break;
1235  default:
1236  break;
1237  }
1238 
1239  while (true)
1240  {
1241  syntax_primitive const& tkn = in.consume();
1242  switch (tkn.type())
1243  {
1247  if (ending == tkn.type()) return block;
1249  if constexpr (std::is_invocable_v<ErrorHandler, token_stream&>) handler(in);
1250  return block;
1251  default:
1252  break;
1253  }
1254 
1255  in.reconsume();
1256  block.m_value.push_back(consume_component_value(in, handler));
1257  }
1258 
1259  assert(false);
1260  return simple_block();
1261  }
1262 
1263  // --------------------------------------------------------------------------------------------
1264  // 5.4.8. Consume a function
1265  //
1266  // https://drafts.csswg.org/css-syntax-3/#consume-function
1267  //
1268  // --------------------------------------------------------------------------------------------
1269 
1270  template <typename ErrorHandler>
1271  inline function consume_function(token_stream& in, ErrorHandler handler)
1272  {
1273  assert(in.current_input_token().type() == syntax_primitive_name::FunctionToken);
1274 
1275  function fn{ in.current_input_token().get<function_token>().m_value };
1276 
1277  while (true)
1278  {
1279  syntax_primitive const& tkn = in.consume();
1280  switch (tkn.type())
1281  {
1283  return fn;
1285  if constexpr (std::is_invocable_v<ErrorHandler, token_stream&>) handler(in);
1286  return fn;
1287  default:
1288  in.reconsume();
1289  fn.m_value.push_back(consume_component_value(in, handler));
1290  }
1291  }
1292 
1293  assert(false);
1294  return function();
1295  }
1296 }
wordring::wwwc::css::consume_declaration
std::optional< declaration > consume_declaration(token_stream &in, ErrorHandler handler)
入力から declaration を消費する
Definition: parsing.hpp:1144
wordring::wwwc::css::declaration
宣言を表現する AST ノード
Definition: wwwc/css_syntax/token.hpp:473
wordring::wwwc::css::syntax_primitive_name::OpenCurlyToken
@ OpenCurlyToken
'{'
wordring::wwwc::css::consume_list_of_declarations
std::vector< syntax_primitive > consume_list_of_declarations(token_stream &in, ErrorHandler handler)
入力から declaration のリストを消費する
Definition: parsing.hpp:1018
wordring::wwwc::css::syntax_primitive
トークンや構文アイテムを表現するクラス
Definition: wwwc/css_syntax/token.hpp:482
wordring::wwwc::css::syntax_primitive_name::CloseSquareToken
@ CloseSquareToken
']'
wordring::wwwc::css::token_stream
トークン列をストリームとしてアクセスするためのアダプタ
Definition: parsing.hpp:43
wordring::wwwc::css::syntax_primitive_name::WhitespaceToken
@ WhitespaceToken
空白文字
wordring::wwwc::css::parse_rule
std::optional< syntax_primitive > parse_rule(token_stream &in, ErrorHandler handler)
規則を構文解析する
Definition: parsing.hpp:432
wordring::wwwc::css::syntax_primitive_name::FunctionToken
@ FunctionToken
関数
wordring::wwwc::css::parse_comma_separated_list_of_component_values
std::vector< std::vector< syntax_primitive > > parse_comma_separated_list_of_component_values(token_stream &in, ErrorHandler handler)
コンマ区切りのコンポーネント値のリストを構文解析する
Definition: parsing.hpp:724
wordring::wwwc::css::syntax_primitive_name::SimpleBlock
@ SimpleBlock
simple block
wordring::wwwc::css::parse_declaration
std::optional< declaration > parse_declaration(token_stream &in, ErrorHandler handler)
宣言を構文解析する
Definition: parsing.hpp:502
wordring::wwwc::css::parse_component_value
std::optional< component_value > parse_component_value(token_stream &in, ErrorHandler handler)
コンポーネント値を構文解析する
Definition: parsing.hpp:606
wordring::wwwc::filter_code_points
ForwardIterator filter_code_points(ForwardIterator first, ForwardIterator last)
コード・ポイント列をフィルタする
Definition: wwwc/css_syntax/input_stream.hpp:121
wordring::wwwc::css::syntax_primitive_name::CloseParenToken
@ CloseParenToken
')'
wordring::wwwc::css
wordring::wwwc::css::syntax_primitive_name::AtKeywordToken
@ AtKeywordToken
@xxx
wordring::wwwc::css::parse_list_of_declarations
std::vector< syntax_primitive > parse_list_of_declarations(token_stream &in, ErrorHandler handler)
宣言リストを構文解析する
Definition: parsing.hpp:557
wordring::wwwc::css::syntax_primitive_name::OpenSquareToken
@ OpenSquareToken
'['
wordring::wwwc::decode
void decode(ForwardIterator first, ForwardIterator last, OutputIterator out, encoding_name fallback=static_cast< encoding_name >(0))
バイト列を復号する
Definition: wwwc/css_syntax/input_stream.hpp:30
wordring::wwwc::css::at_keyword_token
@xxxトークン
Definition: wwwc/css_syntax/token.hpp:75
wordring::wwwc::css::syntax_primitive_name::EofToken
@ EofToken
EOF
wordring::wwwc::css::syntax_primitive_name::SemicolonToken
@ SemicolonToken
';'
wordring::wwwc::css::process_important
bool process_important(std::vector< component_value > &v)
Definition: parsing.hpp:1091
wordring::wwwc::css::parse_stylesheet
std::vector< syntax_primitive > parse_stylesheet(token_stream &in, ErrorHandler handler)
スタイルシートを構文解析する
Definition: parsing.hpp:316
wordring::wwwc::css::parse_list_of_rules
std::vector< syntax_primitive > parse_list_of_rules(token_stream &in, ErrorHandler handler)
規則リストを構文解析する
Definition: parsing.hpp:382
wordring::wwwc::css::parse_comma_list
std::vector< Syntax > parse_comma_list(token_stream &in, parse_context &ctx, ErrorHandler handler)
カンマ区切りのリストをCSS文法に沿って構文解析する
Definition: parsing.hpp:252
wordring::wwwc::css::eof_token
EOF トークン
Definition: wwwc/css_syntax/token.hpp:159
wordring::wwwc::css::consume_list_of_rules
std::vector< syntax_primitive > consume_list_of_rules(token_stream &in, bool top_level=false, ErrorHandler handler=nullptr)
Ruleのリストを消費する
Definition: parsing.hpp:834
wordring::wwwc::css::delim_token
区切り文字トークン
Definition: wwwc/css_syntax/token.hpp:103
wordring::wwwc::css::delim_token::m_value
char32_t m_value
Definition: wwwc/css_syntax/token.hpp:103
wordring::wwwc::css::syntax_primitive_name::CloseCurlyToken
@ CloseCurlyToken
'}'
wordring::wwwc::css::syntax_primitive_name
syntax_primitive_name
Definition: wwwc/css_syntax/token.hpp:20
wordring::wwwc::css::syntax_primitive_name::CdcToken
@ CdcToken
"-->"
wordring::wwwc::css::parse_context
CSS の構文解析に使われるコンテキスト
Definition: css_defs.hpp:23
wordring::wwwc::css::syntax_primitive_stream
syntax_primitive の配列をストリーム化するアダプタ
Definition: wwwc/css_syntax/token.hpp:601
wordring::wwwc::css::consume_qualified_rule
std::optional< qualified_rule > consume_qualified_rule(token_stream &in, ErrorHandler handler)
入力から qualified_rule を消費する
Definition: parsing.hpp:959
wordring::wwwc::css::syntax_primitive_name::CdoToken
@ CdoToken
"<!--"
wordring::wwwc::css::syntax_primitive_name::CommaToken
@ CommaToken
','
wordring::wwwc::css::syntax_primitive_name::DelimToken
@ DelimToken
区切り文字
wordring::wwwc::css::component_value
CSSコンポーネント値を表現する AST ノード
Definition: wwwc/css_syntax/token.hpp:218
wordring::wwwc::css::simple_block
単純ブロックを表現する AST ノード
Definition: wwwc/css_syntax/token.hpp:180
wordring::wwwc::css::qualified_rule
修飾規則を表現する AST ノード
Definition: wwwc/css_syntax/token.hpp:458
wordring::wwwc::css::consume_at_rule
at_rule consume_at_rule(token_stream &in, ErrorHandler handler)
入力から at_rule を消費する
Definition: parsing.hpp:900
wordring::wwwc::css::syntax_primitive_name::ColonToken
@ ColonToken
':'
wordring::wwwc::css::ident_token
識別子トークン
Definition: wwwc/css_syntax/token.hpp:69
wordring::wwwc::css::ident_token::m_value
std::u32string m_value
Definition: wwwc/css_syntax/token.hpp:69
wordring::wwwc::css::syntax_primitive_name::OpenParenToken
@ OpenParenToken
'('
wordring::wwwc::css::at_rule
@規則を表現する AST ノード
Definition: wwwc/css_syntax/token.hpp:409
wordring::wwwc::css::normalize_into_token_stream
std::vector< syntax_primitive > normalize_into_token_stream(std::vector< syntax_primitive > &&in, ErrorHandler handler=nullptr)
入力をトークン列へ正規化する
Definition: parsing.hpp:114
wordring::wwwc::css::parse_grammar
Syntax parse_grammar(token_stream &in, parse_context &ctx, ErrorHandler handler=nullptr)
CSS文法に沿って解析する
Definition: parsing.hpp:190
wordring::wwwc::css::syntax_primitive_name::IdentToken
@ IdentToken
識別子
wordring::whatwg::is_ascii_case_insensitive_match
bool is_ascii_case_insensitive_match(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2)
大文字と小文字を区別しないで比較する
Definition: infra/infra.hpp:281
wordring::wwwc::css::parse_list_of_component_values
std::vector< syntax_primitive > parse_list_of_component_values(token_stream &in, ErrorHandler handler)
コンポーネント値のリストを構文解析する
Definition: parsing.hpp:665