diff --git a/promql/lex.go b/promql/lex.go index 41dee517c..eccd91bf4 100644 --- a/promql/lex.go +++ b/promql/lex.go @@ -465,7 +465,7 @@ func lexStatements(l *lexer) stateFn { } } fallthrough - case isAlphaNumeric(r) || r == ':': + case isAlpha(r) || r == ':': l.backup() return lexKeywordOrIdentifier case r == '(': @@ -515,7 +515,7 @@ func lexInsideBraces(l *lexer) stateFn { return l.errorf("unexpected end of input inside braces") case isSpace(r): return lexSpace - case unicode.IsLetter(r) || r == '_': + case isAlpha(r): l.backup() return lexIdentifier case r == ',': @@ -703,5 +703,10 @@ func isEndOfLine(r rune) bool { // isAlphaNumeric reports whether r is an alphabetic, digit, or underscore. func isAlphaNumeric(r rune) bool { - return r == '_' || ('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z') || unicode.IsDigit(r) + return isAlpha(r) || unicode.IsDigit(r) +} + +// isAlpha reports whether r is an alphabetic or underscore. +func isAlpha(r rune) bool { + return r == '_' || ('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z') } diff --git a/promql/lex_test.go b/promql/lex_test.go index 71dd9a988..ce56d83f6 100644 --- a/promql/lex_test.go +++ b/promql/lex_test.go @@ -121,6 +121,12 @@ var tests = []struct { }, { input: "abc d", expected: []item{{itemIdentifier, 0, "abc"}, {itemIdentifier, 4, "d"}}, + }, { + input: ":bc", + expected: []item{{itemMetricIdentifier, 0, ":bc"}}, + }, { + input: "0a:bc", + fail: true, }, // Test comments. { @@ -247,6 +253,12 @@ var tests = []struct { { input: `台北`, fail: true, + }, { + input: `{台北='a'}`, + fail: true, + }, { + input: `{0a='a'}`, + fail: true, }, { input: `{foo='bar'}`, expected: []item{ diff --git a/promql/parse.go b/promql/parse.go index 58e5d8f3d..eeff1f7cc 100644 --- a/promql/parse.go +++ b/promql/parse.go @@ -453,6 +453,19 @@ func (p *parser) rangeSelector(vs *VectorSelector) *MatrixSelector { return e } +// parseNumber parses a number. +func (p *parser) number(val string) float64 { + n, err := strconv.ParseInt(val, 0, 64) + f := float64(n) + if err != nil { + f, err = strconv.ParseFloat(val, 64) + } + if err != nil { + p.errorf("error parsing number: %s", err) + } + return f +} + // primaryExpr parses a primary expression. // // | | | @@ -460,14 +473,7 @@ func (p *parser) rangeSelector(vs *VectorSelector) *MatrixSelector { func (p *parser) primaryExpr() Expr { switch t := p.next(); { case t.typ == itemNumber: - n, err := strconv.ParseInt(t.val, 0, 64) - f := float64(n) - if err != nil { - f, err = strconv.ParseFloat(t.val, 64) - } - if err != nil { - p.errorf("error parsing number: %s", err) - } + f := p.number(t.val) return &NumberLiteral{clientmodel.SampleValue(f)} case t.typ == itemString: