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
}