func()

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)
	}
}