func (p *parser) parsePseudoclassSelector() (Selector, error) {
	if p.i >= len(p.s) {
		return nil, fmt.Errorf("expected pseudoclass selector (:pseudoclass), found EOF instead")
	}
	if p.s[p.i] != ':' {
		return nil, fmt.Errorf("expected attribute selector (:pseudoclass), found '%c' instead", p.s[p.i])
	}
	p.i++
	name, err := p.parseIdentifier()
	if err != nil {
		return nil, err
	}
	name = toLowerASCII(name)
	switch name {
	case "not", "has", "haschild":
		if !p.consumeParenthesis() {
			return nil, expectedParenthesis
		}
		sel, err := p.parseSelectorGroup()
		if err != nil {
			return nil, err
		}
		if !p.consumeClosingParenthesis() {
			return nil, expectedClosingParenthesis
		}
		switch name {
		case "not":
			return negatedSelector(sel), nil
		case "has":
			return hasDescendantSelector(sel), nil
		case "haschild":
			return hasChildSelector(sel), nil
		}
	case "contains", "containsown":
		if !p.consumeParenthesis() {
			return nil, expectedParenthesis
		}
		if p.i == len(p.s) {
			return nil, unmatchedParenthesis
		}
		var val string
		switch p.s[p.i] {
		case '\'', '"':
			val, err = p.parseString()
		default:
			val, err = p.parseIdentifier()
		}
		if err != nil {
			return nil, err
		}
		val = strings.ToLower(val)
		p.skipWhitespace()
		if p.i >= len(p.s) {
			return nil, errors.New("unexpected EOF in pseudo selector")
		}
		if !p.consumeClosingParenthesis() {
			return nil, expectedClosingParenthesis
		}
		switch name {
		case "contains":
			return textSubstrSelector(val), nil
		case "containsown":
			return ownTextSubstrSelector(val), nil
		}
	case "matches", "matchesown":
		if !p.consumeParenthesis() {
			return nil, expectedParenthesis
		}
		rx, err := p.parseRegex()
		if err != nil {
			return nil, err
		}
		if p.i >= len(p.s) {
			return nil, errors.New("unexpected EOF in pseudo selector")
		}
		if !p.consumeClosingParenthesis() {
			return nil, expectedClosingParenthesis
		}
		switch name {
		case "matches":
			return textRegexSelector(rx), nil
		case "matchesown":
			return ownTextRegexSelector(rx), nil
		}
	case "nth-child", "nth-last-child", "nth-of-type", "nth-last-of-type":
		if !p.consumeParenthesis() {
			return nil, expectedParenthesis
		}
		a, b, err := p.parseNth()
		if err != nil {
			return nil, err
		}
		if !p.consumeClosingParenthesis() {
			return nil, expectedClosingParenthesis
		}
		return nthChildSelector(a, b,
				name == "nth-last-child" || name == "nth-last-of-type",
				name == "nth-of-type" || name == "nth-last-of-type"),
			nil
	case "first-child":
		return nthChildSelector(0, 1, false, false), nil
	case "last-child":
		return nthChildSelector(0, 1, true, false), nil
	case "first-of-type":
		return nthChildSelector(0, 1, false, true), nil
	case "last-of-type":
		return nthChildSelector(0, 1, true, true), nil
	case "only-child":
		return onlyChildSelector(false), nil
	case "only-of-type":
		return onlyChildSelector(true), nil
	case "input":
		return inputSelector, nil
	case "empty":
		return emptyElementSelector, nil
	}
	return nil, fmt.Errorf("unknown pseudoclass :%s", name)
}
parsePseudoclassSelector parses a pseudoclass selector like :not(p).
package cascadia
import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"golang.org/x/net/html"
)
type parser struct {
	s string  
	i int     
}
func (p *parser) parseEscape() (result string, err error) {
	if len(p.s) < p.i+2 || p.s[p.i] != '\\' {
		return "", errors.New("invalid escape sequence")
	}
	start := p.i + 1
	c := p.s[start]
	switch {
	case c == '\r' || c == '\n' || c == '\f':
		return "", errors.New("escaped line ending outside string")
	case hexDigit(c):
		var i int
		for i = start; i < p.i+6 && i < len(p.s) && hexDigit(p.s[i]); i++ {
		}
		v, _ := strconv.ParseUint(p.s[start:i], 16, 21)
		if len(p.s) > i {
			switch p.s[i] {
			case '\r':
				i++
				if len(p.s) > i && p.s[i] == '\n' {
					i++
				}
			case ' ', '\t', '\n', '\f':
				i++
			}
		}
		p.i = i
		return string(rune(v)), nil
	}
	result = p.s[start : start+1]
	p.i += 2
	return result, nil
}
func hexDigit(c byte) bool {
	return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F'
}
func nameStart(c byte) bool {
	return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c > 127
}
func nameChar(c byte) bool {
	return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c > 127 ||
		c == '-' || '0' <= c && c <= '9'
}
func (p *parser) parseIdentifier() (result string, err error) {
	startingDash := false
	if len(p.s) > p.i && p.s[p.i] == '-' {
		startingDash = true
		p.i++
	}
	if len(p.s) <= p.i {
		return "", errors.New("expected identifier, found EOF instead")
	}
	if c := p.s[p.i]; !(nameStart(c) || c == '\\') {
		return "", fmt.Errorf("expected identifier, found %c instead", c)
	}
	result, err = p.parseName()
	if startingDash && err == nil {
		result = "-" + result
	}
	return
}
func (p *parser) parseName() (result string, err error) {
	i := p.i
loop:
	for i < len(p.s) {
		c := p.s[i]
		switch {
		case nameChar(c):
			start := i
			for i < len(p.s) && nameChar(p.s[i]) {
				i++
			}
			result += p.s[start:i]
		case c == '\\':
			p.i = i
			val, err := p.parseEscape()
			if err != nil {
				return "", err
			}
			i = p.i
			result += val
		default:
			break loop
		}
	}
	if result == "" {
		return "", errors.New("expected name, found EOF instead")
	}
	p.i = i
	return result, nil
}
func (p *parser) parseString() (result string, err error) {
	i := p.i
	if len(p.s) < i+2 {
		return "", errors.New("expected string, found EOF instead")
	}
	quote := p.s[i]
	i++
loop:
	for i < len(p.s) {
		switch p.s[i] {
		case '\\':
			if len(p.s) > i+1 {
				switch c := p.s[i+1]; c {
				case '\r':
					if len(p.s) > i+2 && p.s[i+2] == '\n' {
						i += 3
						continue loop
					}
					fallthrough
				case '\n', '\f':
					i += 2
					continue loop
				}
			}
			p.i = i
			val, err := p.parseEscape()
			if err != nil {
				return "", err
			}
			i = p.i
			result += val
		case quote:
			break loop
		case '\r', '\n', '\f':
			return "", errors.New("unexpected end of line in string")
		default:
			start := i
			for i < len(p.s) {
				if c := p.s[i]; c == quote || c == '\\' || c == '\r' || c == '\n' || c == '\f' {
					break
				}
				i++
			}
			result += p.s[start:i]
		}
	}
	if i >= len(p.s) {
		return "", errors.New("EOF in string")
	}
	i++
	p.i = i
	return result, nil
}
func (p *parser) parseRegex() (rx *regexp.Regexp, err error) {
	i := p.i
	if len(p.s) < i+2 {
		return nil, errors.New("expected regular expression, found EOF instead")
	}
	open := 0
loop:
	for i < len(p.s) {
		switch p.s[i] {
		case '(', '[':
			open++
		case ')', ']':
			open--
			if open < 0 {
				break loop
			}
		}
		i++
	}
	if i >= len(p.s) {
		return nil, errors.New("EOF in regular expression")
	}
	rx, err = regexp.Compile(p.s[p.i:i])
	p.i = i
	return rx, err
}
func (p *parser) skipWhitespace() bool {
	i := p.i
	for i < len(p.s) {
		switch p.s[i] {
		case ' ', '\t', '\r', '\n', '\f':
			i++
			continue
		case '/':
			if strings.HasPrefix(p.s[i:], "/*") {
				end := strings.Index(p.s[i+len("/*"):], "*/")
				if end != -1 {
					i += end + len("/**/")
					continue
				}
			}
		}
		break
	}
	if i > p.i {
		p.i = i
		return true
	}
	return false
}
func (p *parser) consumeParenthesis() bool {
	if p.i < len(p.s) && p.s[p.i] == '(' {
		p.i++
		p.skipWhitespace()
		return true
	}
	return false
}
func (p *parser) consumeClosingParenthesis() bool {
	i := p.i
	p.skipWhitespace()
	if p.i < len(p.s) && p.s[p.i] == ')' {
		p.i++
		return true
	}
	p.i = i
	return false
}
func (p *parser) parseTypeSelector() (result Selector, err error) {
	tag, err := p.parseIdentifier()
	if err != nil {
		return nil, err
	}
	return typeSelector(tag), nil
}
func (p *parser) parseIDSelector() (Selector, error) {
	if p.i >= len(p.s) {
		return nil, fmt.Errorf("expected id selector (#id), found EOF instead")
	}
	if p.s[p.i] != '#' {
		return nil, fmt.Errorf("expected id selector (#id), found '%c' instead", p.s[p.i])
	}
	p.i++
	id, err := p.parseName()
	if err != nil {
		return nil, err
	}
	return attributeEqualsSelector("id", id), nil
}
func (p *parser) parseClassSelector() (Selector, error) {
	if p.i >= len(p.s) {
		return nil, fmt.Errorf("expected class selector (.class), found EOF instead")
	}
	if p.s[p.i] != '.' {
		return nil, fmt.Errorf("expected class selector (.class), found '%c' instead", p.s[p.i])
	}
	p.i++
	class, err := p.parseIdentifier()
	if err != nil {
		return nil, err
	}
	return attributeIncludesSelector("class", class), nil
}
func (p *parser) parseAttributeSelector() (Selector, error) {
	if p.i >= len(p.s) {
		return nil, fmt.Errorf("expected attribute selector ([attribute]), found EOF instead")
	}
	if p.s[p.i] != '[' {
		return nil, fmt.Errorf("expected attribute selector ([attribute]), found '%c' instead", p.s[p.i])
	}
	p.i++
	p.skipWhitespace()
	key, err := p.parseIdentifier()
	if err != nil {
		return nil, err
	}
	p.skipWhitespace()
	if p.i >= len(p.s) {
		return nil, errors.New("unexpected EOF in attribute selector")
	}
	if p.s[p.i] == ']' {
		p.i++
		return attributeExistsSelector(key), nil
	}
	if p.i+2 >= len(p.s) {
		return nil, errors.New("unexpected EOF in attribute selector")
	}
	op := p.s[p.i : p.i+2]
	if op[0] == '=' {
		op = "="
	} else if op[1] != '=' {
		return nil, fmt.Errorf(`expected equality operator, found "%s" instead`, op)
	}
	p.i += len(op)
	p.skipWhitespace()
	if p.i >= len(p.s) {
		return nil, errors.New("unexpected EOF in attribute selector")
	}
	var val string
	var rx *regexp.Regexp
	if op == "#=" {
		rx, err = p.parseRegex()
	} else {
		switch p.s[p.i] {
		case '\'', '"':
			val, err = p.parseString()
		default:
			val, err = p.parseIdentifier()
		}
	}
	if err != nil {
		return nil, err
	}
	p.skipWhitespace()
	if p.i >= len(p.s) {
		return nil, errors.New("unexpected EOF in attribute selector")
	}
	if p.s[p.i] != ']' {
		return nil, fmt.Errorf("expected ']', found '%c' instead", p.s[p.i])
	}
	p.i++
	switch op {
	case "=":
		return attributeEqualsSelector(key, val), nil
	case "~=":
		return attributeIncludesSelector(key, val), nil
	case "|=":
		return attributeDashmatchSelector(key, val), nil
	case "^=":
		return attributePrefixSelector(key, val), nil
	case "$=":
		return attributeSuffixSelector(key, val), nil
	case "*=":
		return attributeSubstringSelector(key, val), nil
	case "#=":
		return attributeRegexSelector(key, rx), nil
	}
	return nil, fmt.Errorf("attribute operator %q is not supported", op)
}
var expectedParenthesis = errors.New("expected '(' but didn't find it")
var expectedClosingParenthesis = errors.New("expected ')' but didn't find it")
var unmatchedParenthesis = errors.New("unmatched '('")