func parseExpr()

in query/parse.go [99:196]


func parseExpr(in []byte) (Q, int, error) {
	b := in[:]
	var expr Q
	for len(b) > 0 && isSpace(b[0]) {
		b = b[1:]
	}

	tok, err := nextToken(b)
	if err != nil {
		return nil, 0, err
	}
	if tok == nil {
		return nil, 0, nil
	}
	b = b[len(tok.Input):]

	text := string(tok.Text)
	switch tok.Type {
	case tokCase:
		switch text {
		case "yes":
		case "no":
		case "auto":
		default:
			return nil, 0, fmt.Errorf("query: unknown case argument %q, want {yes,no,auto}", text)
		}
		expr = &caseQ{text}
	case tokRepo:
		expr = &Repo{Pattern: text}
	case tokBranch:
		expr = &Branch{Pattern: text}
	case tokText, tokRegex:
		q, err := regexpQuery(text, false, false)
		if err != nil {
			return nil, 0, err
		}
		expr = q
	case tokFile:
		q, err := regexpQuery(text, false, true)
		if err != nil {
			return nil, 0, err
		}
		expr = q

	case tokContent:
		q, err := regexpQuery(text, true, false)
		if err != nil {
			return nil, 0, err
		}
		expr = q
	case tokLang:
		expr = &Language{Language: text}

	case tokSym:
		if text == "" {
			return nil, 0, fmt.Errorf("the sym: atom must have an argument")
		}
		expr = &Symbol{&Substring{Pattern: text}}

	case tokParenClose:
		// Caller must consume paren.
		expr = nil

	case tokParenOpen:
		qs, n, err := parseExprList(b)
		b = b[n:]
		if err != nil {
			return nil, 0, err
		}

		pTok, err := nextToken(b)
		if err != nil {
			return nil, 0, err
		}
		if pTok == nil || pTok.Type != tokParenClose {
			return nil, 0, fmt.Errorf("query: missing close paren, got token %v", pTok)
		}

		b = b[len(pTok.Input):]
		expr, err = parseOperators(qs)
		if err != nil {
			return nil, 0, err
		}
	case tokNegate:
		subQ, n, err := parseExpr(b)
		if err != nil {
			return nil, 0, err
		}
		if subQ == nil {
			return nil, 0, fmt.Errorf("query: '-' operator needs an argument")
		}
		b = b[n:]
		expr = &Not{subQ}

	}

	return expr, len(in) - len(b), nil
}