提交 c2ab54e9 编写于 作者: J Julius Volz

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.
上级 ae832c9e
......@@ -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 */
......
此差异已折叠。
......@@ -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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册