promql/parse.go
func (p *parser) aggrExpr() *AggregateExpr {
	const ctx = "aggregation"

	agop := p.next()
	if !agop.typ.isAggregator() {
		p.errorf("expected aggregation operator but got %s", agop)
	}
	var grouping []string
	var without bool

	modifiersFirst := false

	if t := p.peek().typ; t == ItemBy || t == ItemWithout {
		if t == ItemWithout {
			without = true
		}
		p.next()
		grouping = p.labels()
		modifiersFirst = true
	}

	p.expect(ItemLeftParen, ctx)
	var param Expr
	if agop.typ.isAggregatorWithParam() {
		param = p.expr()
		p.expect(ItemComma, ctx)
	}
	e := p.expr()
	p.expect(ItemRightParen, ctx)

	if !modifiersFirst {
		if t := p.peek().typ; t == ItemBy || t == ItemWithout {
			if len(grouping) > 0 {
				p.errorf("aggregation must only contain one grouping clause")
			}
			if t == ItemWithout {
				without = true
			}
			p.next()
			grouping = p.labels()
		}
	}

	return &AggregateExpr{
		Op:       agop.typ,
		Expr:     e,
		Param:    param,
		Grouping: grouping,
		Without:  without,
	}
}
func (p *parser) aggrExpr() *AggregateExpr {
	const ctx = "aggregation"

	agop := p.next()
	if !agop.typ.isAggregator() {
		p.errorf("expected aggregation operator but got %s", agop)
	}
	var grouping []string
	var without bool

	modifiersFirst := false

	if t := p.peek().typ; t == ItemBy || t == ItemWithout {
		if t == ItemWithout {
			without = true
		}
		p.next()
		grouping = p.labels()
		modifiersFirst = true
	}

	p.expect(ItemLeftParen, ctx)
	var param Expr
	if agop.typ.isAggregatorWithParam() {
		param = p.expr()
		p.expect(ItemComma, ctx)
	}
	e := p.expr()
	p.expect(ItemRightParen, ctx)

	if !modifiersFirst {
		if t := p.peek().typ; t == ItemBy || t == ItemWithout {
			if len(grouping) > 0 {
				p.errorf("aggregation must only contain one grouping clause")
			}
			if t == ItemWithout {
				without = true
			}
			p.next()
			grouping = p.labels()
		}
	}

	return &AggregateExpr{
		Op:       agop.typ,
		Expr:     e,
		Param:    param,
		Grouping: grouping,
		Without:  without,
	}
}
// aggrExpr parses an aggregation expression.
//
//		<aggr_op> (<Vector_expr>) [by|without <labels>]
//		<aggr_op> [by|without <labels>] (<Vector_expr>)
//