From 579fdf65e20d93b8fbd95531bec0cef8b106da5c Mon Sep 17 00:00:00 2001 From: Fabian Reinartz Date: Tue, 4 Aug 2015 14:57:34 +0200 Subject: [PATCH] Implement unary expression for vector types. Closes #956 --- promql/engine.go | 14 +++++++++++--- promql/parse.go | 4 +++- promql/parse_test.go | 43 ++++++++++++++++++++++++++++++++----------- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/promql/engine.go b/promql/engine.go index f7b2bbb8d..f32f373eb 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -691,11 +691,19 @@ func (ev *evaluator) eval(expr Expr) Value { return &String{Value: e.Val, Timestamp: ev.Timestamp} case *UnaryExpr: - smpl := ev.evalScalar(e.Expr) + se := ev.evalOneOf(e.Expr, ExprScalar, ExprVector) + // Only + and - are possible operators. if e.Op == itemSUB { - smpl.Value = -smpl.Value + switch v := se.(type) { + case *Scalar: + v.Value = -v.Value + case Vector: + for i, sv := range v { + v[i].Value = -sv.Value + } + } } - return smpl + return se case *VectorSelector: return ev.vectorSelector(e) diff --git a/promql/parse.go b/promql/parse.go index c1bc1fd7d..6cfc5ea2b 100644 --- a/promql/parse.go +++ b/promql/parse.go @@ -1075,7 +1075,9 @@ func (p *parser) checkType(node Node) (typ ExprType) { if n.Op != itemADD && n.Op != itemSUB { p.errorf("only + and - operators allowed for unary expressions") } - p.expectType(n.Expr, ExprScalar, "unary expression") + if t := p.checkType(n.Expr); t != ExprScalar && t != ExprVector { + p.errorf("unary expression only allowed on expressions of type scalar or vector, got %q", t) + } case *NumberLiteral, *MatrixSelector, *StringLiteral, *VectorSelector: // Nothing to do for terminals. diff --git a/promql/parse_test.go b/promql/parse_test.go index 3fc1df873..24d581bfb 100644 --- a/promql/parse_test.go +++ b/promql/parse_test.go @@ -123,6 +123,26 @@ var testExpr = []struct { }}, }, }, + }, { + input: "-some_metric", expected: &UnaryExpr{ + Op: itemSUB, + Expr: &VectorSelector{ + Name: "some_metric", + LabelMatchers: metric.LabelMatchers{ + {Type: metric.Equal, Name: clientmodel.MetricNameLabel, Value: "some_metric"}, + }, + }, + }, + }, { + input: "+some_metric", expected: &UnaryExpr{ + Op: itemADD, + Expr: &VectorSelector{ + Name: "some_metric", + LabelMatchers: metric.LabelMatchers{ + {Type: metric.Equal, Name: clientmodel.MetricNameLabel, Value: "some_metric"}, + }, + }, + }, }, { input: "", fail: true, @@ -191,14 +211,18 @@ var testExpr = []struct { input: "1 =~ 1", fail: true, errMsg: "could not parse remaining input \"=~ 1\"...", - }, { - input: "-some_metric", - fail: true, - errMsg: "expected type scalar in unary expression, got vector", }, { input: `-"string"`, fail: true, - errMsg: "expected type scalar in unary expression, got string", + errMsg: `unary expression only allowed on expressions of type scalar or vector, got "string"`, + }, { + input: `-test[5m]`, + fail: true, + errMsg: `unary expression only allowed on expressions of type scalar or vector, got "matrix"`, + }, { + input: `*test`, + fail: true, + errMsg: "no valid expression found", }, // Vector binary operations. { @@ -950,18 +974,15 @@ var testExpr = []struct { input: "-=", fail: true, errMsg: `no valid expression found`, - }, - { + }, { input: "++-++-+-+-<", fail: true, errMsg: `no valid expression found`, - }, - { + }, { input: "e-+=/(0)", fail: true, errMsg: `no valid expression found`, - }, - { + }, { input: "-If", fail: true, errMsg: `no valid expression found`,