mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-12 06:17:27 -08:00
Support scientific notation and special float values.
This adds support for scientific notation in the expression language, as well as for all possible literal forms of +Inf/-Inf/NaN. TODO: Keep enough state in the parser/lexer to distinguish contexts in which "Inf", "NaN", etc. should be parsed as a number vs. parsed as a label name. Currently, foo{nan="bar"} would be a syntax error. However, that is an existing bug for all our reserved words. E.g. foo{sum="bar"} is a syntax error as well. This should be fixed separately.
This commit is contained in:
parent
ae832c9e63
commit
c2ab54e9a6
|
@ -55,6 +55,11 @@ L [a-zA-Z_]
|
|||
M [a-zA-Z_:]
|
||||
U [smhdwy]
|
||||
|
||||
FLOAT [-+]?{D}*\.?{D}+{EXPONENT}?|[+-]?[iI][nN][fF]|[nN][aA][nN]
|
||||
EXPONENT [eE][-+]?[0-9]+
|
||||
|
||||
STR \"(\\.|[^\\"])*\"|\'(\\.|[^\\'])*\'
|
||||
|
||||
%x S_COMMENTS
|
||||
|
||||
%yyc c
|
||||
|
@ -88,19 +93,18 @@ avg|sum|max|min|count lval.str = strings.ToUpper(lexer.token()); return AGGR_
|
|||
[+\-] lval.str = lexer.token(); return ADDITIVE_OP
|
||||
[*/%] lval.str = lexer.token(); return MULT_OP
|
||||
|
||||
{D}+{U} lval.str = lexer.token(); return DURATION
|
||||
{L}({L}|{D})* lval.str = lexer.token(); return IDENTIFIER
|
||||
{M}({M}|{D})* lval.str = lexer.token(); return METRICNAME
|
||||
|
||||
\-?{D}+(\.{D}*)? num, err := strconv.ParseFloat(lexer.token(), 64);
|
||||
{FLOAT} num, err := strconv.ParseFloat(lexer.token(), 64);
|
||||
if (err != nil && err.(*strconv.NumError).Err == strconv.ErrSyntax) {
|
||||
panic("Invalid float")
|
||||
}
|
||||
lval.num = clientmodel.SampleValue(num)
|
||||
return NUMBER
|
||||
|
||||
\"(\\.|[^\\"])*\" lval.str = lexer.token()[1:len(lexer.token()) - 1]; return STRING
|
||||
\'(\\.|[^\\'])*\' lval.str = lexer.token()[1:len(lexer.token()) - 1]; return STRING
|
||||
{D}+{U} lval.str = lexer.token(); return DURATION
|
||||
{L}({L}|{D})* lval.str = lexer.token(); return IDENTIFIER
|
||||
{M}({M}|{D})* lval.str = lexer.token(); return METRICNAME
|
||||
|
||||
{STR} lval.str = lexer.token()[1:len(lexer.token()) - 1]; return STRING
|
||||
|
||||
[{}\[\]()=,] return int(lexer.buf[0])
|
||||
[\t\n\r ] /* gobble up any whitespace */
|
||||
|
|
1858
rules/lexer.l.go
1858
rules/lexer.l.go
File diff suppressed because it is too large
Load diff
|
@ -36,7 +36,7 @@ var (
|
|||
testEvalTime = testStartTime.Add(testSampleInterval * 10)
|
||||
fixturesPath = "fixtures"
|
||||
|
||||
reSample = regexp.MustCompile(`^(.*) \=\> (\-?\d+\.?\d*e?\d*|[+-]Inf|NaN) \@\[(\d+)\]$`)
|
||||
reSample = regexp.MustCompile(`^(.*)( \=\>|:) (\-?\d+\.?\d*e?\d*|[+-]Inf|NaN) \@\[(\d+)\]$`)
|
||||
minNormal = math.Float64frombits(0x0010000000000000) // The smallest positive normal value of type float64.
|
||||
)
|
||||
|
||||
|
@ -81,16 +81,16 @@ func samplesAlmostEqual(a, b string) bool {
|
|||
if aMatches[1] != bMatches[1] {
|
||||
return false // Labels don't match.
|
||||
}
|
||||
if aMatches[3] != bMatches[3] {
|
||||
if aMatches[4] != bMatches[4] {
|
||||
return false // Timestamps don't match.
|
||||
}
|
||||
// If we are here, we have the diff in the floats.
|
||||
// We have to check if they are almost equal.
|
||||
aVal, err := strconv.ParseFloat(aMatches[2], 64)
|
||||
aVal, err := strconv.ParseFloat(aMatches[3], 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bVal, err := strconv.ParseFloat(bMatches[2], 64)
|
||||
bVal, err := strconv.ParseFloat(bMatches[3], 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -902,6 +902,58 @@ func TestExpressions(t *testing.T) {
|
|||
`{instance="ins2", job="job2"} => 0.11666666666666667 @[%v]`,
|
||||
},
|
||||
},
|
||||
{
|
||||
expr: `12.34e6`,
|
||||
output: []string{`scalar: 12340000 @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `12.34e+6`,
|
||||
output: []string{`scalar: 12340000 @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `12.34e-6`,
|
||||
output: []string{`scalar: 0.00001234 @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `.2`,
|
||||
output: []string{`scalar: 0.2 @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `+0.2`,
|
||||
output: []string{`scalar: 0.2 @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `-0.2e-6`,
|
||||
output: []string{`scalar: -0.0000002 @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `+Inf`,
|
||||
output: []string{`scalar: +Inf @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `inF`,
|
||||
output: []string{`scalar: +Inf @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `-inf`,
|
||||
output: []string{`scalar: -Inf @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `NaN`,
|
||||
output: []string{`scalar: NaN @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `nan`,
|
||||
output: []string{`scalar: NaN @[%v]`},
|
||||
},
|
||||
{
|
||||
expr: `2.`,
|
||||
shouldFail: true,
|
||||
},
|
||||
{
|
||||
expr: `999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999`,
|
||||
output: []string{`scalar: +Inf @[%v]`},
|
||||
},
|
||||
}
|
||||
|
||||
storage, closer := newTestStorage(t)
|
||||
|
|
Loading…
Reference in a new issue