func (p *Parser) Parse() (Selector, error) {
	p.s = strings.TrimSpace(p.s)
	if len(p.s) == 0 {
		return Any{}, nil
	}

	var b rune
	var selector, subSelector Selector
	var err error
	var word string
	var op string

	// loop over "clauses"
	// clauses are separated by commas and grouped logically as "ands"
	for {
		// sniff the !haskey form
		b = p.current()

		if b == Bang {
			p.advance() // we aren't going to use the '!'

			// read off the !KEY
			// readWord will leave us on the next non-alpha char
			word, err = p.readWord()
			if err != nil {
				return nil, err
			}

			selector = p.addAnd(selector, p.notHasKey(word)) // add the !KEY term
			if p.done() {
				break
			}

			p.skipToNonWhitespace()
			b = p.current()
			if b != Comma {
				return nil, p.parseError("consecutive not has key terms")
			}

			p.advance()
			continue
		}

		// we're done peeking the first char
		// read the first KEY
		word, err = p.readWord()
		if err != nil {
			return nil, err
		}

		p.mark() // mark to revert if the sniff for the `KEY` form fails

		// sniff if the next character after the word is a comma
		// this indicates it's a "key" form, or existence check on a key
		b = p.skipToNonWhitespace() // the comma is not whitespace
		if b == Comma || p.done() {
			selector = p.addAnd(selector, p.hasKey(word))

			if b == Comma {
				// this is largely a no-op unless we hit a comma
				p.advance()
				// we _have_ to eat the next whitespace
				_ = p.skipToNonWhitespace()
				if p.done() {
					return nil, p.parseError()
				}
			}
			if p.done() {
				break
			}
			continue
		} else {
			p.popMark()
		}

		op, err = p.readOp()
		if err != nil {
			return nil, err
		}

		switch op {
		case OpEquals, OpDoubleEquals:
			subSelector, err = p.equals(word)
		case OpNotEquals:
			subSelector, err = p.notEquals(word)
		case OpIn:
			subSelector, err = p.in(word)
		case OpNotIn:
			subSelector, err = p.notIn(word)
		default:
			return nil, p.parseError("invalid operator")
		}
		if err != nil {
			return nil, err
		}
		selector = p.addAnd(selector, subSelector)

		b = p.skipToNonWhitespace()
		if b == Comma {
			p.advance()
			if p.done() {
				return nil, p.parseError(errExpectedNonEmptyKey)
			}
			p.skipToNonWhitespace()
			continue
		}

		if p.done() {
			break
		}

		// we have a "foo == bar foo" situation
		return nil, p.parseError("keys not separated by comma")
	}

	if !p.skipValidation {
		err = selector.Validate()
		if err != nil {
			return nil, err
		}
	}

	return selector, nil
}
// Parse does the actual parsing.
Parse does the actual parsing.
// Parse does the actual parsing .
func (p *Parser) Parse() (Selector, error) {
	p.s = strings.TrimSpace(p.s)
	if len(p.s) == 0 {
		return Any{}, nil
	}
	var b rune
	var selector, subSelector Selector
	var err error
	var word string
	var op string
	for {
		b = p.current()
		if b == Bang {
			p.advance() 
			word, err = p.readWord()
			if err != nil {
				return nil, err
			}
			selector = p.addAnd(selector, p.notHasKey(word)) 
			if p.done() {
				break
			}
			p.skipToNonWhitespace()
			b = p.current()
			if b != Comma {
				return nil, p.parseError("consecutive not has key terms")
			}
			p.advance()
			continue
		}
		word, err = p.readWord()
		if err != nil {
			return nil, err
		}
		p.mark() 
		b = p.skipToNonWhitespace() 
		if b == Comma || p.done() {
			selector = p.addAnd(selector, p.hasKey(word))
			if b == Comma {
				p.advance()
				_ = p.skipToNonWhitespace()
				if p.done() {
					return nil, p.parseError()
				}
			}
			if p.done() {
				break
			}
			continue
		} else {
			p.popMark()
		}
		op, err = p.readOp()
		if err != nil {
			return nil, err
		}
		switch op {
		case OpEquals, OpDoubleEquals:
			subSelector, err = p.equals(word)
		case OpNotEquals:
			subSelector, err = p.notEquals(word)
		case OpIn:
			subSelector, err = p.in(word)
		case OpNotIn:
			subSelector, err = p.notIn(word)
		default:
			return nil, p.parseError("invalid operator")
		}
		if err != nil {
			return nil, err
		}
		selector = p.addAnd(selector, subSelector)
		b = p.skipToNonWhitespace()
		if b == Comma {
			p.advance()
			if p.done() {
				return nil, p.parseError(errExpectedNonEmptyKey)
			}
			p.skipToNonWhitespace()
			continue
		}
		if p.done() {
			break
		}
		return nil, p.parseError("keys not separated by comma")
	}
	if !p.skipValidation {
		err = selector.Validate()
		if err != nil {
			return nil, err
		}
	}
	return selector, nil
}
func ( p * Parser ) Parse ( ) ( Selector , error ) { p . s = strings . TrimSpace ( p . s ) if len ( p . s ) == 0 { return Any { } , nil } var b rune var selector , subSelector Selector var err error var word string var op string for { b = p . current ( ) if b == Bang { p . advance ( ) word , err = p . readWord ( ) if err != nil { return nil , err } selector = p . addAnd ( selector , p . notHasKey ( word ) ) if p . done ( ) { break } p . skipToNonWhitespace ( ) b = p . current ( ) if b != Comma { return nil , p . parseError ( " " ) } p . advance ( ) continue } word , err = p . readWord ( ) if err != nil { return nil , err } p . mark ( ) b = p . skipToNonWhitespace ( ) if b == Comma || p . done ( ) { selector = p . addAnd ( selector , p . hasKey ( word ) ) if b == Comma { p . advance ( ) _ = p . skipToNonWhitespace ( ) if p . done ( ) { return nil , p . parseError ( ) } } if p . done ( ) { break } continue } else { p . popMark ( ) } op , err = p . readOp ( ) if err != nil { return nil , err } switch op { case OpEquals , OpDoubleEquals : subSelector , err = p . equals ( word ) case OpNotEquals : subSelector , err = p . notEquals ( word ) case OpIn : subSelector , err = p . in ( word ) case OpNotIn : subSelector , err = p . notIn ( word ) default : return nil , p . parseError ( " " ) } if err != nil { return nil , err } selector = p . addAnd ( selector , subSelector ) b = p . skipToNonWhitespace ( ) if b == Comma { p . advance ( ) if p . done ( ) { return nil , p . parseError ( errExpectedNonEmptyKey ) } p . skipToNonWhitespace ( ) continue } if p . done ( ) { break } return nil , p . parseError ( " " ) } if ! p . skipValidation { err = selector . Validate ( ) if err != nil { return nil , err } } return selector , nil }
Parse does the actual parsing.
Parse does the actual parsing .
// loop over "clauses" // clauses are separated by commas and grouped logically as "ands" // sniff the !haskey form // we aren't going to use the '!' // read off the !KEY // readWord will leave us on the next non-alpha char // add the !KEY term // we're done peeking the first char // read the first KEY // mark to revert if the sniff for the `KEY` form fails // sniff if the next character after the word is a comma // this indicates it's a "key" form, or existence check on a key // the comma is not whitespace // this is largely a no-op unless we hit a comma // we _have_ to eat the next whitespace // we have a "foo == bar foo" situation