promql/parse.go
func (p *parser) expr() Expr {
	// Parse the starting expression.
	expr := p.unaryExpr()

	// Loop through the operations and construct a binary operation tree based
	// on the operators' precedence.
	for {
		// If the next token is not an operator the expression is done.
		op := p.peek().typ
		if !op.isOperator() {
			// Check for subquery.
			if op == ItemLeftBracket {
				expr = p.subqueryOrRangeSelector(expr, false)
				if s, ok := expr.(*SubqueryExpr); ok {
					// Parse optional offset.
					if p.peek().typ == ItemOffset {
						offset := p.offset()
						s.Offset = offset
					}
				}
			}
			return expr
		}
		p.next() // Consume operator.

		// Parse optional operator matching options. Its validity
		// is checked in the type-checking stage.
		vecMatching := &VectorMatching{
			Card: CardOneToOne,
		}
		if op.isSetOperator() {
			vecMatching.Card = CardManyToMany
		}

		returnBool := false
		// Parse bool modifier.
		if p.peek().typ == ItemBool {
			if !op.isComparisonOperator() {
				p.errorf("bool modifier can only be used on comparison operators")
			}
			p.next()
			returnBool = true
		}

		// Parse ON/IGNORING clause.
		if p.peek().typ == ItemOn || p.peek().typ == ItemIgnoring {
			if p.peek().typ == ItemOn {
				vecMatching.On = true
			}
			p.next()
			vecMatching.MatchingLabels = p.labels()

			// Parse grouping.
			if t := p.peek().typ; t == ItemGroupLeft || t == ItemGroupRight {
				p.next()
				if t == ItemGroupLeft {
					vecMatching.Card = CardManyToOne
				} else {
					vecMatching.Card = CardOneToMany
				}
				if p.peek().typ == ItemLeftParen {
					vecMatching.Include = p.labels()
				}
			}
		}

		for _, ln := range vecMatching.MatchingLabels {
			for _, ln2 := range vecMatching.Include {
				if ln == ln2 && vecMatching.On {
					p.errorf("label %q must not occur in ON and GROUP clause at once", ln)
				}
			}
		}

		// Parse the next operand.
		rhs := p.unaryExpr()

		// Assign the new root based on the precedence of the LHS and RHS operators.
		expr = p.balance(expr, op, rhs, vecMatching, returnBool)
	}
}
func (p *parser) expr() Expr {
	// Parse the starting expression.
	expr := p.unaryExpr()

	// Loop through the operations and construct a binary operation tree based
	// on the operators' precedence.
	for {
		// If the next token is not an operator the expression is done.
		op := p.peek().typ
		if !op.isOperator() {
			// Check for subquery.
			if op == ItemLeftBracket {
				expr = p.subqueryOrRangeSelector(expr, false)
				if s, ok := expr.(*SubqueryExpr); ok {
					// Parse optional offset.
					if p.peek().typ == ItemOffset {
						offset := p.offset()
						s.Offset = offset
					}
				}
			}
			return expr
		}
		p.next() // Consume operator.

		// Parse optional operator matching options. Its validity
		// is checked in the type-checking stage.
		vecMatching := &VectorMatching{
			Card: CardOneToOne,
		}
		if op.isSetOperator() {
			vecMatching.Card = CardManyToMany
		}

		returnBool := false
		// Parse bool modifier.
		if p.peek().typ == ItemBool {
			if !op.isComparisonOperator() {
				p.errorf("bool modifier can only be used on comparison operators")
			}
			p.next()
			returnBool = true
		}

		// Parse ON/IGNORING clause.
		if p.peek().typ == ItemOn || p.peek().typ == ItemIgnoring {
			if p.peek().typ == ItemOn {
				vecMatching.On = true
			}
			p.next()
			vecMatching.MatchingLabels = p.labels()

			// Parse grouping.
			if t := p.peek().typ; t == ItemGroupLeft || t == ItemGroupRight {
				p.next()
				if t == ItemGroupLeft {
					vecMatching.Card = CardManyToOne
				} else {
					vecMatching.Card = CardOneToMany
				}
				if p.peek().typ == ItemLeftParen {
					vecMatching.Include = p.labels()
				}
			}
		}

		for _, ln := range vecMatching.MatchingLabels {
			for _, ln2 := range vecMatching.Include {
				if ln == ln2 && vecMatching.On {
					p.errorf("label %q must not occur in ON and GROUP clause at once", ln)
				}
			}
		}

		// Parse the next operand.
		rhs := p.unaryExpr()

		// Assign the new root based on the precedence of the LHS and RHS operators.
		expr = p.balance(expr, op, rhs, vecMatching, returnBool)
	}
}
func ( p * parser ) expr ( ) Expr { // Parse the starting expression. expr := p . unaryExpr ( ) // Loop through the operations and construct a binary operation tree based // on the operators' precedence. for { // If the next token is not an operator the expression is done. op := p . peek ( ) . typ if ! op . isOperator ( ) { // Check for subquery. if op == ItemLeftBracket { expr = p . subqueryOrRangeSelector ( expr , false ) if s , ok := expr . ( * SubqueryExpr ) ; ok { // Parse optional offset. if p . peek ( ) . typ == ItemOffset { offset := p . offset ( ) s . Offset = offset } } } return expr } p . next ( ) // Consume operator. // Parse optional operator matching options. Its validity // is checked in the type-checking stage. vecMatching := & VectorMatching { Card : CardOneToOne , } if op . isSetOperator ( ) { vecMatching . Card = CardManyToMany } returnBool := false // Parse bool modifier. if p . peek ( ) . typ == ItemBool { if ! op . isComparisonOperator ( ) { p . errorf ( " " ) } p . next ( ) returnBool = true } // Parse ON/IGNORING clause. if p . peek ( ) . typ == ItemOn || p . peek ( ) . typ == ItemIgnoring { if p . peek ( ) . typ == ItemOn { vecMatching . On = true } p . next ( ) vecMatching . MatchingLabels = p . labels ( ) // Parse grouping. if t := p . peek ( ) . typ ; t == ItemGroupLeft || t == ItemGroupRight { p . next ( ) if t == ItemGroupLeft { vecMatching . Card = CardManyToOne } else { vecMatching . Card = CardOneToMany } if p . peek ( ) . typ == ItemLeftParen { vecMatching . Include = p . labels ( ) } } } for _ , ln := range vecMatching . MatchingLabels { for _ , ln2 := range vecMatching . Include { if ln == ln2 && vecMatching . On { p . errorf ( " " , ln ) } } } // Parse the next operand. rhs := p . unaryExpr ( ) // Assign the new root based on the precedence of the LHS and RHS operators. expr = p . balance ( expr , op , rhs , vecMatching , returnBool ) } }
// expr parses any expression.
expr parses any expression .