docs: def parse_selectors(self, iselector, index=0, flags=0):
          """Parse selectors."""
  
          sel = _Selector()
          selectors = []
          has_selector = False
          closed = False
          relations = []
          rel_type = ":" + WS_COMBINATOR
          is_open = bool(flags & FLG_OPEN)
          is_pseudo = bool(flags & FLG_PSEUDO)
          is_relative = bool(flags & FLG_RELATIVE)
          is_not = bool(flags & FLG_NOT)
          is_html = bool(flags & FLG_HTML)
          is_default = bool(flags & FLG_DEFAULT)
          is_indeterminate = bool(flags & FLG_INDETERMINATE)
          is_in_range = bool(flags & FLG_IN_RANGE)
          is_out_of_range = bool(flags & FLG_OUT_OF_RANGE)
  
          if self.debug:  # pragma: no cover
              if is_pseudo:
                  print('    is_pseudo: True')
              if is_open:
                  print('    is_open: True')
              if is_relative:
                  print('    is_relative: True')
              if is_not:
                  print('    is_not: True')
              if is_html:
                  print('    is_html: True')
              if is_default:
                  print('    is_default: True')
              if is_indeterminate:
                  print('    is_indeterminate: True')
              if is_in_range:
                  print('    is_in_range: True')
              if is_out_of_range:
                  print('    is_out_of_range: True')
  
          if is_relative:
              selectors.append(_Selector())
  
          try:
              while True:
                  key, m = next(iselector)
  
                  # Handle parts
                  if key == "at_rule":
                      raise NotImplementedError("At-rules found at position {}".format(m.start(0)))
                  elif key == 'pseudo_class_custom':
                      has_selector = self.parse_pseudo_class_custom(sel, m, has_selector)
                  elif key == 'pseudo_class':
                      has_selector, is_html = self.parse_pseudo_class(sel, m, has_selector, iselector, is_html)
                  elif key == 'pseudo_element':
                      raise NotImplementedError("Psuedo-element found at position {}".format(m.start(0)))
                  elif key == 'pseudo_contains':
                      has_selector = self.parse_pseudo_contains(sel, m, has_selector)
                  elif key in ('pseudo_nth_type', 'pseudo_nth_child'):
                      has_selector = self.parse_pseudo_nth(sel, m, has_selector, iselector)
                  elif key == 'pseudo_lang':
                      has_selector = self.parse_pseudo_lang(sel, m, has_selector)
                  elif key == 'pseudo_dir':
                      has_selector = self.parse_pseudo_dir(sel, m, has_selector)
                      # Currently only supports HTML
                      is_html = True
                  elif key == 'pseudo_close':
                      if not has_selector:
                          raise SelectorSyntaxError(
                              "Expected a selector at postion {}".format(m.start(0)),
                              self.pattern,
                              m.start(0)
                          )
                      if is_open:
                          closed = True
                          break
                      else:
                          raise SelectorSyntaxError(
                              "Unmatched pseudo-class close at postion {}".format(m.start(0)),
                              self.pattern,
                              m.start(0)
                          )
                  elif key == 'combine':
                      if is_relative:
                          has_selector, sel, rel_type = self.parse_has_combinator(
                              sel, m, has_selector, selectors, rel_type, index
                          )
                      else:
                          has_selector, sel = self.parse_combinator(
                              sel, m, has_selector, selectors, relations, is_pseudo, index
                          )
                  elif key in ('attribute', 'quirks_attribute'):
                      quirks = key == 'quirks_attribute'
                      if quirks:
                          temp_index = index + m.group(0).find('=') + 1
                          util.warn_quirks(
                              "You have attempted to use an attribute " +
                              "value that should have been quoted at position {}.".format(temp_index),
                              "the attribute value should be quoted.",
                              self.pattern,
                              temp_index
                          )
                      has_selector = self.parse_attribute_selector(sel, m, has_selector, quirks)
                  elif key == 'tag':
                      if has_selector:
                          raise SelectorSyntaxError(
                              "Tag name found at position {} instead of at the start".format(m.start(0)),
                              self.pattern,
                              m.start(0)
                          )
                      has_selector = self.parse_tag_pattern(sel, m, has_selector)
                  elif key in ('class', 'id'):
                      has_selector = self.parse_class_id(sel, m, has_selector)
  
                  index = m.end(0)
          except StopIteration:
              pass
  
          if is_open and not closed:
              raise SelectorSyntaxError(
                  "Unclosed pseudo-class at position {}".format(index),
                  self.pattern,
                  index
              )
  
          if has_selector:
              if not sel.tag and not is_pseudo:
                  # Implied `*`
                  sel.tag = ct.SelectorTag('*', None)
              if is_relative:
                  sel.rel_type = rel_type
                  selectors[-1].relations.append(sel)
              else:
                  sel.relations.extend(relations)
                  del relations[:]
                  selectors.append(sel)
          else:
              # We will always need to finish a selector when `:has()` is used as it leads with combining.
              raise SelectorSyntaxError(
                  'Expected a selector at position {}'.format(index),
                  self.pattern,
                  index
              )
  
          # Some patterns require additional logic, such as default. We try to make these the
          # last pattern, and append the appropriate flag to that selector which communicates
          # to the matcher what additional logic is required.
          if is_default:
              selectors[-1].flags = ct.SEL_DEFAULT
          if is_indeterminate:
              selectors[-1].flags = ct.SEL_INDETERMINATE
          if is_in_range:
              selectors[-1].flags = ct.SEL_IN_RANGE
          if is_out_of_range:
              selectors[-1].flags = ct.SEL_OUT_OF_RANGE
  
          return ct.SelectorList([s.freeze() for s in selectors], is_not, is_html)