promql/parse.go
func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
	const ctx = "label matching"

	matchers := []*labels.Matcher{}

	p.expect(ItemLeftBrace, ctx)

	// Check if no matchers are provided.
	if p.peek().typ == ItemRightBrace {
		p.next()
		return matchers
	}

	for {
		label := p.expect(ItemIdentifier, ctx)

		op := p.next().typ
		if !op.isOperator() {
			p.errorf("expected label matching operator but got %s", op)
		}
		var validOp = false
		for _, allowedOp := range operators {
			if op == allowedOp {
				validOp = true
			}
		}
		if !validOp {
			p.errorf("operator must be one of %q, is %q", operators, op)
		}

		val := p.unquoteString(p.expect(ItemString, ctx).val)

		// Map the item to the respective match type.
		var matchType labels.MatchType
		switch op {
		case ItemEQL:
			matchType = labels.MatchEqual
		case ItemNEQ:
			matchType = labels.MatchNotEqual
		case ItemEQLRegex:
			matchType = labels.MatchRegexp
		case ItemNEQRegex:
			matchType = labels.MatchNotRegexp
		default:
			p.errorf("item %q is not a metric match type", op)
		}

		m, err := labels.NewMatcher(matchType, label.val, val)
		if err != nil {
			p.error(err)
		}

		matchers = append(matchers, m)

		if p.peek().typ == ItemIdentifier {
			p.errorf("missing comma before next identifier %q", p.peek().val)
		}

		// Terminate list if last matcher.
		if p.peek().typ != ItemComma {
			break
		}
		p.next()

		// Allow comma after each item in a multi-line listing.
		if p.peek().typ == ItemRightBrace {
			break
		}
	}

	p.expect(ItemRightBrace, ctx)

	return matchers
}
func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
	const ctx = "label matching"

	matchers := []*labels.Matcher{}

	p.expect(ItemLeftBrace, ctx)

	// Check if no matchers are provided.
	if p.peek().typ == ItemRightBrace {
		p.next()
		return matchers
	}

	for {
		label := p.expect(ItemIdentifier, ctx)

		op := p.next().typ
		if !op.isOperator() {
			p.errorf("expected label matching operator but got %s", op)
		}
		var validOp = false
		for _, allowedOp := range operators {
			if op == allowedOp {
				validOp = true
			}
		}
		if !validOp {
			p.errorf("operator must be one of %q, is %q", operators, op)
		}

		val := p.unquoteString(p.expect(ItemString, ctx).val)

		// Map the item to the respective match type.
		var matchType labels.MatchType
		switch op {
		case ItemEQL:
			matchType = labels.MatchEqual
		case ItemNEQ:
			matchType = labels.MatchNotEqual
		case ItemEQLRegex:
			matchType = labels.MatchRegexp
		case ItemNEQRegex:
			matchType = labels.MatchNotRegexp
		default:
			p.errorf("item %q is not a metric match type", op)
		}

		m, err := labels.NewMatcher(matchType, label.val, val)
		if err != nil {
			p.error(err)
		}

		matchers = append(matchers, m)

		if p.peek().typ == ItemIdentifier {
			p.errorf("missing comma before next identifier %q", p.peek().val)
		}

		// Terminate list if last matcher.
		if p.peek().typ != ItemComma {
			break
		}
		p.next()

		// Allow comma after each item in a multi-line listing.
		if p.peek().typ == ItemRightBrace {
			break
		}
	}

	p.expect(ItemRightBrace, ctx)

	return matchers
}
// labelMatchers parses a set of label matchers.
//
//		'{' [ <labelname> <match_op> <match_string>, ... ] '}'
//