function combination(left, combinator, right) {
  switch (combinator.trim()) {
    case '': {
      // descendant
      return (element, subject) => {
        if (right(element, null)) {
          let parent = element.parent
          while (parent.type === 'VElement') {
            if (left(parent, subject)) {
              return true
            }
            parent = parent.parent
          }
        }
        return false
      }
    }
    case '>': {
      // child
      return (element, subject) => {
        if (right(element, null)) {
          const parent = element.parent
          if (parent.type === 'VElement') {
            return left(parent, subject)
          }
        }
        return false
      }
    }
    case '+': {
      // adjacent
      return (element, subject) => {
        if (right(element, null)) {
          const before = getBeforeElement(element)
          if (before) {
            return left(before, subject)
          }
        }
        return false
      }
    }
    case '~': {
      // sibling
      return (element, subject) => {
        if (right(element, null)) {
          for (const before of getBeforeElements(element)) {
            if (left(before, subject)) {
              return true
            }
          }
        }
        return false
      }
    }
    default: {
      throw new SelectorError(`Unknown combinator: ${combinator}.`)
    }
  }
}
@param {VElementMatcher} left
@param {string} combinator
@param {VElementMatcher} right
@returns {VElementMatcher}