Fix parsing of label names which are also keywords
The current separation between lexer and parser is a bit fuzzy when it comes to operators, aggregators and other keywords. The lexer already tries to determine the type of a token, even though that type might change depending on the context. This led to the problematic behavior that no tokens known to the lexer could be used as label names, including operators (and, by, ...), aggregators (count, quantile, ...) or other keywords (for, offset, ...). This change additionally checks whether an identifier is one of these types. We might want to check whether the specific item identification should be moved from the lexer to the parser.
This commit is contained in:
parent
24db241bd5
commit
04ae6196f2
|
@ -889,3 +889,16 @@ func isDigit(r rune) bool {
|
|||
func isAlpha(r rune) bool {
|
||||
return r == '_' || ('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z')
|
||||
}
|
||||
|
||||
// isLabel reports whether the string can be used as label.
|
||||
func isLabel(s string) bool {
|
||||
if len(s) == 0 || !isAlpha(rune(s[0])) {
|
||||
return false
|
||||
}
|
||||
for _, c := range s[1:] {
|
||||
if !isAlphaNumeric(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -673,7 +673,10 @@ func (p *parser) labels() model.LabelNames {
|
|||
labels := model.LabelNames{}
|
||||
if p.peek().typ != itemRightParen {
|
||||
for {
|
||||
id := p.expect(itemIdentifier, ctx)
|
||||
id := p.next()
|
||||
if !isLabel(id.val) {
|
||||
p.errorf("unexpected %s in %s, expected label", id.desc(), ctx)
|
||||
}
|
||||
labels = append(labels, model.LabelName(id.val))
|
||||
|
||||
if p.peek().typ != itemComma {
|
||||
|
|
|
@ -1225,6 +1225,24 @@ var testExpr = []struct {
|
|||
},
|
||||
Param: &StringLiteral{"value"},
|
||||
},
|
||||
}, {
|
||||
// Test usage of keywords as label names.
|
||||
input: "sum without(and, by, avg, count, alert, annotations)(some_metric)",
|
||||
expected: &AggregateExpr{
|
||||
Op: itemSum,
|
||||
Without: true,
|
||||
Expr: &VectorSelector{
|
||||
Name: "some_metric",
|
||||
LabelMatchers: metric.LabelMatchers{
|
||||
mustLabelMatcher(metric.Equal, model.MetricNameLabel, "some_metric"),
|
||||
},
|
||||
},
|
||||
Grouping: model.LabelNames{"and", "by", "avg", "count", "alert", "annotations"},
|
||||
},
|
||||
}, {
|
||||
input: "sum without(==)(some_metric)",
|
||||
fail: true,
|
||||
errMsg: "unexpected <op:==> in grouping opts, expected label",
|
||||
}, {
|
||||
input: `sum some_metric by (test)`,
|
||||
fail: true,
|
||||
|
|
Loading…
Reference in New Issue