Browse Source

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.
pull/1958/head
Tobias Schmidt 8 years ago
parent
commit
04ae6196f2
  1. 13
      promql/lex.go
  2. 5
      promql/parse.go
  3. 18
      promql/parse_test.go

13
promql/lex.go

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

5
promql/parse.go

@ -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 {

18
promql/parse_test.go

@ -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…
Cancel
Save