mirror of
https://github.com/prometheus/prometheus.git
synced 2026-05-12 08:06:52 +02:00
Merge pull request #18623 from roidelapluie/promql-parser-range-duration-keyword
promql/parser: recognize range in duration expressions
This commit is contained in:
commit
bd4758a835
@ -499,15 +499,15 @@ func lexStatements(l *Lexer) stateFn {
|
||||
l.backup()
|
||||
return lexKeywordOrIdentifier
|
||||
}
|
||||
switch r {
|
||||
case ':':
|
||||
switch {
|
||||
case r == ':':
|
||||
if l.gotColon {
|
||||
return l.errorf("unexpected colon %q", r)
|
||||
}
|
||||
l.emit(COLON)
|
||||
l.gotColon = true
|
||||
return lexStatements
|
||||
case 's', 'S', 'm', 'M':
|
||||
case isDurationKeywordStartChar(r):
|
||||
if l.scanDurationKeyword() {
|
||||
return lexStatements
|
||||
}
|
||||
@ -935,6 +935,32 @@ func lexNumber(l *Lexer) stateFn {
|
||||
return lexStatements
|
||||
}
|
||||
|
||||
// durationKeywordTokens maps lowercase duration keyword names to their token types.
|
||||
var durationKeywordTokens = map[string]ItemType{
|
||||
"step": STEP,
|
||||
"range": RANGE,
|
||||
"min": MIN,
|
||||
"max": MAX,
|
||||
}
|
||||
|
||||
// durationKeywordStartChars is the set of lowercase runes that can start a duration keyword,
|
||||
// derived from durationKeywordTokens.
|
||||
var durationKeywordStartChars = makeDurationKeywordStartChars()
|
||||
|
||||
func makeDurationKeywordStartChars() map[rune]struct{} {
|
||||
m := make(map[rune]struct{}, len(durationKeywordTokens))
|
||||
for kw := range durationKeywordTokens {
|
||||
m[rune(kw[0])] = struct{}{}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// isDurationKeywordStartChar reports whether r can be the first character of a duration keyword.
|
||||
func isDurationKeywordStartChar(r rune) bool {
|
||||
_, ok := durationKeywordStartChars[unicode.ToLower(r)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (l *Lexer) scanDurationKeyword() bool {
|
||||
for {
|
||||
switch r := l.next(); {
|
||||
@ -942,24 +968,12 @@ func (l *Lexer) scanDurationKeyword() bool {
|
||||
// absorb.
|
||||
default:
|
||||
l.backup()
|
||||
word := l.input[l.start:l.pos]
|
||||
kw := strings.ToLower(word)
|
||||
switch kw {
|
||||
case "step":
|
||||
l.emit(STEP)
|
||||
word := strings.ToLower(l.input[l.start:l.pos])
|
||||
if tok, ok := durationKeywordTokens[word]; ok {
|
||||
l.emit(tok)
|
||||
return true
|
||||
case "range":
|
||||
l.emit(RANGE)
|
||||
return true
|
||||
case "min":
|
||||
l.emit(MIN)
|
||||
return true
|
||||
case "max":
|
||||
l.emit(MAX)
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1239,7 +1253,7 @@ func lexDurationExpr(l *Lexer) stateFn {
|
||||
case r == ',':
|
||||
l.emit(COMMA)
|
||||
return lexDurationExpr
|
||||
case r == 's' || r == 'S' || r == 'm' || r == 'M' || r == 'r' || r == 'R':
|
||||
case isDurationKeywordStartChar(r):
|
||||
if l.scanDurationKeyword() {
|
||||
return lexDurationExpr
|
||||
}
|
||||
|
||||
@ -4718,6 +4718,32 @@ var testExpr = []struct {
|
||||
EndPos: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `foo[2m/range()]`,
|
||||
expected: &MatrixSelector{
|
||||
VectorSelector: &VectorSelector{
|
||||
Name: "foo",
|
||||
LabelMatchers: []*labels.Matcher{
|
||||
MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"),
|
||||
},
|
||||
PosRange: posrange.PositionRange{Start: 0, End: 3},
|
||||
},
|
||||
RangeExpr: &DurationExpr{
|
||||
Op: DIV,
|
||||
LHS: &NumberLiteral{
|
||||
Val: 120,
|
||||
Duration: true,
|
||||
PosRange: posrange.PositionRange{Start: 4, End: 6},
|
||||
},
|
||||
RHS: &DurationExpr{
|
||||
Op: RANGE,
|
||||
StartPos: 7,
|
||||
EndPos: 14,
|
||||
},
|
||||
},
|
||||
EndPos: 15,
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `foo[-range()]`,
|
||||
expected: &MatrixSelector{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user