libwordring
grammar.hpp
1 #pragma once
2 
3 // ------------------------------------------------------------------------------------------------
4 // 17. Grammar
5 //
6 // https://drafts.csswg.org/selectors-4/#grammar
7 // https://triple-underscore.github.io/selectors4-ja.html#grammar
8 // ------------------------------------------------------------------------------------------------
9 
10 #include <wordring/wwwc/selectors/pseudo_class_defs.hpp>
11 #include <wordring/wwwc/css_defs.hpp>
12 #include <wordring/wwwc/selectors/tree_structural_pseudo_classes.hpp>
13 
14 #include <wordring/wwwc/css_syntax/parsing.hpp>
15 
16 #include <wordring/encoding/encoding.hpp>
17 #include <wordring/html/html_defs.hpp>
18 
19 #include <wordring/whatwg/infra/infra.hpp>
20 
21 #include <algorithm>
22 #include <iterator>
23 #include <optional>
24 #include <string>
25 #include <string_view>
26 #include <utility>
27 #include <variant>
28 #include <vector>
29 
30 namespace wordring::wwwc::css
31 {
32  // --------------------------------------------------------------------------------------------
33  // 17. Grammar
34  //
35  // https://drafts.csswg.org/selectors-4/#grammar
36  // https://triple-underscore.github.io/selectors4-ja.html#grammar
37  // --------------------------------------------------------------------------------------------
38 
48  {
49  public:
50  using const_iterator = syntax_primitive_stream::const_iterator;
51 
52  using document_type_name = wordring::html::document_type_name;
54 
55  public:
56  selector_grammar() = default;
57  selector_grammar(selector_grammar const&) = default;
59 
60  selector_grammar(const_iterator first, const_iterator last);
61 
62  selector_grammar& operator=(selector_grammar const&) = default;
63  selector_grammar& operator=(selector_grammar&&) = default;
64 
65  operator bool() const;
66 
67  bool operator !() const;
68 
69  const_iterator begin() const;
70 
71  const_iterator end() const;
72 
73  protected:
76  const_iterator m_first;
77 
80  const_iterator m_last;
81 
82  };
83 
95  {
96  public:
97  using const_iterator = syntax_primitive_stream::const_iterator;
98 
99  public:
100  static combinator consume(syntax_primitive_stream in, parse_context& ctx);
101 
102  public:
103  combinator() = default;
104  combinator(combinator const&) = default;
105  combinator(const_iterator first, const_iterator last, char32_t c);
106 
107  char32_t type() const;
108 
109  private:
110  char32_t m_c;
111  };
112 
124  {
125  public:
126  using const_iterator = syntax_primitive_stream::const_iterator;
127 
128  public:
135 
136  public:
137  ns_prefix() = default;
138  ns_prefix(ns_prefix const&) = default;
139  ns_prefix(ns_prefix&&) = default;
140  ns_prefix(const_iterator first, const_iterator last, std::u32string const& prefix);
141 
142  ns_prefix& operator =(ns_prefix const&) = default;
143  ns_prefix& operator =(ns_prefix&&) = default;
144 
151  std::u32string const& string() const;
152 
153  private:
154  std::u32string m_ns_prefix;
155  };
156 
170  class wq_name: public selector_grammar
171  {
172  public:
173  using const_iterator = syntax_primitive_stream::const_iterator;
174 
175  public:
176  static wq_name consume(syntax_primitive_stream in, parse_context& ctx);
177 
178  public:
179  wq_name() = default;
180  wq_name(const_iterator first, const_iterator last, std::optional<ns_prefix> ns, std::u32string const& name);
181 
184  std::optional<ns_prefix> const& prefix() const;
185 
188  std::u32string const& name() const;
189 
190  private:
191  std::optional<ns_prefix> m_ns_prefix;
192  std::u32string m_name;
193  };
194 
211  {
212  public:
213  using const_iterator = syntax_primitive_stream::const_iterator;
214 
215  using document_type_name = wordring::html::document_type_name;
217 
218  public:
219  static id_selector consume(syntax_primitive_stream in, parse_context& ctx);
220 
221  public:
222  id_selector() = default;
223 
230  id_selector(const_iterator first, const_iterator last, std::u32string const& value);
231 
234  std::u32string const& value() const;
235 
253  template <typename NodePointer>
254  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
255  {
257 
258  assert(!(ctx.m_type_name == document_type_name::Xml
259  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
260 
261  if (traits::is_element(np))
262  {
263  auto it1 = traits::abegin(np);
264  auto it2 = traits::aend(np);
265  while (it1 != it2)
266  {
267  std::u32string name = wordring::encoding_cast<std::u32string>(traits::get_qualified_name(*it1));
268  if (ctx.m_type_name == document_type_name::Html)
269  {
270  std::u32string tmp;
271  wordring::whatwg::to_ascii_lowercase(name.begin(), name.end(), std::back_inserter(tmp));
272  name = std::move(tmp);
273  }
274 
275  if (name == U"id")
276  {
277  std::u32string val = wordring::encoding_cast<std::u32string>(traits::value(*it1));
278  if (ctx.m_mode_name == document_mode_name::Quirks)
279  {
280  std::u32string tmp;
281  wordring::whatwg::to_ascii_lowercase(val.begin(), val.end(), std::back_inserter(tmp));
282  val = std::move(tmp);
283  }
284  if (val == m_value) return true;
285  }
286  ++it1;
287  }
288  }
289  return false;
290  }
291 
292  private:
293  std::u32string m_value;
294  };
295 
312  {
313  public:
314  using const_iterator = syntax_primitive_stream::const_iterator;
315 
316  using document_type_name = wordring::html::document_type_name;
318 
319  public:
320  static class_selector consume(syntax_primitive_stream in, parse_context& ctx);
321 
322  public:
323  class_selector() = default;
324  class_selector(const_iterator first, const_iterator last, std::u32string const& name);
325 
328  std::u32string const& name() const;
329 
350  template <typename NodePointer>
351  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
352  {
354 
355  assert(!(ctx.m_type_name == document_type_name::Xml
356  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
357 
358  if (traits::is_element(np))
359  {
360  auto it1 = traits::abegin(np);
361  auto it2 = traits::aend(np);
362  while (it1 != it2)
363  {
364  std::u32string name = wordring::encoding_cast<std::u32string>(traits::get_qualified_name(*it1));
365  if (ctx.m_type_name == document_type_name::Html)
366  {
367  std::u32string tmp;
368  wordring::whatwg::to_ascii_lowercase(name.begin(), name.end(), std::back_inserter(tmp));
369  name = std::move(tmp);
370  }
371  if (name != U"class")
372  {
373  ++it1;
374  continue;
375  }
376 
377  std::u32string val = wordring::encoding_cast<std::u32string>(traits::value(*it1));
378  if (ctx.m_mode_name == document_mode_name::Quirks)
379  {
380  std::u32string tmp;
381  wordring::whatwg::to_ascii_lowercase(val.begin(), val.end(), std::back_inserter(tmp));
382  val = std::move(tmp);
383  }
384 
385  std::vector<std::u32string> v;
386  wordring::whatwg::split_on_ascii_whitespace(val.begin(), val.end(), std::back_inserter(v));
387  for (std::u32string const& s : v)
388  {
389  bool matched = (ctx.m_mode_name == document_mode_name::Quirks)
390  ? wordring::whatwg::is_ascii_case_insensitive_match(s.begin(), s.end(), m_name.begin(), m_name.end())
391  : s == val;
392 
393  if (matched) return true;
394  }
395  ++it1;
396  }
397  }
398  return false;
399  }
400 
401  private:
402  std::u32string m_name;
403  };
404 
417  {
418  public:
419  using const_iterator = syntax_primitive_stream::const_iterator;
420 
421  public:
422  static attr_matcher consume(syntax_primitive_stream in, parse_context& ctx);
423 
424  public:
425  attr_matcher() = default;
426  attr_matcher(const_iterator first, const_iterator last, char32_t c);
427 
428  char32_t prefix() const;
429 
430  private:
431  char32_t m_prefix = U'\0';
432  };
433 
452  {
453  public:
454  using const_iterator = syntax_primitive_stream::const_iterator;
455 
456  public:
457  static attr_modifier consume(syntax_primitive_stream in, parse_context& ctx);
458 
459  public:
460  attr_modifier() = default;
461  attr_modifier(const_iterator first, const_iterator last, char32_t c);
462 
463  char32_t value() const;
464 
465  private:
466  char32_t m_c;
467  };
468 
481  {
482  public:
483  using value_type = std::variant<std::monostate, ident_token, function>;
484  using const_iterator = syntax_primitive_stream::const_iterator;
485 
486  public:
487 
499 
500  public:
502  pseudo_class_selector(const_iterator first, const_iterator last);
503  pseudo_class_selector(const_iterator first, const_iterator last, ident_token const& id, pseudo_class_id_name name);
504  pseudo_class_selector(const_iterator first, const_iterator last, function const& fn, pseudo_class_fn_name name);
505 
506  syntax_primitive_name type() const;
507 
508  template <typename T>
509  T const& get() const { return std::get<T>(m_value); }
510 
521  template <typename NodePointer>
522  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
523  {
524  assert(!(ctx.m_type_name == document_type_name::Xml
525  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
526 
527  // 識別子だけの疑似クラスはこちら
528  switch (m_pseudo_class_id_name)
529  {
530  case pseudo_class_id_name::Root: // :root
531  return root_pseudo_class::match(np, ctx);
532  default:
533  return false;
534  }
535 
536  // 関数型の疑似クラスはこちら
537  //switch (m_pseudo_class_fn_name)
538  //{
539  //default:
540  // break;
541  //}
542 
543  return false;
544  }
545 
546  protected:
547  value_type m_value;
548  pseudo_class_id_name m_pseudo_class_id_name;
549  pseudo_class_fn_name m_pseudo_class_fn_name;
550  };
551 
564  {
565  public:
566  using value_type = pseudo_class_selector::value_type;
567  using const_iterator = syntax_primitive_stream::const_iterator;
568 
569  public:
583 
584  public:
586  pseudo_element_selector(const_iterator first, const_iterator last);
587  pseudo_element_selector(const_iterator first, const_iterator last, ident_token const& id, pseudo_element_id_name name);
588 
599  template <typename NodePointer>
600  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
601  {
602  assert(!(ctx.m_type_name == document_type_name::Xml
603  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
604 
605  return false;
606  }
607 
608  private:
609  pseudo_element_id_name m_pseudo_element_id_name;
610  };
611 
625  {
626  public:
627  using const_iterator = syntax_primitive_stream::const_iterator;
628 
629  public:
631 
632  public:
633  attribute_selector() = default;
634  attribute_selector(const_iterator first, const_iterator last, wq_name name, char32_t matcher, std::u32string const& value, char32_t modifier);
635 
636  std::optional<ns_prefix> const& prefix() const;
637  std::u32string const& name() const;
638  char32_t matcher() const;
639  std::u32string const& value() const;
640  char32_t modifier() const;
641 
691  template <typename NodePointer>
692  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
693  {
696  using wordring::whatwg::split_on_ascii_whitespace;
697  using wordring::encoding_cast;
699 
700  assert(!(ctx.m_type_name == document_type_name::Xml
701  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
702 
703  // 要素以外のノードに属性は無い
704  if (!traits::is_element(np)) return false;
705 
706  // 属性名照合
707  auto it1 = traits::abegin(np);
708  auto it2 = traits::aend(np);
709  while (it1 != it2)
710  {
711  // 名前空間接頭辞
712  if (m_name.prefix()) // セレクタが名前空間接頭辞を含んでいる
713  {
714  std::u32string const& prefix1 = m_name.prefix()->string();
715  std::u32string uri2 = encoding_cast<std::u32string>(traits::get_namespace(*it1));
716 
717  if (prefix1 == U"*"); // 接頭辞を持たない属性を含めて全てにマッチ
718  else if (prefix1 == U"") // 接頭辞を持たない属性にマッチ
719  {
720  if (!uri2.empty())
721  {
722  ++it1;
723  continue;
724  }
725  }
726  else
727  {
728  auto it = ctx.m_namespace_uris.find(prefix1);
729  if (it == ctx.m_namespace_uris.end() || it->second != uri2)
730  {
731  ++it1;
732  continue;
733  }
734  }
735  }
736  else // セレクタが名前空間接頭辞を含まない(名前空間付きの属性にマッチしない)
737  {
738  if (!traits::get_namespace(*it1).empty())
739  {
740  ++it1;
741  continue;
742  }
743  }
744 
745  // 属性名
746  std::u32string const& n1 = m_name.name();
747  std::u32string n2 = encoding_cast<std::u32string>(traits::get_local_name(*it1));
748  // XML はASCII大小区別、HTMLは大小無視
749  if (ctx.m_type_name == document_type_name::Xml)
750  {
751  if (n1 == n2) break;
752  }
753  else
754  {
755  if (is_ascii_case_insensitive_match(n1.begin(), n1.end(), n2.begin(), n2.end())) break;
756  }
757 
758  ++it1;
759  }
760  if (it1 == it2) return false;
761 
762  // 属性値照合
763  switch (m_matcher)
764  {
765  case U'\0':// [attr]
766  assert(m_value.empty());
767  return true;
768  case U'=': // [attr=val]
769  {
770  std::u32string s = encoding_cast<std::u32string>(traits::value(*it1));
771  if (m_modifier == U'i') return is_ascii_case_insensitive_match(m_value.begin(), m_value.end(), s.begin(), s.end());
772  else return m_value == s;
773  }
774  case U'~': // [attr~=val]
775  {
776  std::u32string tmp = encoding_cast<std::u32string>(traits::value(*it1));
777  std::vector<std::u32string> v;
778  split_on_ascii_whitespace(tmp.begin(), tmp.end(), std::back_inserter(v));
779  for (std::u32string const& s : v)
780  {
781  if (m_modifier == U'i' && is_ascii_case_insensitive_match(m_value.begin(), m_value.end(), s.begin(), s.end())) return true;
782  else if(m_value == s) return true;
783  }
784  break;
785  }
786  case U'|': // [attr|=val]
787  {
788  std::u32string s = encoding_cast<std::u32string>(traits::value(*it1));
789  if (m_modifier == U'i')
790  {
791  if (m_value.size() < s.size()
792  && is_ascii_case_insensitive_match(m_value.begin(), m_value.end(), s.begin(), s.begin() + m_value.size())
793  && s[m_value.size()] == U'-') return true;
794  }
795  else
796  {
797  if (m_value.size() < s.size()
798  && std::equal(m_value.begin(), m_value.end(), s.begin(), s.begin() + m_value.size())
799  && s[m_value.size()] == U'-') return true;
800  }
801  break;
802  }
803  case U'^': // [attr^=val]
804  {
805  std::u32string s = encoding_cast<std::u32string>(traits::value(*it1));
806  if (m_modifier == U'i')
807  {
808  if (m_value.size() <= s.size()
809  && is_ascii_case_insensitive_match(m_value.begin(), m_value.end(), s.begin(), s.begin() + m_value.size())) return true;
810  }
811  else
812  {
813  if (m_value.size() <= s.size()
814  && std::equal(m_value.begin(), m_value.end(), s.begin(), s.begin() + m_value.size())) return true;
815  }
816  break;
817  }
818  case U'$': // [attr$=val]
819  {
820  std::u32string s = encoding_cast<std::u32string>(traits::value(*it1));
821  if (s.size() < m_value.size()) return false;
822  if (m_modifier == U'i')
823  {
824  if (is_ascii_case_insensitive_match(m_value.rbegin(), m_value.rend(), s.rbegin(), s.rbegin() + m_value.size())) return true;
825  }
826  else
827  {
828  if (std::equal(m_value.rbegin(), m_value.rend(), s.rbegin(), s.rbegin() + m_value.size())) return true;
829  }
830  break;
831  }
832  case U'*': // [attr*=val]
833  {
834  std::u32string s1 = encoding_cast<std::u32string>(traits::value(*it1));
835  std::u32string s2 = m_value;
836  if (m_modifier == U'i')
837  {
838  std::u32string tmp;
839  to_ascii_lowercase(s1.begin(), s1.end(), std::back_inserter(tmp));
840  std::swap(s1, tmp);
841  tmp.clear();
842  to_ascii_lowercase(s2.begin(), s2.end(), std::back_inserter(tmp));
843  s2 = std::move(tmp);
844  }
845  if (s1.find(s2) != std::u32string::npos) return true;
846  break;
847  }
848  default:
849  break;
850  }
851  return false;
852  }
853 
854  private:
856  wq_name m_name;
857  char32_t m_matcher;
858  std::u32string m_value;
859 
866  char32_t m_modifier;
867  };
868 
882  {
883  public:
884  using const_iterator = syntax_primitive_stream::const_iterator;
885 
886  using value_type = std::variant<id_selector, class_selector, attribute_selector, pseudo_class_selector>;
887 
888  public:
890  public:
891  subclass_selector() = default;
892  subclass_selector(const_iterator first, const_iterator last, value_type value);
893 
894  value_type const& value() const;
895 
900  template <typename NodePointer>
901  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
902  {
903  assert(!(ctx.m_type_name == document_type_name::Xml
904  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
905 
906  return std::visit([&](auto const& x) { return x.match(np, ctx); }, m_value);
907  }
908 
909  private:
910  value_type m_value;
911  };
912 
927  {
928  public:
929  using const_iterator = syntax_primitive_stream::const_iterator;
930 
931  using value_type = std::variant<wq_name, std::optional<ns_prefix>>;
932 
933  public:
934  static type_selector consume(syntax_primitive_stream in, parse_context& ctx);
935 
936  public:
937  type_selector() = default;
938  type_selector(const_iterator first, const_iterator last, value_type value);
939 
940  value_type const& value() const;
941 
950  template <typename NodePointer>
951  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
952  {
955  using wordring::encoding_cast;
956 
957  assert(!(ctx.m_type_name == document_type_name::Xml
958  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
959 
960  // 要素以外のノードにタグ名は無い
961  if (!traits::is_element(np)) return false;
962 
963  // 名前空間接頭辞
964  std::optional<ns_prefix> const& opt = (m_value.index() == 0)
965  ? std::get_if<wq_name>(&m_value)->prefix()
966  : **std::get_if<std::optional<ns_prefix>>(&m_value);
967 
968  std::u32string uri2 = encoding_cast<std::u32string>(traits::get_namespace(np));
969 
970  if (opt) // セレクタに名前空間接頭辞アリ
971  {
972  std::u32string const& prefix1 = opt->string();
973  if (prefix1 == U"*"); // 接頭辞を持たない要素を含めて全てにマッチ
974  else if (prefix1 == U"") // 接頭辞を持たない要素にマッチ
975  {
976  if (!uri2.empty()) return false;
977  }
978  else
979  {
980  auto it = ctx.m_namespace_uris.find(prefix1);
981  if (it == ctx.m_namespace_uris.end() || it->second != uri2) return false;
982  }
983  }
984  else // セレクタに名前空間接頭辞ナシ
985  {
986  auto it = ctx.m_namespace_uris.find(U""); // 既定の名前空間を検索
987  if (it == ctx.m_namespace_uris.end()); // 既定の名前空間が無い場合全てにマッチ
988  else // あれば既定の名前空間にマッチ
989  {
990  if (it->second != uri2) return false;
991  }
992  }
993 
994  // タグ名
995  if (m_value.index() == 1) return true;
996 
997  std::u32string const& name1 = std::get_if<wq_name>(&m_value)->name();
998  std::u32string name2 = encoding_cast<std::u32string>(traits::get_local_name(np));
999 
1000  if (ctx.m_type_name == document_type_name::Html)
1001  {
1002  if (is_ascii_case_insensitive_match(name1.begin(), name1.end(), name2.begin(), name2.end())) return true;
1003  }
1004  else
1005  {
1006  if (name1 == name2) return true;
1007  }
1008 
1009  return false;
1010  }
1011 
1012  private:
1015  value_type m_value;
1016  };
1017 
1030  {
1031  public:
1032  using const_iterator = syntax_primitive_stream::const_iterator;
1033 
1034  using value_type = std::variant<std::monostate, type_selector, subclass_selector>;
1035 
1036  public:
1037  static simple_selector consume(syntax_primitive_stream in, parse_context& ctx);
1038 
1039  public:
1040  simple_selector() = default;
1041  simple_selector(const_iterator first, const_iterator last, value_type value);
1042 
1043  value_type const& value() const;
1044 
1049  template <typename NodePointer>
1050  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1051  {
1052  assert(!(ctx.m_type_name == document_type_name::Xml
1053  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1054 
1055  if (m_value.index() == 1) return std::get_if<type_selector>(&m_value)->match(np, ctx);
1056  else if (m_value.index() == 2) return std::get_if<subclass_selector>(&m_value)->match(np, ctx);
1057 
1058  return false;
1059  }
1060 
1061  private:
1062  value_type m_value;
1063  };
1064 
1081  {
1082  public:
1083  using const_iterator = syntax_primitive_stream::const_iterator;
1084 
1085  using value_type = std::variant<type_selector, subclass_selector, pseudo_element_selector, pseudo_class_selector>;
1086 
1087  public:
1088  static compound_selector consume(syntax_primitive_stream in, parse_context& ctx);
1089 
1090  public:
1091  compound_selector() = default;
1092  compound_selector(const_iterator first, const_iterator last, std::vector<value_type>&& value);
1093 
1094  std::vector<value_type> const& value() const;
1095 
1100  template <typename NodePointer>
1101  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1102  {
1103  assert(!(ctx.m_type_name == document_type_name::Xml
1104  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1105 
1106  for (value_type const& val : m_value)
1107  {
1108  if (!std::visit([&](auto const& x) { return x.match(np, ctx); }, val)) return false;
1109  }
1110 
1111  return true;
1112  }
1113 
1114  private:
1115  std::vector<value_type> m_value;
1116  };
1117 
1132  {
1133  public:
1134  using const_iterator = syntax_primitive_stream::const_iterator;
1135 
1136  using value_type = std::variant<compound_selector, combinator>;
1137  using reverse_iterator = std::vector<value_type>::const_reverse_iterator;
1138  public:
1139  static complex_selector consume(syntax_primitive_stream in, parse_context& ctx);
1140 
1141  private:
1154  template <typename NodePointer>
1155  bool match(reverse_iterator it, NodePointer const& np, match_context<NodePointer> const& ctx) const
1156  {
1158 
1159  if (!std::get_if<compound_selector>(&*it)->match(np, ctx)) return false;
1160  ++it;
1161  if (it == m_value.rend()) return true;
1162 
1163  char32_t c = U' ';
1164  if (it->index() == 1)
1165  {
1166  c = std::get_if<combinator>(&*it)->type();
1167  ++it;
1168  }
1169 
1170  switch (c)
1171  {
1172  case U' ':
1173  for (auto p = traits::parent(np); p != traits::pointer(); p = traits::parent(p))
1174  {
1175  if (match(it, p, ctx)) return true;
1176  }
1177  break;
1178  case U'>':
1179  {
1180  auto p = traits::parent(np);
1181  if (p != traits::pointer() && match(it, p, ctx)) return true;
1182  break;
1183  }
1184  case U'+':
1185  {
1186  auto parent = traits::parent(np);
1187  if (parent == traits::pointer()) return false; // 根に兄弟は無いはず。
1188  auto first = traits::begin(parent);
1189  for(auto p = np; p != first;)
1190  {
1191  p = traits::prev(p);
1192  if (traits::is_element(p)) return match(it, p, ctx);
1193  }
1194  break;
1195  }
1196  case U'~':
1197  {
1198  auto parent = traits::parent(np);
1199  if (parent == traits::pointer()) return false; // 根に兄弟は無いはず。
1200  auto first = traits::begin(parent);
1201  for (auto p = np; p != first;)
1202  {
1203  p = traits::prev(p);
1204  if (traits::is_element(p) && match(it, p, ctx)) return true;
1205  }
1206  break;
1207  }
1208  default:
1209  break;
1210  }
1211 
1212  return false;
1213  }
1214 
1215  public:
1216  complex_selector() = default;
1217  complex_selector(const_iterator first, const_iterator last, std::vector<value_type>&& value);
1218 
1219  std::vector<value_type> const& value() const;
1220 
1225  template <typename NodePointer>
1226  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1227  {
1228  assert(!(ctx.m_type_name == document_type_name::Xml
1229  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1230 
1231  return match(m_value.rbegin(), np, ctx);
1232  }
1233 
1234  private:
1235  std::vector<value_type> m_value;
1236  };
1237 
1256  {
1257  public:
1258  using const_iterator = syntax_primitive_stream::const_iterator;
1259 
1260  using value_type = std::variant<compound_selector, combinator>;
1261 
1262  public:
1263  static relative_selector consume(syntax_primitive_stream in, parse_context& ctx);
1264 
1265  public:
1266  relative_selector() = default;
1267  relative_selector(const_iterator first, const_iterator last, std::vector<value_type>&& value);
1268 
1269  std::vector<value_type> const& value() const;
1270 
1277  template <typename NodePointer>
1278  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1279  {
1281  using ns_name = wordring::html::ns_name;
1283  using wordring::encoding_cast;
1284 
1285  assert(!(ctx.m_type_name == document_type_name::Xml
1286  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1287 
1288  return false;
1289  }
1290 
1297  template <typename NodePointer>
1299  {
1301 
1302  if (ctx.m_scope_elements.empty()
1303  && (ctx.m_scoping_root == traits::pointer() || !traits::is_element(ctx.m_scoping_root)));
1304  else
1305  {
1306  }
1307  }
1308 
1309  private:
1310  std::vector<value_type> m_value;
1311  };
1312 
1325  {
1326  public:
1327  using const_iterator = syntax_primitive_stream::const_iterator;
1328 
1329  public:
1331 
1332  public:
1333  relative_selector_list() = default;
1334  relative_selector_list(const_iterator first, const_iterator last, std::vector<relative_selector>&& value);
1335 
1336  std::vector<relative_selector> const& value() const;
1337 
1344  template <typename NodePointer>
1345  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1346  {
1347  assert(!(ctx.m_type_name == document_type_name::Xml
1348  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1349 
1350  return false;
1351  }
1352 
1353 
1360  template <typename NodePointer>
1362  {
1363  for (relative_selector& rs : m_value) rs.absolutize(ctx);
1364  }
1365 
1366  private:
1367  std::vector<relative_selector> m_value;
1368  };
1369 
1382  {
1383  public:
1384  using const_iterator = syntax_primitive_stream::const_iterator;
1385 
1386  public:
1388 
1389  public:
1390  simple_selector_list() = default;
1391  simple_selector_list(const_iterator first, const_iterator last, std::vector<simple_selector>&& value);
1392 
1393  std::vector<simple_selector> const& value() const;
1394 
1399  template <typename NodePointer>
1400  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1401  {
1402  assert(!(ctx.m_type_name == document_type_name::Xml
1403  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1404 
1405  for (simple_selector const& ss : m_value)
1406  {
1407  if (ss.match(np, ctx)) return true;
1408  }
1409 
1410  return false;
1411  }
1412 
1413  private:
1414  std::vector<simple_selector> m_value;
1415  };
1416 
1429  {
1430  public:
1431  using const_iterator = syntax_primitive_stream::const_iterator;
1432 
1433  public:
1435 
1436  public:
1437  compound_selector_list() = default;
1438  compound_selector_list(const_iterator first, const_iterator last, std::vector<compound_selector>&& value);
1439 
1440  std::vector<compound_selector> const& value() const;
1441 
1446  template <typename NodePointer>
1447  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1448  {
1449  assert(!(ctx.m_type_name == document_type_name::Xml
1450  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1451 
1452  for (compound_selector const& cs : m_value)
1453  {
1454  if (cs.match(np, ctx)) return true;
1455  }
1456 
1457  return false;
1458  }
1459 
1460  private:
1461  std::vector<compound_selector> m_value;
1462  };
1463 
1476  {
1477  public:
1478  using const_iterator = syntax_primitive_stream::const_iterator;
1479 
1480  public:
1482 
1483  public:
1484  complex_selector_list() = default;
1485  complex_selector_list(const_iterator first, const_iterator last, std::vector<complex_selector>&& value);
1486 
1487  std::vector<complex_selector> const& value() const;
1488 
1493  template <typename NodePointer>
1494  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1495  {
1496  assert(!(ctx.m_type_name == document_type_name::Xml
1497  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1498 
1499  for (complex_selector const& cs : m_value)
1500  {
1501  if (cs.match(np, ctx)) return true;
1502  }
1503 
1504  return false;
1505  }
1506 
1507  private:
1508  std::vector<complex_selector> m_value;
1509  };
1510 
1511 
1524  {
1525  public:
1526  using const_iterator = syntax_primitive_stream::const_iterator;
1527 
1528  public:
1529  static selector_list consume(syntax_primitive_stream in, parse_context& ctx);
1530 
1531  public:
1532  selector_list() = default;
1533  selector_list(const_iterator first, const_iterator last, complex_selector_list&& value);
1534 
1535  complex_selector_list const& value() const;
1536 
1541  template <typename NodePointer>
1542  bool match(NodePointer const& np, match_context<NodePointer> const& ctx) const
1543  {
1544  assert(!(ctx.m_type_name == document_type_name::Xml
1545  && (ctx.m_mode_name == document_mode_name::LimitedQuirks || ctx.m_mode_name == document_mode_name::Quirks)));
1546 
1547  return m_value.match(np, ctx);
1548  }
1549 
1550  private:
1551  complex_selector_list m_value;
1552  };
1553 
1554 
1555 }
wordring::wwwc::css::type_selector
<type-selector>
Definition: grammar.hpp:926
wordring::wwwc::css::pseudo_class_selector::m_value
value_type m_value
疑似クラスを示す関数、あるいは識別子
Definition: grammar.hpp:547
wordring::whatwg::to_ascii_lowercase
void to_ascii_lowercase(InputIterator first, InputIterator last, OutputIterator output)
小文字化する
Definition: infra/infra.hpp:253
wordring::wwwc::css::selector_list
<selector-list>
Definition: grammar.hpp:1523
wordring::wwwc::css::selector_grammar
セレクタに関する構文規則の基本クラス
Definition: grammar.hpp:47
wordring::wwwc::css::pseudo_class_selector::consume
static pseudo_class_selector consume(syntax_primitive_stream in, parse_context &ctx)
疑似クラスを消費する
wordring::wwwc::css::pseudo_class_selector
<pseudo-class-selector>
Definition: grammar.hpp:480
wordring::wwwc::css::match_context::m_namespace_uris
std::map< std::u32string, std::u32string > m_namespace_uris
名前空間接頭辞 : 名前空間 URI のマップ
Definition: css_defs.hpp:59
wordring::wwwc::css::match_context::m_mode_name
document_mode_name m_mode_name
文書モード
Definition: css_defs.hpp:53
wordring::wwwc::css::pseudo_class_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:522
wordring::wwwc::css::selector_list::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1542
wordring::wwwc::css::pseudo_element_id_name
pseudo_element_id_name
疑似要素を区別する列挙体
Definition: pseudo_class_defs.hpp:42
wordring::html::node_traits
HTMLノードへの操作を仲介するアダプタ
Definition: html/html_defs.hpp:29
wordring::wwwc::css::subclass_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:901
wordring::wwwc::css::attribute_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:692
wordring::wwwc::css::attr_modifier
<attr-modifier>
Definition: grammar.hpp:451
wordring::wwwc::css::type_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:951
wordring::wwwc::css::compound_selector_list::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1447
wordring::wwwc::css::complex_selector_list
<complex-selector-list>
Definition: grammar.hpp:1475
wordring::wwwc::css::id_selector
<id-selector>
Definition: grammar.hpp:210
wordring::wwwc::css::relative_selector_list
<relative-selector-list>
Definition: grammar.hpp:1324
wordring::wwwc::css::wq_name::name
std::u32string const & name() const
名前を返す
wordring::wwwc::css::match_context::m_scope_elements
std::vector< node_pointer > m_scope_elements
scope 要素
Definition: css_defs.hpp:76
wordring::wwwc::css::relative_selector
<relative-selector>
Definition: grammar.hpp:1255
wordring::wwwc::css::wq_name::prefix
std::optional< ns_prefix > const & prefix() const
名前空間接頭辞を返す
wordring::wwwc::css::match_context::m_type_name
document_type_name m_type_name
文書型
Definition: css_defs.hpp:46
wordring::wwwc::css::compound_selector_list
<compound-selector-list>
Definition: grammar.hpp:1428
wordring::wwwc::css::compound_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1101
wordring::wwwc::css::ns_prefix::consume
static ns_prefix consume(syntax_primitive_stream in, parse_context &ctx)
構文規則と合致する場合、入力から合致部分を消費する
wordring::wwwc::css
wordring::wwwc::css::complex_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1226
wordring::wwwc::css::id_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:254
wordring::wwwc::css::relative_selector::absolutize
void absolutize(match_context< NodePointer > const &ctx)
相対セレクタを絶対化する
Definition: grammar.hpp:1298
wordring::wwwc::css::compound_selector
<compound-selector>
Definition: grammar.hpp:1080
wordring::wwwc::css::pseudo_element_selector
<pseudo-element-selector>
Definition: grammar.hpp:563
wordring::wwwc::css::simple_selector_list::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1400
wordring::wwwc::css::match_context::m_scoping_root
node_pointer m_scoping_root
root 要素
Definition: css_defs.hpp:69
wordring::wwwc::css::pseudo_class_selector::m_pseudo_class_id_name
pseudo_class_id_name m_pseudo_class_id_name
識別子を示す列挙値、あるいは 0
Definition: grammar.hpp:548
wordring::wwwc::css::match_context
CSS セレクタとノードの照合に使われるコンテキスト
Definition: css_defs.hpp:33
wordring::wwwc::css::pseudo_element_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:600
wordring::wwwc::css::attribute_selector
<attribute-selector>
Definition: grammar.hpp:624
wordring::wwwc::css::syntax_primitive_name
syntax_primitive_name
Definition: wwwc/css_syntax/token.hpp:20
wordring::wwwc::css::id_selector::value
std::u32string const & value() const
属性値を返す
wordring::wwwc::css::parse_context
CSS の構文解析に使われるコンテキスト
Definition: css_defs.hpp:23
wordring::wwwc::css::relative_selector_list::absolutize
void absolutize(match_context< NodePointer > const &ctx)
相対セレクタを絶対化する
Definition: grammar.hpp:1361
wordring::wwwc::css::class_selector::name
std::u32string const & name() const
クラス名を返す
wordring::wwwc::css::pseudo_class_selector::m_pseudo_class_fn_name
pseudo_class_fn_name m_pseudo_class_fn_name
関数を示す列挙値、あるいは 0
Definition: grammar.hpp:549
wordring::whatwg::html::document_mode_name
document_mode_name
Definition: whatwg/html/html_defs.hpp:28
wordring::wwwc::css::combinator
<combinator>
Definition: grammar.hpp:94
wordring::wwwc::css::syntax_primitive_stream
syntax_primitive の配列をストリーム化するアダプタ
Definition: wwwc/css_syntax/token.hpp:601
wordring::wwwc::css::relative_selector_list::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1345
wordring::wwwc::css::complex_selector_list::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1494
wordring::wwwc::css::class_selector
<class-selector>
Definition: grammar.hpp:311
wordring::wwwc::css::simple_selector_list
<simple-selector-list>
Definition: grammar.hpp:1381
wordring::wwwc::css::selector_grammar::m_last
const_iterator m_last
構文解析時に部分セレクタが消費した入力の終端
Definition: grammar.hpp:80
wordring::wwwc::css::ident_token
識別子トークン
Definition: wwwc/css_syntax/token.hpp:69
wordring::wwwc::css::subclass_selector
<subclass-selector>
Definition: grammar.hpp:881
wordring::wwwc::css::complex_selector
<complex-selector>
Definition: grammar.hpp:1131
wordring::wwwc::css::ns_prefix
<ns-prefix>
Definition: grammar.hpp:123
wordring::wwwc::css::simple_selector
<simple-selector>
Definition: grammar.hpp:1029
wordring::wwwc::css::selector_grammar::m_first
const_iterator m_first
構文解析時に部分セレクタが消費した入力の先頭
Definition: grammar.hpp:76
wordring::wwwc::css::pseudo_element_selector::consume
static pseudo_element_selector consume(syntax_primitive_stream in, parse_context &ctx)
疑似要素を消費する
wordring::wwwc::css::relative_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1278
wordring::wwwc::css::simple_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:1050
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::wq_name
<wq-name>
Definition: grammar.hpp:170
wordring::wwwc::css::ns_prefix::string
std::u32string const & string() const
名前空間接頭辞を返す
wordring::wwwc::css::class_selector::match
bool match(NodePointer const &np, match_context< NodePointer > const &ctx) const
ノードにマッチするか検査する
Definition: grammar.hpp:351
wordring::wwwc::css::attr_matcher
<attr-matcher>
Definition: grammar.hpp:416