in query/expr/parser.go [359:473]
func (p *Parser) parseUnaryExpr(inclusion bool) (Expr, error) {
// If the first token is a LPAREN then parse it as its own grouped expression.
if tok, _, _ := p.scanIgnoreWhitespace(); tok == LPAREN {
expr, err := p.ParseExpr(0)
if err != nil {
return nil, err
}
tok, pos, lit := p.scanIgnoreWhitespace()
if tok == RPAREN {
// Expect an RPAREN at the end.
if inclusion {
return &Call{Args: []Expr{expr}}, nil
}
return &ParenExpr{Expr: expr}, nil
} else if tok == COMMA {
// Parse a tuple as a function call with empty name.
var args []Expr
args = append(args, expr)
for {
// Parse an expression argument.
arg, err := p.ParseExpr(0)
if err != nil {
return nil, err
}
args = append(args, arg)
// If there's not a comma next then stop parsing arguments.
if tok, _, _ := p.scan(); tok != COMMA {
p.unscan()
break
}
}
// There should be a right parentheses at the end.
if tok, pos, lit := p.scan(); tok != RPAREN {
return nil, newParseError(tokstr(tok, lit), []string{")"}, pos)
}
return &Call{Args: args}, nil
} else {
return nil, newParseError(tokstr(tok, lit), []string{")"}, pos)
}
}
p.unscan()
// Read next token.
tok, pos, lit := p.scanIgnoreWhitespace()
if tok.isUnaryOperator() {
expr, err := p.ParseExpr(tok.Precedence())
if err != nil {
return nil, err
}
return &UnaryExpr{Op: tok, Expr: expr}, nil
}
switch tok {
case CASE:
return p.parseCase()
case IDENT:
// If the next immediate token is a left parentheses, parse as function call.
// Otherwise parse as a variable reference.
if tok0, _, _ := p.scan(); tok0 == LPAREN {
return p.parseCall(lit)
}
p.unscan() // unscan the last token (wasn't an LPAREN)
p.unscan() // unscan the IDENT token
// Parse it as a VarRef.
return p.parseVarRef()
case DISTINCT:
// If the next immediate token is a left parentheses, parse as function call.
// Otherwise parse as a Distinct expression.
tok0, pos, lit := p.scan()
if tok0 == LPAREN {
return p.parseCall("distinct")
} else if tok0 == WS {
tok1, pos, lit := p.scanIgnoreWhitespace()
if tok1 != IDENT {
return nil, newParseError(tokstr(tok1, lit), []string{"identifier"}, pos)
}
return &Distinct{Val: lit}, nil
}
return nil, newParseError(tokstr(tok0, lit), []string{"(", "identifier"}, pos)
case STRING:
return &StringLiteral{Val: lit}, nil
case NUMBER:
v, _ := strconv.ParseFloat(lit, 64)
e := &NumberLiteral{Val: v, Expr: lit}
var err error
e.Int, err = strconv.Atoi(e.Expr)
if err != nil {
e.ExprType = Float
e.Int = int(v)
} else if e.Int >= 0 {
e.ExprType = Unsigned
} else {
e.ExprType = Signed
}
return e, nil
case NULL:
return &NullLiteral{}, nil
case UNKNOWN:
return &UnknownLiteral{}, nil
case TRUE, FALSE:
return &BooleanLiteral{Val: (tok == TRUE)}, nil
case MUL:
return &Wildcard{}, nil
default:
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string", "number", "bool"}, pos)
}
}