mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Expose lexer item types (#5358)
* Expose lexer item types We have generally agreed to expose AST types / values that are necessary to make sense of the AST outside of the promql package. Currently the `UnaryExpr`, `BinaryExpr`, and `AggregateExpr` AST nodes store the lexer item type to indicate the operator type, but since the individual item types aren't exposed, an external user of the package cannot determine the operator type. So this PR exposes them. Although not all item types are required to make sense of the AST (some are really only used in the lexer), I decided to expose them all here to be somewhat more consistent. Another option would be to not use lexer item types at all in AST nodes. The concrete motivation is my work on the PromQL->Flux transpiler, but this ought to be useful for other cases as well. Signed-off-by: Julius Volz <julius.volz@gmail.com> * Fix item type names in tests Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
985eaa8194
commit
8155cc4992
105
promql/engine.go
105
promql/engine.go
|
@ -36,7 +36,6 @@ import (
|
||||||
"github.com/prometheus/prometheus/pkg/timestamp"
|
"github.com/prometheus/prometheus/pkg/timestamp"
|
||||||
"github.com/prometheus/prometheus/pkg/value"
|
"github.com/prometheus/prometheus/pkg/value"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/util/stats"
|
"github.com/prometheus/prometheus/util/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1040,7 +1039,7 @@ func (ev *evaluator) eval(expr Expr) Value {
|
||||||
|
|
||||||
case *UnaryExpr:
|
case *UnaryExpr:
|
||||||
mat := ev.eval(e.Expr).(Matrix)
|
mat := ev.eval(e.Expr).(Matrix)
|
||||||
if e.Op == itemSUB {
|
if e.Op == ItemSUB {
|
||||||
for i := range mat {
|
for i := range mat {
|
||||||
mat[i].Metric = dropMetricName(mat[i].Metric)
|
mat[i].Metric = dropMetricName(mat[i].Metric)
|
||||||
for j := range mat[i].Points {
|
for j := range mat[i].Points {
|
||||||
|
@ -1062,15 +1061,15 @@ func (ev *evaluator) eval(expr Expr) Value {
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
case lt == ValueTypeVector && rt == ValueTypeVector:
|
case lt == ValueTypeVector && rt == ValueTypeVector:
|
||||||
switch e.Op {
|
switch e.Op {
|
||||||
case itemLAND:
|
case ItemLAND:
|
||||||
return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
|
return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
|
||||||
return ev.VectorAnd(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
|
return ev.VectorAnd(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
case itemLOR:
|
case ItemLOR:
|
||||||
return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
|
return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
|
||||||
return ev.VectorOr(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
|
return ev.VectorOr(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
case itemLUnless:
|
case ItemLUnless:
|
||||||
return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
|
return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
|
||||||
return ev.VectorUnless(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
|
return ev.VectorUnless(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh)
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
|
@ -1605,29 +1604,29 @@ func dropMetricName(l labels.Labels) labels.Labels {
|
||||||
// scalarBinop evaluates a binary operation between two Scalars.
|
// scalarBinop evaluates a binary operation between two Scalars.
|
||||||
func scalarBinop(op ItemType, lhs, rhs float64) float64 {
|
func scalarBinop(op ItemType, lhs, rhs float64) float64 {
|
||||||
switch op {
|
switch op {
|
||||||
case itemADD:
|
case ItemADD:
|
||||||
return lhs + rhs
|
return lhs + rhs
|
||||||
case itemSUB:
|
case ItemSUB:
|
||||||
return lhs - rhs
|
return lhs - rhs
|
||||||
case itemMUL:
|
case ItemMUL:
|
||||||
return lhs * rhs
|
return lhs * rhs
|
||||||
case itemDIV:
|
case ItemDIV:
|
||||||
return lhs / rhs
|
return lhs / rhs
|
||||||
case itemPOW:
|
case ItemPOW:
|
||||||
return math.Pow(lhs, rhs)
|
return math.Pow(lhs, rhs)
|
||||||
case itemMOD:
|
case ItemMOD:
|
||||||
return math.Mod(lhs, rhs)
|
return math.Mod(lhs, rhs)
|
||||||
case itemEQL:
|
case ItemEQL:
|
||||||
return btos(lhs == rhs)
|
return btos(lhs == rhs)
|
||||||
case itemNEQ:
|
case ItemNEQ:
|
||||||
return btos(lhs != rhs)
|
return btos(lhs != rhs)
|
||||||
case itemGTR:
|
case ItemGTR:
|
||||||
return btos(lhs > rhs)
|
return btos(lhs > rhs)
|
||||||
case itemLSS:
|
case ItemLSS:
|
||||||
return btos(lhs < rhs)
|
return btos(lhs < rhs)
|
||||||
case itemGTE:
|
case ItemGTE:
|
||||||
return btos(lhs >= rhs)
|
return btos(lhs >= rhs)
|
||||||
case itemLTE:
|
case ItemLTE:
|
||||||
return btos(lhs <= rhs)
|
return btos(lhs <= rhs)
|
||||||
}
|
}
|
||||||
panic(fmt.Errorf("operator %q not allowed for Scalar operations", op))
|
panic(fmt.Errorf("operator %q not allowed for Scalar operations", op))
|
||||||
|
@ -1636,29 +1635,29 @@ func scalarBinop(op ItemType, lhs, rhs float64) float64 {
|
||||||
// vectorElemBinop evaluates a binary operation between two Vector elements.
|
// vectorElemBinop evaluates a binary operation between two Vector elements.
|
||||||
func vectorElemBinop(op ItemType, lhs, rhs float64) (float64, bool) {
|
func vectorElemBinop(op ItemType, lhs, rhs float64) (float64, bool) {
|
||||||
switch op {
|
switch op {
|
||||||
case itemADD:
|
case ItemADD:
|
||||||
return lhs + rhs, true
|
return lhs + rhs, true
|
||||||
case itemSUB:
|
case ItemSUB:
|
||||||
return lhs - rhs, true
|
return lhs - rhs, true
|
||||||
case itemMUL:
|
case ItemMUL:
|
||||||
return lhs * rhs, true
|
return lhs * rhs, true
|
||||||
case itemDIV:
|
case ItemDIV:
|
||||||
return lhs / rhs, true
|
return lhs / rhs, true
|
||||||
case itemPOW:
|
case ItemPOW:
|
||||||
return math.Pow(lhs, rhs), true
|
return math.Pow(lhs, rhs), true
|
||||||
case itemMOD:
|
case ItemMOD:
|
||||||
return math.Mod(lhs, rhs), true
|
return math.Mod(lhs, rhs), true
|
||||||
case itemEQL:
|
case ItemEQL:
|
||||||
return lhs, lhs == rhs
|
return lhs, lhs == rhs
|
||||||
case itemNEQ:
|
case ItemNEQ:
|
||||||
return lhs, lhs != rhs
|
return lhs, lhs != rhs
|
||||||
case itemGTR:
|
case ItemGTR:
|
||||||
return lhs, lhs > rhs
|
return lhs, lhs > rhs
|
||||||
case itemLSS:
|
case ItemLSS:
|
||||||
return lhs, lhs < rhs
|
return lhs, lhs < rhs
|
||||||
case itemGTE:
|
case ItemGTE:
|
||||||
return lhs, lhs >= rhs
|
return lhs, lhs >= rhs
|
||||||
case itemLTE:
|
case ItemLTE:
|
||||||
return lhs, lhs <= rhs
|
return lhs, lhs <= rhs
|
||||||
}
|
}
|
||||||
panic(fmt.Errorf("operator %q not allowed for operations between Vectors", op))
|
panic(fmt.Errorf("operator %q not allowed for operations between Vectors", op))
|
||||||
|
@ -1678,7 +1677,7 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
|
|
||||||
result := map[uint64]*groupedAggregation{}
|
result := map[uint64]*groupedAggregation{}
|
||||||
var k int64
|
var k int64
|
||||||
if op == itemTopK || op == itemBottomK {
|
if op == ItemTopK || op == ItemBottomK {
|
||||||
f := param.(float64)
|
f := param.(float64)
|
||||||
if !convertibleToInt64(f) {
|
if !convertibleToInt64(f) {
|
||||||
ev.errorf("Scalar value %v overflows int64", f)
|
ev.errorf("Scalar value %v overflows int64", f)
|
||||||
|
@ -1689,11 +1688,11 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var q float64
|
var q float64
|
||||||
if op == itemQuantile {
|
if op == ItemQuantile {
|
||||||
q = param.(float64)
|
q = param.(float64)
|
||||||
}
|
}
|
||||||
var valueLabel string
|
var valueLabel string
|
||||||
if op == itemCountValues {
|
if op == ItemCountValues {
|
||||||
valueLabel = param.(string)
|
valueLabel = param.(string)
|
||||||
if !model.LabelName(valueLabel).IsValid() {
|
if !model.LabelName(valueLabel).IsValid() {
|
||||||
ev.errorf("invalid label name %q", valueLabel)
|
ev.errorf("invalid label name %q", valueLabel)
|
||||||
|
@ -1706,7 +1705,7 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
for _, s := range vec {
|
for _, s := range vec {
|
||||||
metric := s.Metric
|
metric := s.Metric
|
||||||
|
|
||||||
if op == itemCountValues {
|
if op == ItemCountValues {
|
||||||
lb := labels.NewBuilder(metric)
|
lb := labels.NewBuilder(metric)
|
||||||
lb.Set(valueLabel, strconv.FormatFloat(s.V, 'f', -1, 64))
|
lb.Set(valueLabel, strconv.FormatFloat(s.V, 'f', -1, 64))
|
||||||
metric = lb.Labels()
|
metric = lb.Labels()
|
||||||
|
@ -1754,15 +1753,15 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
if k > inputVecLen {
|
if k > inputVecLen {
|
||||||
resultSize = inputVecLen
|
resultSize = inputVecLen
|
||||||
}
|
}
|
||||||
if op == itemStdvar || op == itemStddev {
|
if op == ItemStdvar || op == ItemStddev {
|
||||||
result[groupingKey].value = 0.0
|
result[groupingKey].value = 0.0
|
||||||
} else if op == itemTopK || op == itemQuantile {
|
} else if op == ItemTopK || op == ItemQuantile {
|
||||||
result[groupingKey].heap = make(vectorByValueHeap, 0, resultSize)
|
result[groupingKey].heap = make(vectorByValueHeap, 0, resultSize)
|
||||||
heap.Push(&result[groupingKey].heap, &Sample{
|
heap.Push(&result[groupingKey].heap, &Sample{
|
||||||
Point: Point{V: s.V},
|
Point: Point{V: s.V},
|
||||||
Metric: s.Metric,
|
Metric: s.Metric,
|
||||||
})
|
})
|
||||||
} else if op == itemBottomK {
|
} else if op == ItemBottomK {
|
||||||
result[groupingKey].reverseHeap = make(vectorByReverseValueHeap, 0, resultSize)
|
result[groupingKey].reverseHeap = make(vectorByReverseValueHeap, 0, resultSize)
|
||||||
heap.Push(&result[groupingKey].reverseHeap, &Sample{
|
heap.Push(&result[groupingKey].reverseHeap, &Sample{
|
||||||
Point: Point{V: s.V},
|
Point: Point{V: s.V},
|
||||||
|
@ -1773,33 +1772,33 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
}
|
}
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case itemSum:
|
case ItemSum:
|
||||||
group.value += s.V
|
group.value += s.V
|
||||||
|
|
||||||
case itemAvg:
|
case ItemAvg:
|
||||||
group.groupCount++
|
group.groupCount++
|
||||||
group.mean += (s.V - group.mean) / float64(group.groupCount)
|
group.mean += (s.V - group.mean) / float64(group.groupCount)
|
||||||
|
|
||||||
case itemMax:
|
case ItemMax:
|
||||||
if group.value < s.V || math.IsNaN(group.value) {
|
if group.value < s.V || math.IsNaN(group.value) {
|
||||||
group.value = s.V
|
group.value = s.V
|
||||||
}
|
}
|
||||||
|
|
||||||
case itemMin:
|
case ItemMin:
|
||||||
if group.value > s.V || math.IsNaN(group.value) {
|
if group.value > s.V || math.IsNaN(group.value) {
|
||||||
group.value = s.V
|
group.value = s.V
|
||||||
}
|
}
|
||||||
|
|
||||||
case itemCount, itemCountValues:
|
case ItemCount, ItemCountValues:
|
||||||
group.groupCount++
|
group.groupCount++
|
||||||
|
|
||||||
case itemStdvar, itemStddev:
|
case ItemStdvar, ItemStddev:
|
||||||
group.groupCount++
|
group.groupCount++
|
||||||
delta := s.V - group.mean
|
delta := s.V - group.mean
|
||||||
group.mean += delta / float64(group.groupCount)
|
group.mean += delta / float64(group.groupCount)
|
||||||
group.value += delta * (s.V - group.mean)
|
group.value += delta * (s.V - group.mean)
|
||||||
|
|
||||||
case itemTopK:
|
case ItemTopK:
|
||||||
if int64(len(group.heap)) < k || group.heap[0].V < s.V || math.IsNaN(group.heap[0].V) {
|
if int64(len(group.heap)) < k || group.heap[0].V < s.V || math.IsNaN(group.heap[0].V) {
|
||||||
if int64(len(group.heap)) == k {
|
if int64(len(group.heap)) == k {
|
||||||
heap.Pop(&group.heap)
|
heap.Pop(&group.heap)
|
||||||
|
@ -1810,7 +1809,7 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case itemBottomK:
|
case ItemBottomK:
|
||||||
if int64(len(group.reverseHeap)) < k || group.reverseHeap[0].V > s.V || math.IsNaN(group.reverseHeap[0].V) {
|
if int64(len(group.reverseHeap)) < k || group.reverseHeap[0].V > s.V || math.IsNaN(group.reverseHeap[0].V) {
|
||||||
if int64(len(group.reverseHeap)) == k {
|
if int64(len(group.reverseHeap)) == k {
|
||||||
heap.Pop(&group.reverseHeap)
|
heap.Pop(&group.reverseHeap)
|
||||||
|
@ -1821,7 +1820,7 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case itemQuantile:
|
case ItemQuantile:
|
||||||
group.heap = append(group.heap, s)
|
group.heap = append(group.heap, s)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1832,19 +1831,19 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
// Construct the result Vector from the aggregated groups.
|
// Construct the result Vector from the aggregated groups.
|
||||||
for _, aggr := range result {
|
for _, aggr := range result {
|
||||||
switch op {
|
switch op {
|
||||||
case itemAvg:
|
case ItemAvg:
|
||||||
aggr.value = aggr.mean
|
aggr.value = aggr.mean
|
||||||
|
|
||||||
case itemCount, itemCountValues:
|
case ItemCount, ItemCountValues:
|
||||||
aggr.value = float64(aggr.groupCount)
|
aggr.value = float64(aggr.groupCount)
|
||||||
|
|
||||||
case itemStdvar:
|
case ItemStdvar:
|
||||||
aggr.value = aggr.value / float64(aggr.groupCount)
|
aggr.value = aggr.value / float64(aggr.groupCount)
|
||||||
|
|
||||||
case itemStddev:
|
case ItemStddev:
|
||||||
aggr.value = math.Sqrt(aggr.value / float64(aggr.groupCount))
|
aggr.value = math.Sqrt(aggr.value / float64(aggr.groupCount))
|
||||||
|
|
||||||
case itemTopK:
|
case ItemTopK:
|
||||||
// The heap keeps the lowest value on top, so reverse it.
|
// The heap keeps the lowest value on top, so reverse it.
|
||||||
sort.Sort(sort.Reverse(aggr.heap))
|
sort.Sort(sort.Reverse(aggr.heap))
|
||||||
for _, v := range aggr.heap {
|
for _, v := range aggr.heap {
|
||||||
|
@ -1855,7 +1854,7 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
}
|
}
|
||||||
continue // Bypass default append.
|
continue // Bypass default append.
|
||||||
|
|
||||||
case itemBottomK:
|
case ItemBottomK:
|
||||||
// The heap keeps the lowest value on top, so reverse it.
|
// The heap keeps the lowest value on top, so reverse it.
|
||||||
sort.Sort(sort.Reverse(aggr.reverseHeap))
|
sort.Sort(sort.Reverse(aggr.reverseHeap))
|
||||||
for _, v := range aggr.reverseHeap {
|
for _, v := range aggr.reverseHeap {
|
||||||
|
@ -1866,7 +1865,7 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
}
|
}
|
||||||
continue // Bypass default append.
|
continue // Bypass default append.
|
||||||
|
|
||||||
case itemQuantile:
|
case ItemQuantile:
|
||||||
aggr.value = quantile(q, aggr.heap)
|
aggr.value = quantile(q, aggr.heap)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1893,7 +1892,7 @@ func btos(b bool) float64 {
|
||||||
// result of the op operation.
|
// result of the op operation.
|
||||||
func shouldDropMetricName(op ItemType) bool {
|
func shouldDropMetricName(op ItemType) bool {
|
||||||
switch op {
|
switch op {
|
||||||
case itemADD, itemSUB, itemDIV, itemMUL, itemPOW, itemMOD:
|
case ItemADD, ItemSUB, ItemDIV, ItemMUL, ItemPOW, ItemMOD:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|
346
promql/lex.go
346
promql/lex.go
|
@ -30,11 +30,11 @@ type item struct {
|
||||||
// String returns a descriptive string for the item.
|
// String returns a descriptive string for the item.
|
||||||
func (i item) String() string {
|
func (i item) String() string {
|
||||||
switch {
|
switch {
|
||||||
case i.typ == itemEOF:
|
case i.typ == ItemEOF:
|
||||||
return "EOF"
|
return "EOF"
|
||||||
case i.typ == itemError:
|
case i.typ == ItemError:
|
||||||
return i.val
|
return i.val
|
||||||
case i.typ == itemIdentifier || i.typ == itemMetricIdentifier:
|
case i.typ == ItemIdentifier || i.typ == ItemMetricIdentifier:
|
||||||
return fmt.Sprintf("%q", i.val)
|
return fmt.Sprintf("%q", i.val)
|
||||||
case i.typ.isKeyword():
|
case i.typ.isKeyword():
|
||||||
return fmt.Sprintf("<%s>", i.val)
|
return fmt.Sprintf("<%s>", i.val)
|
||||||
|
@ -59,7 +59,7 @@ func (i ItemType) isAggregator() bool { return i > aggregatorsStart && i < aggre
|
||||||
// isAggregator returns true if the item is an aggregator that takes a parameter.
|
// isAggregator returns true if the item is an aggregator that takes a parameter.
|
||||||
// Returns false otherwise
|
// Returns false otherwise
|
||||||
func (i ItemType) isAggregatorWithParam() bool {
|
func (i ItemType) isAggregatorWithParam() bool {
|
||||||
return i == itemTopK || i == itemBottomK || i == itemCountValues || i == itemQuantile
|
return i == ItemTopK || i == ItemBottomK || i == ItemCountValues || i == ItemQuantile
|
||||||
}
|
}
|
||||||
|
|
||||||
// isKeyword returns true if the item corresponds to a keyword.
|
// isKeyword returns true if the item corresponds to a keyword.
|
||||||
|
@ -70,7 +70,7 @@ func (i ItemType) isKeyword() bool { return i > keywordsStart && i < keywordsEnd
|
||||||
// Returns false otherwise.
|
// Returns false otherwise.
|
||||||
func (i ItemType) isComparisonOperator() bool {
|
func (i ItemType) isComparisonOperator() bool {
|
||||||
switch i {
|
switch i {
|
||||||
case itemEQL, itemNEQ, itemLTE, itemLSS, itemGTE, itemGTR:
|
case ItemEQL, ItemNEQ, ItemLTE, ItemLSS, ItemGTE, ItemGTR:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -80,7 +80,7 @@ func (i ItemType) isComparisonOperator() bool {
|
||||||
// isSetOperator returns whether the item corresponds to a set operator.
|
// isSetOperator returns whether the item corresponds to a set operator.
|
||||||
func (i ItemType) isSetOperator() bool {
|
func (i ItemType) isSetOperator() bool {
|
||||||
switch i {
|
switch i {
|
||||||
case itemLAND, itemLOR, itemLUnless:
|
case ItemLAND, ItemLOR, ItemLUnless:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -94,17 +94,17 @@ const LowestPrec = 0 // Non-operators.
|
||||||
// is LowestPrec.
|
// is LowestPrec.
|
||||||
func (i ItemType) precedence() int {
|
func (i ItemType) precedence() int {
|
||||||
switch i {
|
switch i {
|
||||||
case itemLOR:
|
case ItemLOR:
|
||||||
return 1
|
return 1
|
||||||
case itemLAND, itemLUnless:
|
case ItemLAND, ItemLUnless:
|
||||||
return 2
|
return 2
|
||||||
case itemEQL, itemNEQ, itemLTE, itemLSS, itemGTE, itemGTR:
|
case ItemEQL, ItemNEQ, ItemLTE, ItemLSS, ItemGTE, ItemGTR:
|
||||||
return 3
|
return 3
|
||||||
case itemADD, itemSUB:
|
case ItemADD, ItemSUB:
|
||||||
return 4
|
return 4
|
||||||
case itemMUL, itemDIV, itemMOD:
|
case ItemMUL, ItemDIV, ItemMOD:
|
||||||
return 5
|
return 5
|
||||||
case itemPOW:
|
case ItemPOW:
|
||||||
return 6
|
return 6
|
||||||
default:
|
default:
|
||||||
return LowestPrec
|
return LowestPrec
|
||||||
|
@ -113,7 +113,7 @@ func (i ItemType) precedence() int {
|
||||||
|
|
||||||
func (i ItemType) isRightAssociative() bool {
|
func (i ItemType) isRightAssociative() bool {
|
||||||
switch i {
|
switch i {
|
||||||
case itemPOW:
|
case ItemPOW:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -124,138 +124,138 @@ func (i ItemType) isRightAssociative() bool {
|
||||||
type ItemType int
|
type ItemType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
itemError ItemType = iota // Error occurred, value is error message
|
ItemError ItemType = iota // Error occurred, value is error message
|
||||||
itemEOF
|
ItemEOF
|
||||||
itemComment
|
ItemComment
|
||||||
itemIdentifier
|
ItemIdentifier
|
||||||
itemMetricIdentifier
|
ItemMetricIdentifier
|
||||||
itemLeftParen
|
ItemLeftParen
|
||||||
itemRightParen
|
ItemRightParen
|
||||||
itemLeftBrace
|
ItemLeftBrace
|
||||||
itemRightBrace
|
ItemRightBrace
|
||||||
itemLeftBracket
|
ItemLeftBracket
|
||||||
itemRightBracket
|
ItemRightBracket
|
||||||
itemComma
|
ItemComma
|
||||||
itemAssign
|
ItemAssign
|
||||||
itemColon
|
ItemColon
|
||||||
itemSemicolon
|
ItemSemicolon
|
||||||
itemString
|
ItemString
|
||||||
itemNumber
|
ItemNumber
|
||||||
itemDuration
|
ItemDuration
|
||||||
itemBlank
|
ItemBlank
|
||||||
itemTimes
|
ItemTimes
|
||||||
itemSpace
|
ItemSpace
|
||||||
|
|
||||||
operatorsStart
|
operatorsStart
|
||||||
// Operators.
|
// Operators.
|
||||||
itemSUB
|
ItemSUB
|
||||||
itemADD
|
ItemADD
|
||||||
itemMUL
|
ItemMUL
|
||||||
itemMOD
|
ItemMOD
|
||||||
itemDIV
|
ItemDIV
|
||||||
itemLAND
|
ItemLAND
|
||||||
itemLOR
|
ItemLOR
|
||||||
itemLUnless
|
ItemLUnless
|
||||||
itemEQL
|
ItemEQL
|
||||||
itemNEQ
|
ItemNEQ
|
||||||
itemLTE
|
ItemLTE
|
||||||
itemLSS
|
ItemLSS
|
||||||
itemGTE
|
ItemGTE
|
||||||
itemGTR
|
ItemGTR
|
||||||
itemEQLRegex
|
ItemEQLRegex
|
||||||
itemNEQRegex
|
ItemNEQRegex
|
||||||
itemPOW
|
ItemPOW
|
||||||
operatorsEnd
|
operatorsEnd
|
||||||
|
|
||||||
aggregatorsStart
|
aggregatorsStart
|
||||||
// Aggregators.
|
// Aggregators.
|
||||||
itemAvg
|
ItemAvg
|
||||||
itemCount
|
ItemCount
|
||||||
itemSum
|
ItemSum
|
||||||
itemMin
|
ItemMin
|
||||||
itemMax
|
ItemMax
|
||||||
itemStddev
|
ItemStddev
|
||||||
itemStdvar
|
ItemStdvar
|
||||||
itemTopK
|
ItemTopK
|
||||||
itemBottomK
|
ItemBottomK
|
||||||
itemCountValues
|
ItemCountValues
|
||||||
itemQuantile
|
ItemQuantile
|
||||||
aggregatorsEnd
|
aggregatorsEnd
|
||||||
|
|
||||||
keywordsStart
|
keywordsStart
|
||||||
// Keywords.
|
// Keywords.
|
||||||
itemOffset
|
ItemOffset
|
||||||
itemBy
|
ItemBy
|
||||||
itemWithout
|
ItemWithout
|
||||||
itemOn
|
ItemOn
|
||||||
itemIgnoring
|
ItemIgnoring
|
||||||
itemGroupLeft
|
ItemGroupLeft
|
||||||
itemGroupRight
|
ItemGroupRight
|
||||||
itemBool
|
ItemBool
|
||||||
keywordsEnd
|
keywordsEnd
|
||||||
)
|
)
|
||||||
|
|
||||||
var key = map[string]ItemType{
|
var key = map[string]ItemType{
|
||||||
// Operators.
|
// Operators.
|
||||||
"and": itemLAND,
|
"and": ItemLAND,
|
||||||
"or": itemLOR,
|
"or": ItemLOR,
|
||||||
"unless": itemLUnless,
|
"unless": ItemLUnless,
|
||||||
|
|
||||||
// Aggregators.
|
// Aggregators.
|
||||||
"sum": itemSum,
|
"sum": ItemSum,
|
||||||
"avg": itemAvg,
|
"avg": ItemAvg,
|
||||||
"count": itemCount,
|
"count": ItemCount,
|
||||||
"min": itemMin,
|
"min": ItemMin,
|
||||||
"max": itemMax,
|
"max": ItemMax,
|
||||||
"stddev": itemStddev,
|
"stddev": ItemStddev,
|
||||||
"stdvar": itemStdvar,
|
"stdvar": ItemStdvar,
|
||||||
"topk": itemTopK,
|
"topk": ItemTopK,
|
||||||
"bottomk": itemBottomK,
|
"bottomk": ItemBottomK,
|
||||||
"count_values": itemCountValues,
|
"count_values": ItemCountValues,
|
||||||
"quantile": itemQuantile,
|
"quantile": ItemQuantile,
|
||||||
|
|
||||||
// Keywords.
|
// Keywords.
|
||||||
"offset": itemOffset,
|
"offset": ItemOffset,
|
||||||
"by": itemBy,
|
"by": ItemBy,
|
||||||
"without": itemWithout,
|
"without": ItemWithout,
|
||||||
"on": itemOn,
|
"on": ItemOn,
|
||||||
"ignoring": itemIgnoring,
|
"ignoring": ItemIgnoring,
|
||||||
"group_left": itemGroupLeft,
|
"group_left": ItemGroupLeft,
|
||||||
"group_right": itemGroupRight,
|
"group_right": ItemGroupRight,
|
||||||
"bool": itemBool,
|
"bool": ItemBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the default string representations for common items. It does not
|
// These are the default string representations for common items. It does not
|
||||||
// imply that those are the only character sequences that can be lexed to such an item.
|
// imply that those are the only character sequences that can be lexed to such an item.
|
||||||
var itemTypeStr = map[ItemType]string{
|
var itemTypeStr = map[ItemType]string{
|
||||||
itemLeftParen: "(",
|
ItemLeftParen: "(",
|
||||||
itemRightParen: ")",
|
ItemRightParen: ")",
|
||||||
itemLeftBrace: "{",
|
ItemLeftBrace: "{",
|
||||||
itemRightBrace: "}",
|
ItemRightBrace: "}",
|
||||||
itemLeftBracket: "[",
|
ItemLeftBracket: "[",
|
||||||
itemRightBracket: "]",
|
ItemRightBracket: "]",
|
||||||
itemComma: ",",
|
ItemComma: ",",
|
||||||
itemAssign: "=",
|
ItemAssign: "=",
|
||||||
itemColon: ":",
|
ItemColon: ":",
|
||||||
itemSemicolon: ";",
|
ItemSemicolon: ";",
|
||||||
itemBlank: "_",
|
ItemBlank: "_",
|
||||||
itemTimes: "x",
|
ItemTimes: "x",
|
||||||
itemSpace: "<space>",
|
ItemSpace: "<space>",
|
||||||
|
|
||||||
itemSUB: "-",
|
ItemSUB: "-",
|
||||||
itemADD: "+",
|
ItemADD: "+",
|
||||||
itemMUL: "*",
|
ItemMUL: "*",
|
||||||
itemMOD: "%",
|
ItemMOD: "%",
|
||||||
itemDIV: "/",
|
ItemDIV: "/",
|
||||||
itemEQL: "==",
|
ItemEQL: "==",
|
||||||
itemNEQ: "!=",
|
ItemNEQ: "!=",
|
||||||
itemLTE: "<=",
|
ItemLTE: "<=",
|
||||||
itemLSS: "<",
|
ItemLSS: "<",
|
||||||
itemGTE: ">=",
|
ItemGTE: ">=",
|
||||||
itemGTR: ">",
|
ItemGTR: ">",
|
||||||
itemEQLRegex: "=~",
|
ItemEQLRegex: "=~",
|
||||||
itemNEQRegex: "!~",
|
ItemNEQRegex: "!~",
|
||||||
itemPOW: "^",
|
ItemPOW: "^",
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -264,8 +264,8 @@ func init() {
|
||||||
itemTypeStr[ty] = s
|
itemTypeStr[ty] = s
|
||||||
}
|
}
|
||||||
// Special numbers.
|
// Special numbers.
|
||||||
key["inf"] = itemNumber
|
key["inf"] = ItemNumber
|
||||||
key["nan"] = itemNumber
|
key["nan"] = ItemNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i ItemType) String() string {
|
func (i ItemType) String() string {
|
||||||
|
@ -279,7 +279,7 @@ func (i item) desc() string {
|
||||||
if _, ok := itemTypeStr[i.typ]; ok {
|
if _, ok := itemTypeStr[i.typ]; ok {
|
||||||
return i.String()
|
return i.String()
|
||||||
}
|
}
|
||||||
if i.typ == itemEOF {
|
if i.typ == ItemEOF {
|
||||||
return i.typ.desc()
|
return i.typ.desc()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s %s", i.typ.desc(), i)
|
return fmt.Sprintf("%s %s", i.typ.desc(), i)
|
||||||
|
@ -287,21 +287,21 @@ func (i item) desc() string {
|
||||||
|
|
||||||
func (i ItemType) desc() string {
|
func (i ItemType) desc() string {
|
||||||
switch i {
|
switch i {
|
||||||
case itemError:
|
case ItemError:
|
||||||
return "error"
|
return "error"
|
||||||
case itemEOF:
|
case ItemEOF:
|
||||||
return "end of input"
|
return "end of input"
|
||||||
case itemComment:
|
case ItemComment:
|
||||||
return "comment"
|
return "comment"
|
||||||
case itemIdentifier:
|
case ItemIdentifier:
|
||||||
return "identifier"
|
return "identifier"
|
||||||
case itemMetricIdentifier:
|
case ItemMetricIdentifier:
|
||||||
return "metric identifier"
|
return "metric identifier"
|
||||||
case itemString:
|
case ItemString:
|
||||||
return "string"
|
return "string"
|
||||||
case itemNumber:
|
case ItemNumber:
|
||||||
return "number"
|
return "number"
|
||||||
case itemDuration:
|
case ItemDuration:
|
||||||
return "duration"
|
return "duration"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%q", i)
|
return fmt.Sprintf("%q", i)
|
||||||
|
@ -408,7 +408,7 @@ func (l *lexer) linePosition() int {
|
||||||
// errorf returns an error token and terminates the scan by passing
|
// errorf returns an error token and terminates the scan by passing
|
||||||
// back a nil pointer that will be the next state, terminating l.nextItem.
|
// back a nil pointer that will be the next state, terminating l.nextItem.
|
||||||
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
|
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
|
||||||
l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
|
l.items <- item{ItemError, l.start, fmt.Sprintf(format, args...)}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,52 +463,52 @@ func lexStatements(l *lexer) stateFn {
|
||||||
} else if l.bracketOpen {
|
} else if l.bracketOpen {
|
||||||
return l.errorf("unclosed left bracket")
|
return l.errorf("unclosed left bracket")
|
||||||
}
|
}
|
||||||
l.emit(itemEOF)
|
l.emit(ItemEOF)
|
||||||
return nil
|
return nil
|
||||||
case r == ',':
|
case r == ',':
|
||||||
l.emit(itemComma)
|
l.emit(ItemComma)
|
||||||
case isSpace(r):
|
case isSpace(r):
|
||||||
return lexSpace
|
return lexSpace
|
||||||
case r == '*':
|
case r == '*':
|
||||||
l.emit(itemMUL)
|
l.emit(ItemMUL)
|
||||||
case r == '/':
|
case r == '/':
|
||||||
l.emit(itemDIV)
|
l.emit(ItemDIV)
|
||||||
case r == '%':
|
case r == '%':
|
||||||
l.emit(itemMOD)
|
l.emit(ItemMOD)
|
||||||
case r == '+':
|
case r == '+':
|
||||||
l.emit(itemADD)
|
l.emit(ItemADD)
|
||||||
case r == '-':
|
case r == '-':
|
||||||
l.emit(itemSUB)
|
l.emit(ItemSUB)
|
||||||
case r == '^':
|
case r == '^':
|
||||||
l.emit(itemPOW)
|
l.emit(ItemPOW)
|
||||||
case r == '=':
|
case r == '=':
|
||||||
if t := l.peek(); t == '=' {
|
if t := l.peek(); t == '=' {
|
||||||
l.next()
|
l.next()
|
||||||
l.emit(itemEQL)
|
l.emit(ItemEQL)
|
||||||
} else if t == '~' {
|
} else if t == '~' {
|
||||||
return l.errorf("unexpected character after '=': %q", t)
|
return l.errorf("unexpected character after '=': %q", t)
|
||||||
} else {
|
} else {
|
||||||
l.emit(itemAssign)
|
l.emit(ItemAssign)
|
||||||
}
|
}
|
||||||
case r == '!':
|
case r == '!':
|
||||||
if t := l.next(); t == '=' {
|
if t := l.next(); t == '=' {
|
||||||
l.emit(itemNEQ)
|
l.emit(ItemNEQ)
|
||||||
} else {
|
} else {
|
||||||
return l.errorf("unexpected character after '!': %q", t)
|
return l.errorf("unexpected character after '!': %q", t)
|
||||||
}
|
}
|
||||||
case r == '<':
|
case r == '<':
|
||||||
if t := l.peek(); t == '=' {
|
if t := l.peek(); t == '=' {
|
||||||
l.next()
|
l.next()
|
||||||
l.emit(itemLTE)
|
l.emit(ItemLTE)
|
||||||
} else {
|
} else {
|
||||||
l.emit(itemLSS)
|
l.emit(ItemLSS)
|
||||||
}
|
}
|
||||||
case r == '>':
|
case r == '>':
|
||||||
if t := l.peek(); t == '=' {
|
if t := l.peek(); t == '=' {
|
||||||
l.next()
|
l.next()
|
||||||
l.emit(itemGTE)
|
l.emit(ItemGTE)
|
||||||
} else {
|
} else {
|
||||||
l.emit(itemGTR)
|
l.emit(ItemGTR)
|
||||||
}
|
}
|
||||||
case isDigit(r) || (r == '.' && isDigit(l.peek())):
|
case isDigit(r) || (r == '.' && isDigit(l.peek())):
|
||||||
l.backup()
|
l.backup()
|
||||||
|
@ -527,21 +527,21 @@ func lexStatements(l *lexer) stateFn {
|
||||||
if l.gotColon {
|
if l.gotColon {
|
||||||
return l.errorf("unexpected colon %q", r)
|
return l.errorf("unexpected colon %q", r)
|
||||||
}
|
}
|
||||||
l.emit(itemColon)
|
l.emit(ItemColon)
|
||||||
l.gotColon = true
|
l.gotColon = true
|
||||||
case r == '(':
|
case r == '(':
|
||||||
l.emit(itemLeftParen)
|
l.emit(ItemLeftParen)
|
||||||
l.parenDepth++
|
l.parenDepth++
|
||||||
return lexStatements
|
return lexStatements
|
||||||
case r == ')':
|
case r == ')':
|
||||||
l.emit(itemRightParen)
|
l.emit(ItemRightParen)
|
||||||
l.parenDepth--
|
l.parenDepth--
|
||||||
if l.parenDepth < 0 {
|
if l.parenDepth < 0 {
|
||||||
return l.errorf("unexpected right parenthesis %q", r)
|
return l.errorf("unexpected right parenthesis %q", r)
|
||||||
}
|
}
|
||||||
return lexStatements
|
return lexStatements
|
||||||
case r == '{':
|
case r == '{':
|
||||||
l.emit(itemLeftBrace)
|
l.emit(ItemLeftBrace)
|
||||||
l.braceOpen = true
|
l.braceOpen = true
|
||||||
return lexInsideBraces(l)
|
return lexInsideBraces(l)
|
||||||
case r == '[':
|
case r == '[':
|
||||||
|
@ -549,14 +549,14 @@ func lexStatements(l *lexer) stateFn {
|
||||||
return l.errorf("unexpected left bracket %q", r)
|
return l.errorf("unexpected left bracket %q", r)
|
||||||
}
|
}
|
||||||
l.gotColon = false
|
l.gotColon = false
|
||||||
l.emit(itemLeftBracket)
|
l.emit(ItemLeftBracket)
|
||||||
l.bracketOpen = true
|
l.bracketOpen = true
|
||||||
return lexDuration
|
return lexDuration
|
||||||
case r == ']':
|
case r == ']':
|
||||||
if !l.bracketOpen {
|
if !l.bracketOpen {
|
||||||
return l.errorf("unexpected right bracket %q", r)
|
return l.errorf("unexpected right bracket %q", r)
|
||||||
}
|
}
|
||||||
l.emit(itemRightBracket)
|
l.emit(ItemRightBracket)
|
||||||
l.bracketOpen = false
|
l.bracketOpen = false
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -581,7 +581,7 @@ func lexInsideBraces(l *lexer) stateFn {
|
||||||
l.backup()
|
l.backup()
|
||||||
return lexIdentifier
|
return lexIdentifier
|
||||||
case r == ',':
|
case r == ',':
|
||||||
l.emit(itemComma)
|
l.emit(ItemComma)
|
||||||
case r == '"' || r == '\'':
|
case r == '"' || r == '\'':
|
||||||
l.stringOpen = r
|
l.stringOpen = r
|
||||||
return lexString
|
return lexString
|
||||||
|
@ -590,24 +590,24 @@ func lexInsideBraces(l *lexer) stateFn {
|
||||||
return lexRawString
|
return lexRawString
|
||||||
case r == '=':
|
case r == '=':
|
||||||
if l.next() == '~' {
|
if l.next() == '~' {
|
||||||
l.emit(itemEQLRegex)
|
l.emit(ItemEQLRegex)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
l.backup()
|
l.backup()
|
||||||
l.emit(itemEQL)
|
l.emit(ItemEQL)
|
||||||
case r == '!':
|
case r == '!':
|
||||||
switch nr := l.next(); {
|
switch nr := l.next(); {
|
||||||
case nr == '~':
|
case nr == '~':
|
||||||
l.emit(itemNEQRegex)
|
l.emit(ItemNEQRegex)
|
||||||
case nr == '=':
|
case nr == '=':
|
||||||
l.emit(itemNEQ)
|
l.emit(ItemNEQ)
|
||||||
default:
|
default:
|
||||||
return l.errorf("unexpected character after '!' inside braces: %q", nr)
|
return l.errorf("unexpected character after '!' inside braces: %q", nr)
|
||||||
}
|
}
|
||||||
case r == '{':
|
case r == '{':
|
||||||
return l.errorf("unexpected left brace %q", r)
|
return l.errorf("unexpected left brace %q", r)
|
||||||
case r == '}':
|
case r == '}':
|
||||||
l.emit(itemRightBrace)
|
l.emit(ItemRightBrace)
|
||||||
l.braceOpen = false
|
l.braceOpen = false
|
||||||
|
|
||||||
if l.seriesDesc {
|
if l.seriesDesc {
|
||||||
|
@ -626,16 +626,16 @@ func lexValueSequence(l *lexer) stateFn {
|
||||||
case r == eof:
|
case r == eof:
|
||||||
return lexStatements
|
return lexStatements
|
||||||
case isSpace(r):
|
case isSpace(r):
|
||||||
l.emit(itemSpace)
|
l.emit(ItemSpace)
|
||||||
lexSpace(l)
|
lexSpace(l)
|
||||||
case r == '+':
|
case r == '+':
|
||||||
l.emit(itemADD)
|
l.emit(ItemADD)
|
||||||
case r == '-':
|
case r == '-':
|
||||||
l.emit(itemSUB)
|
l.emit(ItemSUB)
|
||||||
case r == 'x':
|
case r == 'x':
|
||||||
l.emit(itemTimes)
|
l.emit(ItemTimes)
|
||||||
case r == '_':
|
case r == '_':
|
||||||
l.emit(itemBlank)
|
l.emit(ItemBlank)
|
||||||
case isDigit(r) || (r == '.' && isDigit(l.peek())):
|
case isDigit(r) || (r == '.' && isDigit(l.peek())):
|
||||||
l.backup()
|
l.backup()
|
||||||
lexNumber(l)
|
lexNumber(l)
|
||||||
|
@ -730,7 +730,7 @@ Loop:
|
||||||
break Loop
|
break Loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l.emit(itemString)
|
l.emit(ItemString)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,7 +747,7 @@ Loop:
|
||||||
break Loop
|
break Loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l.emit(itemString)
|
l.emit(ItemString)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,7 +767,7 @@ func lexLineComment(l *lexer) stateFn {
|
||||||
r = l.next()
|
r = l.next()
|
||||||
}
|
}
|
||||||
l.backup()
|
l.backup()
|
||||||
l.emit(itemComment)
|
l.emit(ItemComment)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +781,7 @@ func lexDuration(l *lexer) stateFn {
|
||||||
return l.errorf("bad duration syntax: %q", l.input[l.start:l.pos])
|
return l.errorf("bad duration syntax: %q", l.input[l.start:l.pos])
|
||||||
}
|
}
|
||||||
l.backup()
|
l.backup()
|
||||||
l.emit(itemDuration)
|
l.emit(ItemDuration)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
return l.errorf("bad duration syntax: %q", l.input[l.start:l.pos])
|
return l.errorf("bad duration syntax: %q", l.input[l.start:l.pos])
|
||||||
|
@ -792,14 +792,14 @@ func lexNumber(l *lexer) stateFn {
|
||||||
if !l.scanNumber() {
|
if !l.scanNumber() {
|
||||||
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
||||||
}
|
}
|
||||||
l.emit(itemNumber)
|
l.emit(ItemNumber)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
|
|
||||||
// lexNumberOrDuration scans a number or a duration item.
|
// lexNumberOrDuration scans a number or a duration item.
|
||||||
func lexNumberOrDuration(l *lexer) stateFn {
|
func lexNumberOrDuration(l *lexer) stateFn {
|
||||||
if l.scanNumber() {
|
if l.scanNumber() {
|
||||||
l.emit(itemNumber)
|
l.emit(ItemNumber)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
// Next two chars must be a valid unit and a non-alphanumeric.
|
// Next two chars must be a valid unit and a non-alphanumeric.
|
||||||
|
@ -808,7 +808,7 @@ func lexNumberOrDuration(l *lexer) stateFn {
|
||||||
return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos])
|
return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos])
|
||||||
}
|
}
|
||||||
l.backup()
|
l.backup()
|
||||||
l.emit(itemDuration)
|
l.emit(ItemDuration)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos])
|
return l.errorf("bad number or duration syntax: %q", l.input[l.start:l.pos])
|
||||||
|
@ -845,7 +845,7 @@ func lexIdentifier(l *lexer) stateFn {
|
||||||
// absorb
|
// absorb
|
||||||
}
|
}
|
||||||
l.backup()
|
l.backup()
|
||||||
l.emit(itemIdentifier)
|
l.emit(ItemIdentifier)
|
||||||
return lexStatements
|
return lexStatements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,9 +864,9 @@ Loop:
|
||||||
if kw, ok := key[strings.ToLower(word)]; ok {
|
if kw, ok := key[strings.ToLower(word)]; ok {
|
||||||
l.emit(kw)
|
l.emit(kw)
|
||||||
} else if !strings.Contains(word, ":") {
|
} else if !strings.Contains(word, ":") {
|
||||||
l.emit(itemIdentifier)
|
l.emit(ItemIdentifier)
|
||||||
} else {
|
} else {
|
||||||
l.emit(itemMetricIdentifier)
|
l.emit(ItemMetricIdentifier)
|
||||||
}
|
}
|
||||||
break Loop
|
break Loop
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,19 +35,19 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: ",",
|
input: ",",
|
||||||
expected: []item{{itemComma, 0, ","}},
|
expected: []item{{ItemComma, 0, ","}},
|
||||||
}, {
|
}, {
|
||||||
input: "()",
|
input: "()",
|
||||||
expected: []item{{itemLeftParen, 0, `(`}, {itemRightParen, 1, `)`}},
|
expected: []item{{ItemLeftParen, 0, `(`}, {ItemRightParen, 1, `)`}},
|
||||||
}, {
|
}, {
|
||||||
input: "{}",
|
input: "{}",
|
||||||
expected: []item{{itemLeftBrace, 0, `{`}, {itemRightBrace, 1, `}`}},
|
expected: []item{{ItemLeftBrace, 0, `{`}, {ItemRightBrace, 1, `}`}},
|
||||||
}, {
|
}, {
|
||||||
input: "[5m]",
|
input: "[5m]",
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBracket, 0, `[`},
|
{ItemLeftBracket, 0, `[`},
|
||||||
{itemDuration, 1, `5m`},
|
{ItemDuration, 1, `5m`},
|
||||||
{itemRightBracket, 3, `]`},
|
{ItemRightBracket, 3, `]`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: "\r\n\r",
|
input: "\r\n\r",
|
||||||
|
@ -60,55 +60,55 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: "1",
|
input: "1",
|
||||||
expected: []item{{itemNumber, 0, "1"}},
|
expected: []item{{ItemNumber, 0, "1"}},
|
||||||
}, {
|
}, {
|
||||||
input: "4.23",
|
input: "4.23",
|
||||||
expected: []item{{itemNumber, 0, "4.23"}},
|
expected: []item{{ItemNumber, 0, "4.23"}},
|
||||||
}, {
|
}, {
|
||||||
input: ".3",
|
input: ".3",
|
||||||
expected: []item{{itemNumber, 0, ".3"}},
|
expected: []item{{ItemNumber, 0, ".3"}},
|
||||||
}, {
|
}, {
|
||||||
input: "5.",
|
input: "5.",
|
||||||
expected: []item{{itemNumber, 0, "5."}},
|
expected: []item{{ItemNumber, 0, "5."}},
|
||||||
}, {
|
}, {
|
||||||
input: "NaN",
|
input: "NaN",
|
||||||
expected: []item{{itemNumber, 0, "NaN"}},
|
expected: []item{{ItemNumber, 0, "NaN"}},
|
||||||
}, {
|
}, {
|
||||||
input: "nAN",
|
input: "nAN",
|
||||||
expected: []item{{itemNumber, 0, "nAN"}},
|
expected: []item{{ItemNumber, 0, "nAN"}},
|
||||||
}, {
|
}, {
|
||||||
input: "NaN 123",
|
input: "NaN 123",
|
||||||
expected: []item{{itemNumber, 0, "NaN"}, {itemNumber, 4, "123"}},
|
expected: []item{{ItemNumber, 0, "NaN"}, {ItemNumber, 4, "123"}},
|
||||||
}, {
|
}, {
|
||||||
input: "NaN123",
|
input: "NaN123",
|
||||||
expected: []item{{itemIdentifier, 0, "NaN123"}},
|
expected: []item{{ItemIdentifier, 0, "NaN123"}},
|
||||||
}, {
|
}, {
|
||||||
input: "iNf",
|
input: "iNf",
|
||||||
expected: []item{{itemNumber, 0, "iNf"}},
|
expected: []item{{ItemNumber, 0, "iNf"}},
|
||||||
}, {
|
}, {
|
||||||
input: "Inf",
|
input: "Inf",
|
||||||
expected: []item{{itemNumber, 0, "Inf"}},
|
expected: []item{{ItemNumber, 0, "Inf"}},
|
||||||
}, {
|
}, {
|
||||||
input: "+Inf",
|
input: "+Inf",
|
||||||
expected: []item{{itemADD, 0, "+"}, {itemNumber, 1, "Inf"}},
|
expected: []item{{ItemADD, 0, "+"}, {ItemNumber, 1, "Inf"}},
|
||||||
}, {
|
}, {
|
||||||
input: "+Inf 123",
|
input: "+Inf 123",
|
||||||
expected: []item{{itemADD, 0, "+"}, {itemNumber, 1, "Inf"}, {itemNumber, 5, "123"}},
|
expected: []item{{ItemADD, 0, "+"}, {ItemNumber, 1, "Inf"}, {ItemNumber, 5, "123"}},
|
||||||
}, {
|
}, {
|
||||||
input: "-Inf",
|
input: "-Inf",
|
||||||
expected: []item{{itemSUB, 0, "-"}, {itemNumber, 1, "Inf"}},
|
expected: []item{{ItemSUB, 0, "-"}, {ItemNumber, 1, "Inf"}},
|
||||||
}, {
|
}, {
|
||||||
input: "Infoo",
|
input: "Infoo",
|
||||||
expected: []item{{itemIdentifier, 0, "Infoo"}},
|
expected: []item{{ItemIdentifier, 0, "Infoo"}},
|
||||||
}, {
|
}, {
|
||||||
input: "-Infoo",
|
input: "-Infoo",
|
||||||
expected: []item{{itemSUB, 0, "-"}, {itemIdentifier, 1, "Infoo"}},
|
expected: []item{{ItemSUB, 0, "-"}, {ItemIdentifier, 1, "Infoo"}},
|
||||||
}, {
|
}, {
|
||||||
input: "-Inf 123",
|
input: "-Inf 123",
|
||||||
expected: []item{{itemSUB, 0, "-"}, {itemNumber, 1, "Inf"}, {itemNumber, 5, "123"}},
|
expected: []item{{ItemSUB, 0, "-"}, {ItemNumber, 1, "Inf"}, {ItemNumber, 5, "123"}},
|
||||||
}, {
|
}, {
|
||||||
input: "0x123",
|
input: "0x123",
|
||||||
expected: []item{{itemNumber, 0, "0x123"}},
|
expected: []item{{ItemNumber, 0, "0x123"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -117,22 +117,22 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: "\"test\\tsequence\"",
|
input: "\"test\\tsequence\"",
|
||||||
expected: []item{{itemString, 0, `"test\tsequence"`}},
|
expected: []item{{ItemString, 0, `"test\tsequence"`}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "\"test\\\\.expression\"",
|
input: "\"test\\\\.expression\"",
|
||||||
expected: []item{{itemString, 0, `"test\\.expression"`}},
|
expected: []item{{ItemString, 0, `"test\\.expression"`}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "\"test\\.expression\"",
|
input: "\"test\\.expression\"",
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemError, 0, "unknown escape sequence U+002E '.'"},
|
{ItemError, 0, "unknown escape sequence U+002E '.'"},
|
||||||
{itemString, 0, `"test\.expression"`},
|
{ItemString, 0, `"test\.expression"`},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "`test\\.expression`",
|
input: "`test\\.expression`",
|
||||||
expected: []item{{itemString, 0, "`test\\.expression`"}},
|
expected: []item{{ItemString, 0, "`test\\.expression`"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// See https://github.com/prometheus/prometheus/issues/939.
|
// See https://github.com/prometheus/prometheus/issues/939.
|
||||||
|
@ -146,19 +146,19 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: "5s",
|
input: "5s",
|
||||||
expected: []item{{itemDuration, 0, "5s"}},
|
expected: []item{{ItemDuration, 0, "5s"}},
|
||||||
}, {
|
}, {
|
||||||
input: "123m",
|
input: "123m",
|
||||||
expected: []item{{itemDuration, 0, "123m"}},
|
expected: []item{{ItemDuration, 0, "123m"}},
|
||||||
}, {
|
}, {
|
||||||
input: "1h",
|
input: "1h",
|
||||||
expected: []item{{itemDuration, 0, "1h"}},
|
expected: []item{{ItemDuration, 0, "1h"}},
|
||||||
}, {
|
}, {
|
||||||
input: "3w",
|
input: "3w",
|
||||||
expected: []item{{itemDuration, 0, "3w"}},
|
expected: []item{{ItemDuration, 0, "3w"}},
|
||||||
}, {
|
}, {
|
||||||
input: "1y",
|
input: "1y",
|
||||||
expected: []item{{itemDuration, 0, "1y"}},
|
expected: []item{{ItemDuration, 0, "1y"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -167,16 +167,16 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: "abc",
|
input: "abc",
|
||||||
expected: []item{{itemIdentifier, 0, "abc"}},
|
expected: []item{{ItemIdentifier, 0, "abc"}},
|
||||||
}, {
|
}, {
|
||||||
input: "a:bc",
|
input: "a:bc",
|
||||||
expected: []item{{itemMetricIdentifier, 0, "a:bc"}},
|
expected: []item{{ItemMetricIdentifier, 0, "a:bc"}},
|
||||||
}, {
|
}, {
|
||||||
input: "abc d",
|
input: "abc d",
|
||||||
expected: []item{{itemIdentifier, 0, "abc"}, {itemIdentifier, 4, "d"}},
|
expected: []item{{ItemIdentifier, 0, "abc"}, {ItemIdentifier, 4, "d"}},
|
||||||
}, {
|
}, {
|
||||||
input: ":bc",
|
input: ":bc",
|
||||||
expected: []item{{itemMetricIdentifier, 0, ":bc"}},
|
expected: []item{{ItemMetricIdentifier, 0, ":bc"}},
|
||||||
}, {
|
}, {
|
||||||
input: "0a:bc",
|
input: "0a:bc",
|
||||||
fail: true,
|
fail: true,
|
||||||
|
@ -188,13 +188,13 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: "# some comment",
|
input: "# some comment",
|
||||||
expected: []item{{itemComment, 0, "# some comment"}},
|
expected: []item{{ItemComment, 0, "# some comment"}},
|
||||||
}, {
|
}, {
|
||||||
input: "5 # 1+1\n5",
|
input: "5 # 1+1\n5",
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemNumber, 0, "5"},
|
{ItemNumber, 0, "5"},
|
||||||
{itemComment, 2, "# 1+1"},
|
{ItemComment, 2, "# 1+1"},
|
||||||
{itemNumber, 8, "5"},
|
{ItemNumber, 8, "5"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -204,56 +204,56 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: `=`,
|
input: `=`,
|
||||||
expected: []item{{itemAssign, 0, `=`}},
|
expected: []item{{ItemAssign, 0, `=`}},
|
||||||
}, {
|
}, {
|
||||||
// Inside braces equality is a single '=' character.
|
// Inside braces equality is a single '=' character.
|
||||||
input: `{=}`,
|
input: `{=}`,
|
||||||
expected: []item{{itemLeftBrace, 0, `{`}, {itemEQL, 1, `=`}, {itemRightBrace, 2, `}`}},
|
expected: []item{{ItemLeftBrace, 0, `{`}, {ItemEQL, 1, `=`}, {ItemRightBrace, 2, `}`}},
|
||||||
}, {
|
}, {
|
||||||
input: `==`,
|
input: `==`,
|
||||||
expected: []item{{itemEQL, 0, `==`}},
|
expected: []item{{ItemEQL, 0, `==`}},
|
||||||
}, {
|
}, {
|
||||||
input: `!=`,
|
input: `!=`,
|
||||||
expected: []item{{itemNEQ, 0, `!=`}},
|
expected: []item{{ItemNEQ, 0, `!=`}},
|
||||||
}, {
|
}, {
|
||||||
input: `<`,
|
input: `<`,
|
||||||
expected: []item{{itemLSS, 0, `<`}},
|
expected: []item{{ItemLSS, 0, `<`}},
|
||||||
}, {
|
}, {
|
||||||
input: `>`,
|
input: `>`,
|
||||||
expected: []item{{itemGTR, 0, `>`}},
|
expected: []item{{ItemGTR, 0, `>`}},
|
||||||
}, {
|
}, {
|
||||||
input: `>=`,
|
input: `>=`,
|
||||||
expected: []item{{itemGTE, 0, `>=`}},
|
expected: []item{{ItemGTE, 0, `>=`}},
|
||||||
}, {
|
}, {
|
||||||
input: `<=`,
|
input: `<=`,
|
||||||
expected: []item{{itemLTE, 0, `<=`}},
|
expected: []item{{ItemLTE, 0, `<=`}},
|
||||||
}, {
|
}, {
|
||||||
input: `+`,
|
input: `+`,
|
||||||
expected: []item{{itemADD, 0, `+`}},
|
expected: []item{{ItemADD, 0, `+`}},
|
||||||
}, {
|
}, {
|
||||||
input: `-`,
|
input: `-`,
|
||||||
expected: []item{{itemSUB, 0, `-`}},
|
expected: []item{{ItemSUB, 0, `-`}},
|
||||||
}, {
|
}, {
|
||||||
input: `*`,
|
input: `*`,
|
||||||
expected: []item{{itemMUL, 0, `*`}},
|
expected: []item{{ItemMUL, 0, `*`}},
|
||||||
}, {
|
}, {
|
||||||
input: `/`,
|
input: `/`,
|
||||||
expected: []item{{itemDIV, 0, `/`}},
|
expected: []item{{ItemDIV, 0, `/`}},
|
||||||
}, {
|
}, {
|
||||||
input: `^`,
|
input: `^`,
|
||||||
expected: []item{{itemPOW, 0, `^`}},
|
expected: []item{{ItemPOW, 0, `^`}},
|
||||||
}, {
|
}, {
|
||||||
input: `%`,
|
input: `%`,
|
||||||
expected: []item{{itemMOD, 0, `%`}},
|
expected: []item{{ItemMOD, 0, `%`}},
|
||||||
}, {
|
}, {
|
||||||
input: `AND`,
|
input: `AND`,
|
||||||
expected: []item{{itemLAND, 0, `AND`}},
|
expected: []item{{ItemLAND, 0, `AND`}},
|
||||||
}, {
|
}, {
|
||||||
input: `or`,
|
input: `or`,
|
||||||
expected: []item{{itemLOR, 0, `or`}},
|
expected: []item{{ItemLOR, 0, `or`}},
|
||||||
}, {
|
}, {
|
||||||
input: `unless`,
|
input: `unless`,
|
||||||
expected: []item{{itemLUnless, 0, `unless`}},
|
expected: []item{{ItemLUnless, 0, `unless`}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -262,25 +262,25 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: `sum`,
|
input: `sum`,
|
||||||
expected: []item{{itemSum, 0, `sum`}},
|
expected: []item{{ItemSum, 0, `sum`}},
|
||||||
}, {
|
}, {
|
||||||
input: `AVG`,
|
input: `AVG`,
|
||||||
expected: []item{{itemAvg, 0, `AVG`}},
|
expected: []item{{ItemAvg, 0, `AVG`}},
|
||||||
}, {
|
}, {
|
||||||
input: `MAX`,
|
input: `MAX`,
|
||||||
expected: []item{{itemMax, 0, `MAX`}},
|
expected: []item{{ItemMax, 0, `MAX`}},
|
||||||
}, {
|
}, {
|
||||||
input: `min`,
|
input: `min`,
|
||||||
expected: []item{{itemMin, 0, `min`}},
|
expected: []item{{ItemMin, 0, `min`}},
|
||||||
}, {
|
}, {
|
||||||
input: `count`,
|
input: `count`,
|
||||||
expected: []item{{itemCount, 0, `count`}},
|
expected: []item{{ItemCount, 0, `count`}},
|
||||||
}, {
|
}, {
|
||||||
input: `stdvar`,
|
input: `stdvar`,
|
||||||
expected: []item{{itemStdvar, 0, `stdvar`}},
|
expected: []item{{ItemStdvar, 0, `stdvar`}},
|
||||||
}, {
|
}, {
|
||||||
input: `stddev`,
|
input: `stddev`,
|
||||||
expected: []item{{itemStddev, 0, `stddev`}},
|
expected: []item{{ItemStddev, 0, `stddev`}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -289,28 +289,28 @@ var tests = []struct {
|
||||||
tests: []testCase{
|
tests: []testCase{
|
||||||
{
|
{
|
||||||
input: "offset",
|
input: "offset",
|
||||||
expected: []item{{itemOffset, 0, "offset"}},
|
expected: []item{{ItemOffset, 0, "offset"}},
|
||||||
}, {
|
}, {
|
||||||
input: "by",
|
input: "by",
|
||||||
expected: []item{{itemBy, 0, "by"}},
|
expected: []item{{ItemBy, 0, "by"}},
|
||||||
}, {
|
}, {
|
||||||
input: "without",
|
input: "without",
|
||||||
expected: []item{{itemWithout, 0, "without"}},
|
expected: []item{{ItemWithout, 0, "without"}},
|
||||||
}, {
|
}, {
|
||||||
input: "on",
|
input: "on",
|
||||||
expected: []item{{itemOn, 0, "on"}},
|
expected: []item{{ItemOn, 0, "on"}},
|
||||||
}, {
|
}, {
|
||||||
input: "ignoring",
|
input: "ignoring",
|
||||||
expected: []item{{itemIgnoring, 0, "ignoring"}},
|
expected: []item{{ItemIgnoring, 0, "ignoring"}},
|
||||||
}, {
|
}, {
|
||||||
input: "group_left",
|
input: "group_left",
|
||||||
expected: []item{{itemGroupLeft, 0, "group_left"}},
|
expected: []item{{ItemGroupLeft, 0, "group_left"}},
|
||||||
}, {
|
}, {
|
||||||
input: "group_right",
|
input: "group_right",
|
||||||
expected: []item{{itemGroupRight, 0, "group_right"}},
|
expected: []item{{ItemGroupRight, 0, "group_right"}},
|
||||||
}, {
|
}, {
|
||||||
input: "bool",
|
input: "bool",
|
||||||
expected: []item{{itemBool, 0, "bool"}},
|
expected: []item{{ItemBool, 0, "bool"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -329,56 +329,56 @@ var tests = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: `{foo='bar'}`,
|
input: `{foo='bar'}`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBrace, 0, `{`},
|
{ItemLeftBrace, 0, `{`},
|
||||||
{itemIdentifier, 1, `foo`},
|
{ItemIdentifier, 1, `foo`},
|
||||||
{itemEQL, 4, `=`},
|
{ItemEQL, 4, `=`},
|
||||||
{itemString, 5, `'bar'`},
|
{ItemString, 5, `'bar'`},
|
||||||
{itemRightBrace, 10, `}`},
|
{ItemRightBrace, 10, `}`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `{foo="bar"}`,
|
input: `{foo="bar"}`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBrace, 0, `{`},
|
{ItemLeftBrace, 0, `{`},
|
||||||
{itemIdentifier, 1, `foo`},
|
{ItemIdentifier, 1, `foo`},
|
||||||
{itemEQL, 4, `=`},
|
{ItemEQL, 4, `=`},
|
||||||
{itemString, 5, `"bar"`},
|
{ItemString, 5, `"bar"`},
|
||||||
{itemRightBrace, 10, `}`},
|
{ItemRightBrace, 10, `}`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `{foo="bar\"bar"}`,
|
input: `{foo="bar\"bar"}`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBrace, 0, `{`},
|
{ItemLeftBrace, 0, `{`},
|
||||||
{itemIdentifier, 1, `foo`},
|
{ItemIdentifier, 1, `foo`},
|
||||||
{itemEQL, 4, `=`},
|
{ItemEQL, 4, `=`},
|
||||||
{itemString, 5, `"bar\"bar"`},
|
{ItemString, 5, `"bar\"bar"`},
|
||||||
{itemRightBrace, 15, `}`},
|
{ItemRightBrace, 15, `}`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `{NaN != "bar" }`,
|
input: `{NaN != "bar" }`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBrace, 0, `{`},
|
{ItemLeftBrace, 0, `{`},
|
||||||
{itemIdentifier, 1, `NaN`},
|
{ItemIdentifier, 1, `NaN`},
|
||||||
{itemNEQ, 5, `!=`},
|
{ItemNEQ, 5, `!=`},
|
||||||
{itemString, 8, `"bar"`},
|
{ItemString, 8, `"bar"`},
|
||||||
{itemRightBrace, 14, `}`},
|
{ItemRightBrace, 14, `}`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `{alert=~"bar" }`,
|
input: `{alert=~"bar" }`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBrace, 0, `{`},
|
{ItemLeftBrace, 0, `{`},
|
||||||
{itemIdentifier, 1, `alert`},
|
{ItemIdentifier, 1, `alert`},
|
||||||
{itemEQLRegex, 6, `=~`},
|
{ItemEQLRegex, 6, `=~`},
|
||||||
{itemString, 8, `"bar"`},
|
{ItemString, 8, `"bar"`},
|
||||||
{itemRightBrace, 14, `}`},
|
{ItemRightBrace, 14, `}`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `{on!~"bar"}`,
|
input: `{on!~"bar"}`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBrace, 0, `{`},
|
{ItemLeftBrace, 0, `{`},
|
||||||
{itemIdentifier, 1, `on`},
|
{ItemIdentifier, 1, `on`},
|
||||||
{itemNEQRegex, 3, `!~`},
|
{ItemNEQRegex, 3, `!~`},
|
||||||
{itemString, 5, `"bar"`},
|
{ItemString, 5, `"bar"`},
|
||||||
{itemRightBrace, 10, `}`},
|
{ItemRightBrace, 10, `}`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `{alert!#"bar"}`, fail: true,
|
input: `{alert!#"bar"}`, fail: true,
|
||||||
|
@ -448,43 +448,43 @@ var tests = []struct {
|
||||||
{
|
{
|
||||||
input: `{} _ 1 x .3`,
|
input: `{} _ 1 x .3`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemLeftBrace, 0, `{`},
|
{ItemLeftBrace, 0, `{`},
|
||||||
{itemRightBrace, 1, `}`},
|
{ItemRightBrace, 1, `}`},
|
||||||
{itemSpace, 2, ` `},
|
{ItemSpace, 2, ` `},
|
||||||
{itemBlank, 3, `_`},
|
{ItemBlank, 3, `_`},
|
||||||
{itemSpace, 4, ` `},
|
{ItemSpace, 4, ` `},
|
||||||
{itemNumber, 5, `1`},
|
{ItemNumber, 5, `1`},
|
||||||
{itemSpace, 6, ` `},
|
{ItemSpace, 6, ` `},
|
||||||
{itemTimes, 7, `x`},
|
{ItemTimes, 7, `x`},
|
||||||
{itemSpace, 8, ` `},
|
{ItemSpace, 8, ` `},
|
||||||
{itemNumber, 9, `.3`},
|
{ItemNumber, 9, `.3`},
|
||||||
},
|
},
|
||||||
seriesDesc: true,
|
seriesDesc: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `metric +Inf Inf NaN`,
|
input: `metric +Inf Inf NaN`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemIdentifier, 0, `metric`},
|
{ItemIdentifier, 0, `metric`},
|
||||||
{itemSpace, 6, ` `},
|
{ItemSpace, 6, ` `},
|
||||||
{itemADD, 7, `+`},
|
{ItemADD, 7, `+`},
|
||||||
{itemNumber, 8, `Inf`},
|
{ItemNumber, 8, `Inf`},
|
||||||
{itemSpace, 11, ` `},
|
{ItemSpace, 11, ` `},
|
||||||
{itemNumber, 12, `Inf`},
|
{ItemNumber, 12, `Inf`},
|
||||||
{itemSpace, 15, ` `},
|
{ItemSpace, 15, ` `},
|
||||||
{itemNumber, 16, `NaN`},
|
{ItemNumber, 16, `NaN`},
|
||||||
},
|
},
|
||||||
seriesDesc: true,
|
seriesDesc: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `metric 1+1x4`,
|
input: `metric 1+1x4`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemIdentifier, 0, `metric`},
|
{ItemIdentifier, 0, `metric`},
|
||||||
{itemSpace, 6, ` `},
|
{ItemSpace, 6, ` `},
|
||||||
{itemNumber, 7, `1`},
|
{ItemNumber, 7, `1`},
|
||||||
{itemADD, 8, `+`},
|
{ItemADD, 8, `+`},
|
||||||
{itemNumber, 9, `1`},
|
{ItemNumber, 9, `1`},
|
||||||
{itemTimes, 10, `x`},
|
{ItemTimes, 10, `x`},
|
||||||
{itemNumber, 11, `4`},
|
{ItemNumber, 11, `4`},
|
||||||
},
|
},
|
||||||
seriesDesc: true,
|
seriesDesc: true,
|
||||||
},
|
},
|
||||||
|
@ -496,141 +496,141 @@ var tests = []struct {
|
||||||
{
|
{
|
||||||
input: `test_name{on!~"bar"}[4m:4s]`,
|
input: `test_name{on!~"bar"}[4m:4s]`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemIdentifier, 0, `test_name`},
|
{ItemIdentifier, 0, `test_name`},
|
||||||
{itemLeftBrace, 9, `{`},
|
{ItemLeftBrace, 9, `{`},
|
||||||
{itemIdentifier, 10, `on`},
|
{ItemIdentifier, 10, `on`},
|
||||||
{itemNEQRegex, 12, `!~`},
|
{ItemNEQRegex, 12, `!~`},
|
||||||
{itemString, 14, `"bar"`},
|
{ItemString, 14, `"bar"`},
|
||||||
{itemRightBrace, 19, `}`},
|
{ItemRightBrace, 19, `}`},
|
||||||
{itemLeftBracket, 20, `[`},
|
{ItemLeftBracket, 20, `[`},
|
||||||
{itemDuration, 21, `4m`},
|
{ItemDuration, 21, `4m`},
|
||||||
{itemColon, 23, `:`},
|
{ItemColon, 23, `:`},
|
||||||
{itemDuration, 24, `4s`},
|
{ItemDuration, 24, `4s`},
|
||||||
{itemRightBracket, 26, `]`},
|
{ItemRightBracket, 26, `]`},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `test:name{on!~"bar"}[4m:4s]`,
|
input: `test:name{on!~"bar"}[4m:4s]`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemMetricIdentifier, 0, `test:name`},
|
{ItemMetricIdentifier, 0, `test:name`},
|
||||||
{itemLeftBrace, 9, `{`},
|
{ItemLeftBrace, 9, `{`},
|
||||||
{itemIdentifier, 10, `on`},
|
{ItemIdentifier, 10, `on`},
|
||||||
{itemNEQRegex, 12, `!~`},
|
{ItemNEQRegex, 12, `!~`},
|
||||||
{itemString, 14, `"bar"`},
|
{ItemString, 14, `"bar"`},
|
||||||
{itemRightBrace, 19, `}`},
|
{ItemRightBrace, 19, `}`},
|
||||||
{itemLeftBracket, 20, `[`},
|
{ItemLeftBracket, 20, `[`},
|
||||||
{itemDuration, 21, `4m`},
|
{ItemDuration, 21, `4m`},
|
||||||
{itemColon, 23, `:`},
|
{ItemColon, 23, `:`},
|
||||||
{itemDuration, 24, `4s`},
|
{ItemDuration, 24, `4s`},
|
||||||
{itemRightBracket, 26, `]`},
|
{ItemRightBracket, 26, `]`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `test:name{on!~"b:ar"}[4m:4s]`,
|
input: `test:name{on!~"b:ar"}[4m:4s]`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemMetricIdentifier, 0, `test:name`},
|
{ItemMetricIdentifier, 0, `test:name`},
|
||||||
{itemLeftBrace, 9, `{`},
|
{ItemLeftBrace, 9, `{`},
|
||||||
{itemIdentifier, 10, `on`},
|
{ItemIdentifier, 10, `on`},
|
||||||
{itemNEQRegex, 12, `!~`},
|
{ItemNEQRegex, 12, `!~`},
|
||||||
{itemString, 14, `"b:ar"`},
|
{ItemString, 14, `"b:ar"`},
|
||||||
{itemRightBrace, 20, `}`},
|
{ItemRightBrace, 20, `}`},
|
||||||
{itemLeftBracket, 21, `[`},
|
{ItemLeftBracket, 21, `[`},
|
||||||
{itemDuration, 22, `4m`},
|
{ItemDuration, 22, `4m`},
|
||||||
{itemColon, 24, `:`},
|
{ItemColon, 24, `:`},
|
||||||
{itemDuration, 25, `4s`},
|
{ItemDuration, 25, `4s`},
|
||||||
{itemRightBracket, 27, `]`},
|
{ItemRightBracket, 27, `]`},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `test:name{on!~"b:ar"}[4m:]`,
|
input: `test:name{on!~"b:ar"}[4m:]`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemMetricIdentifier, 0, `test:name`},
|
{ItemMetricIdentifier, 0, `test:name`},
|
||||||
{itemLeftBrace, 9, `{`},
|
{ItemLeftBrace, 9, `{`},
|
||||||
{itemIdentifier, 10, `on`},
|
{ItemIdentifier, 10, `on`},
|
||||||
{itemNEQRegex, 12, `!~`},
|
{ItemNEQRegex, 12, `!~`},
|
||||||
{itemString, 14, `"b:ar"`},
|
{ItemString, 14, `"b:ar"`},
|
||||||
{itemRightBrace, 20, `}`},
|
{ItemRightBrace, 20, `}`},
|
||||||
{itemLeftBracket, 21, `[`},
|
{ItemLeftBracket, 21, `[`},
|
||||||
{itemDuration, 22, `4m`},
|
{ItemDuration, 22, `4m`},
|
||||||
{itemColon, 24, `:`},
|
{ItemColon, 24, `:`},
|
||||||
{itemRightBracket, 25, `]`},
|
{ItemRightBracket, 25, `]`},
|
||||||
},
|
},
|
||||||
}, { // Nested Subquery.
|
}, { // Nested Subquery.
|
||||||
input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s]`,
|
input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s]`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
|
|
||||||
{itemIdentifier, 0, `min_over_time`},
|
{ItemIdentifier, 0, `min_over_time`},
|
||||||
{itemLeftParen, 13, `(`},
|
{ItemLeftParen, 13, `(`},
|
||||||
{itemIdentifier, 14, `rate`},
|
{ItemIdentifier, 14, `rate`},
|
||||||
{itemLeftParen, 18, `(`},
|
{ItemLeftParen, 18, `(`},
|
||||||
{itemIdentifier, 19, `foo`},
|
{ItemIdentifier, 19, `foo`},
|
||||||
{itemLeftBrace, 22, `{`},
|
{ItemLeftBrace, 22, `{`},
|
||||||
{itemIdentifier, 23, `bar`},
|
{ItemIdentifier, 23, `bar`},
|
||||||
{itemEQL, 26, `=`},
|
{ItemEQL, 26, `=`},
|
||||||
{itemString, 27, `"baz"`},
|
{ItemString, 27, `"baz"`},
|
||||||
{itemRightBrace, 32, `}`},
|
{ItemRightBrace, 32, `}`},
|
||||||
{itemLeftBracket, 33, `[`},
|
{ItemLeftBracket, 33, `[`},
|
||||||
{itemDuration, 34, `2s`},
|
{ItemDuration, 34, `2s`},
|
||||||
{itemRightBracket, 36, `]`},
|
{ItemRightBracket, 36, `]`},
|
||||||
{itemRightParen, 37, `)`},
|
{ItemRightParen, 37, `)`},
|
||||||
{itemLeftBracket, 38, `[`},
|
{ItemLeftBracket, 38, `[`},
|
||||||
{itemDuration, 39, `5m`},
|
{ItemDuration, 39, `5m`},
|
||||||
{itemColon, 41, `:`},
|
{ItemColon, 41, `:`},
|
||||||
{itemRightBracket, 42, `]`},
|
{ItemRightBracket, 42, `]`},
|
||||||
{itemRightParen, 43, `)`},
|
{ItemRightParen, 43, `)`},
|
||||||
{itemLeftBracket, 44, `[`},
|
{ItemLeftBracket, 44, `[`},
|
||||||
{itemDuration, 45, `4m`},
|
{ItemDuration, 45, `4m`},
|
||||||
{itemColon, 47, `:`},
|
{ItemColon, 47, `:`},
|
||||||
{itemDuration, 48, `3s`},
|
{ItemDuration, 48, `3s`},
|
||||||
{itemRightBracket, 50, `]`},
|
{ItemRightBracket, 50, `]`},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Subquery with offset.
|
// Subquery with offset.
|
||||||
{
|
{
|
||||||
input: `test:name{on!~"b:ar"}[4m:4s] offset 10m`,
|
input: `test:name{on!~"b:ar"}[4m:4s] offset 10m`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
{itemMetricIdentifier, 0, `test:name`},
|
{ItemMetricIdentifier, 0, `test:name`},
|
||||||
{itemLeftBrace, 9, `{`},
|
{ItemLeftBrace, 9, `{`},
|
||||||
{itemIdentifier, 10, `on`},
|
{ItemIdentifier, 10, `on`},
|
||||||
{itemNEQRegex, 12, `!~`},
|
{ItemNEQRegex, 12, `!~`},
|
||||||
{itemString, 14, `"b:ar"`},
|
{ItemString, 14, `"b:ar"`},
|
||||||
{itemRightBrace, 20, `}`},
|
{ItemRightBrace, 20, `}`},
|
||||||
{itemLeftBracket, 21, `[`},
|
{ItemLeftBracket, 21, `[`},
|
||||||
{itemDuration, 22, `4m`},
|
{ItemDuration, 22, `4m`},
|
||||||
{itemColon, 24, `:`},
|
{ItemColon, 24, `:`},
|
||||||
{itemDuration, 25, `4s`},
|
{ItemDuration, 25, `4s`},
|
||||||
{itemRightBracket, 27, `]`},
|
{ItemRightBracket, 27, `]`},
|
||||||
{itemOffset, 29, "offset"},
|
{ItemOffset, 29, "offset"},
|
||||||
{itemDuration, 36, "10m"},
|
{ItemDuration, 36, "10m"},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:] offset 6m)[4m:3s]`,
|
input: `min_over_time(rate(foo{bar="baz"}[2s])[5m:] offset 6m)[4m:3s]`,
|
||||||
expected: []item{
|
expected: []item{
|
||||||
|
|
||||||
{itemIdentifier, 0, `min_over_time`},
|
{ItemIdentifier, 0, `min_over_time`},
|
||||||
{itemLeftParen, 13, `(`},
|
{ItemLeftParen, 13, `(`},
|
||||||
{itemIdentifier, 14, `rate`},
|
{ItemIdentifier, 14, `rate`},
|
||||||
{itemLeftParen, 18, `(`},
|
{ItemLeftParen, 18, `(`},
|
||||||
{itemIdentifier, 19, `foo`},
|
{ItemIdentifier, 19, `foo`},
|
||||||
{itemLeftBrace, 22, `{`},
|
{ItemLeftBrace, 22, `{`},
|
||||||
{itemIdentifier, 23, `bar`},
|
{ItemIdentifier, 23, `bar`},
|
||||||
{itemEQL, 26, `=`},
|
{ItemEQL, 26, `=`},
|
||||||
{itemString, 27, `"baz"`},
|
{ItemString, 27, `"baz"`},
|
||||||
{itemRightBrace, 32, `}`},
|
{ItemRightBrace, 32, `}`},
|
||||||
{itemLeftBracket, 33, `[`},
|
{ItemLeftBracket, 33, `[`},
|
||||||
{itemDuration, 34, `2s`},
|
{ItemDuration, 34, `2s`},
|
||||||
{itemRightBracket, 36, `]`},
|
{ItemRightBracket, 36, `]`},
|
||||||
{itemRightParen, 37, `)`},
|
{ItemRightParen, 37, `)`},
|
||||||
{itemLeftBracket, 38, `[`},
|
{ItemLeftBracket, 38, `[`},
|
||||||
{itemDuration, 39, `5m`},
|
{ItemDuration, 39, `5m`},
|
||||||
{itemColon, 41, `:`},
|
{ItemColon, 41, `:`},
|
||||||
{itemRightBracket, 42, `]`},
|
{ItemRightBracket, 42, `]`},
|
||||||
{itemOffset, 44, `offset`},
|
{ItemOffset, 44, `offset`},
|
||||||
{itemDuration, 51, `6m`},
|
{ItemDuration, 51, `6m`},
|
||||||
{itemRightParen, 53, `)`},
|
{ItemRightParen, 53, `)`},
|
||||||
{itemLeftBracket, 54, `[`},
|
{ItemLeftBracket, 54, `[`},
|
||||||
{itemDuration, 55, `4m`},
|
{ItemDuration, 55, `4m`},
|
||||||
{itemColon, 57, `:`},
|
{ItemColon, 57, `:`},
|
||||||
{itemDuration, 58, `3s`},
|
{ItemDuration, 58, `3s`},
|
||||||
{itemRightBracket, 60, `]`},
|
{ItemRightBracket, 60, `]`},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -677,18 +677,18 @@ func TestLexer(t *testing.T) {
|
||||||
|
|
||||||
lastItem := out[len(out)-1]
|
lastItem := out[len(out)-1]
|
||||||
if test.fail {
|
if test.fail {
|
||||||
if lastItem.typ != itemError {
|
if lastItem.typ != ItemError {
|
||||||
t.Logf("%d: input %q", i, test.input)
|
t.Logf("%d: input %q", i, test.input)
|
||||||
t.Fatalf("expected lexing error but did not fail")
|
t.Fatalf("expected lexing error but did not fail")
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if lastItem.typ == itemError {
|
if lastItem.typ == ItemError {
|
||||||
t.Logf("%d: input %q", i, test.input)
|
t.Logf("%d: input %q", i, test.input)
|
||||||
t.Fatalf("unexpected lexing error at position %d: %s", lastItem.pos, lastItem)
|
t.Fatalf("unexpected lexing error at position %d: %s", lastItem.pos, lastItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(lastItem, item{itemEOF, Pos(len(test.input)), ""}) {
|
if !reflect.DeepEqual(lastItem, item{ItemEOF, Pos(len(test.input)), ""}) {
|
||||||
t.Logf("%d: input %q", i, test.input)
|
t.Logf("%d: input %q", i, test.input)
|
||||||
t.Fatalf("lexing error: expected output to end with EOF item.\ngot:\n%s", expectedList(out))
|
t.Fatalf("lexing error: expected output to end with EOF item.\ngot:\n%s", expectedList(out))
|
||||||
}
|
}
|
||||||
|
|
183
promql/parse.go
183
promql/parse.go
|
@ -26,7 +26,6 @@ import (
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
"github.com/prometheus/prometheus/pkg/labels"
|
"github.com/prometheus/prometheus/pkg/labels"
|
||||||
"github.com/prometheus/prometheus/pkg/value"
|
"github.com/prometheus/prometheus/pkg/value"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/util/strutil"
|
"github.com/prometheus/prometheus/util/strutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -69,7 +68,7 @@ func ParseMetric(input string) (m labels.Labels, err error) {
|
||||||
defer p.recover(&err)
|
defer p.recover(&err)
|
||||||
|
|
||||||
m = p.metric()
|
m = p.metric()
|
||||||
if p.peek().typ != itemEOF {
|
if p.peek().typ != ItemEOF {
|
||||||
p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
|
p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
|
@ -82,11 +81,11 @@ func ParseMetricSelector(input string) (m []*labels.Matcher, err error) {
|
||||||
defer p.recover(&err)
|
defer p.recover(&err)
|
||||||
|
|
||||||
name := ""
|
name := ""
|
||||||
if t := p.peek().typ; t == itemMetricIdentifier || t == itemIdentifier {
|
if t := p.peek().typ; t == ItemMetricIdentifier || t == ItemIdentifier {
|
||||||
name = p.next().val
|
name = p.next().val
|
||||||
}
|
}
|
||||||
vs := p.VectorSelector(name)
|
vs := p.VectorSelector(name)
|
||||||
if p.peek().typ != itemEOF {
|
if p.peek().typ != ItemEOF {
|
||||||
p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
|
p.errorf("could not parse remaining input %.15q...", p.lex.input[p.lex.lastPos:])
|
||||||
}
|
}
|
||||||
return vs.LabelMatchers, nil
|
return vs.LabelMatchers, nil
|
||||||
|
@ -104,8 +103,8 @@ func newParser(input string) *parser {
|
||||||
func (p *parser) parseExpr() (expr Expr, err error) {
|
func (p *parser) parseExpr() (expr Expr, err error) {
|
||||||
defer p.recover(&err)
|
defer p.recover(&err)
|
||||||
|
|
||||||
for p.peek().typ != itemEOF {
|
for p.peek().typ != ItemEOF {
|
||||||
if p.peek().typ == itemComment {
|
if p.peek().typ == ItemComment {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if expr != nil {
|
if expr != nil {
|
||||||
|
@ -149,20 +148,20 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
|
||||||
|
|
||||||
const ctx = "series values"
|
const ctx = "series values"
|
||||||
for {
|
for {
|
||||||
for p.peek().typ == itemSpace {
|
for p.peek().typ == ItemSpace {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
if p.peek().typ == itemEOF {
|
if p.peek().typ == ItemEOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract blanks.
|
// Extract blanks.
|
||||||
if p.peek().typ == itemBlank {
|
if p.peek().typ == ItemBlank {
|
||||||
p.next()
|
p.next()
|
||||||
times := uint64(1)
|
times := uint64(1)
|
||||||
if p.peek().typ == itemTimes {
|
if p.peek().typ == ItemTimes {
|
||||||
p.next()
|
p.next()
|
||||||
times, err = strconv.ParseUint(p.expect(itemNumber, ctx).val, 10, 64)
|
times, err = strconv.ParseUint(p.expect(ItemNumber, ctx).val, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.errorf("invalid repetition in %s: %s", ctx, err)
|
p.errorf("invalid repetition in %s: %s", ctx, err)
|
||||||
}
|
}
|
||||||
|
@ -172,7 +171,7 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
|
||||||
}
|
}
|
||||||
// This is to ensure that there is a space between this and the next number.
|
// This is to ensure that there is a space between this and the next number.
|
||||||
// This is especially required if the next number is negative.
|
// This is especially required if the next number is negative.
|
||||||
if t := p.expectOneOf(itemSpace, itemEOF, ctx).typ; t == itemEOF {
|
if t := p.expectOneOf(ItemSpace, ItemEOF, ctx).typ; t == ItemEOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
@ -180,15 +179,15 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
|
||||||
|
|
||||||
// Extract values.
|
// Extract values.
|
||||||
sign := 1.0
|
sign := 1.0
|
||||||
if t := p.peek().typ; t == itemSUB || t == itemADD {
|
if t := p.peek().typ; t == ItemSUB || t == ItemADD {
|
||||||
if p.next().typ == itemSUB {
|
if p.next().typ == ItemSUB {
|
||||||
sign = -1
|
sign = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var k float64
|
var k float64
|
||||||
if t := p.peek().typ; t == itemNumber {
|
if t := p.peek().typ; t == ItemNumber {
|
||||||
k = sign * p.number(p.expect(itemNumber, ctx).val)
|
k = sign * p.number(p.expect(ItemNumber, ctx).val)
|
||||||
} else if t == itemIdentifier && p.peek().val == "stale" {
|
} else if t == ItemIdentifier && p.peek().val == "stale" {
|
||||||
p.next()
|
p.next()
|
||||||
k = math.Float64frombits(value.StaleNaN)
|
k = math.Float64frombits(value.StaleNaN)
|
||||||
} else {
|
} else {
|
||||||
|
@ -199,24 +198,24 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
|
||||||
})
|
})
|
||||||
|
|
||||||
// If there are no offset repetitions specified, proceed with the next value.
|
// If there are no offset repetitions specified, proceed with the next value.
|
||||||
if t := p.peek(); t.typ == itemSpace {
|
if t := p.peek(); t.typ == ItemSpace {
|
||||||
// This ensures there is a space between every value.
|
// This ensures there is a space between every value.
|
||||||
continue
|
continue
|
||||||
} else if t.typ == itemEOF {
|
} else if t.typ == ItemEOF {
|
||||||
break
|
break
|
||||||
} else if t.typ != itemADD && t.typ != itemSUB {
|
} else if t.typ != ItemADD && t.typ != ItemSUB {
|
||||||
p.errorf("expected next value or relative expansion in %s but got %s (value: %s)", ctx, t.desc(), p.peek())
|
p.errorf("expected next value or relative expansion in %s but got %s (value: %s)", ctx, t.desc(), p.peek())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand the repeated offsets into values.
|
// Expand the repeated offsets into values.
|
||||||
sign = 1.0
|
sign = 1.0
|
||||||
if p.next().typ == itemSUB {
|
if p.next().typ == ItemSUB {
|
||||||
sign = -1.0
|
sign = -1.0
|
||||||
}
|
}
|
||||||
offset := sign * p.number(p.expect(itemNumber, ctx).val)
|
offset := sign * p.number(p.expect(ItemNumber, ctx).val)
|
||||||
p.expect(itemTimes, ctx)
|
p.expect(ItemTimes, ctx)
|
||||||
|
|
||||||
times, err := strconv.ParseUint(p.expect(itemNumber, ctx).val, 10, 64)
|
times, err := strconv.ParseUint(p.expect(ItemNumber, ctx).val, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.errorf("invalid repetition in %s: %s", ctx, err)
|
p.errorf("invalid repetition in %s: %s", ctx, err)
|
||||||
}
|
}
|
||||||
|
@ -230,7 +229,7 @@ func (p *parser) parseSeriesDesc() (m labels.Labels, vals []sequenceValue, err e
|
||||||
// This is to ensure that there is a space between this expanding notation
|
// This is to ensure that there is a space between this expanding notation
|
||||||
// and the next number. This is especially required if the next number
|
// and the next number. This is especially required if the next number
|
||||||
// is negative.
|
// is negative.
|
||||||
if t := p.expectOneOf(itemSpace, itemEOF, ctx).typ; t == itemEOF {
|
if t := p.expectOneOf(ItemSpace, ItemEOF, ctx).typ; t == ItemEOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,12 +251,12 @@ func (p *parser) next() item {
|
||||||
} else {
|
} else {
|
||||||
t := p.lex.nextItem()
|
t := p.lex.nextItem()
|
||||||
// Skip comments.
|
// Skip comments.
|
||||||
for t.typ == itemComment {
|
for t.typ == ItemComment {
|
||||||
t = p.lex.nextItem()
|
t = p.lex.nextItem()
|
||||||
}
|
}
|
||||||
p.token[0] = t
|
p.token[0] = t
|
||||||
}
|
}
|
||||||
if p.token[p.peekCount].typ == itemError {
|
if p.token[p.peekCount].typ == ItemError {
|
||||||
p.errorf("%s", p.token[p.peekCount].val)
|
p.errorf("%s", p.token[p.peekCount].val)
|
||||||
}
|
}
|
||||||
return p.token[p.peekCount]
|
return p.token[p.peekCount]
|
||||||
|
@ -272,7 +271,7 @@ func (p *parser) peek() item {
|
||||||
|
|
||||||
t := p.lex.nextItem()
|
t := p.lex.nextItem()
|
||||||
// Skip comments.
|
// Skip comments.
|
||||||
for t.typ == itemComment {
|
for t.typ == ItemComment {
|
||||||
t = p.lex.nextItem()
|
t = p.lex.nextItem()
|
||||||
}
|
}
|
||||||
p.token[0] = t
|
p.token[0] = t
|
||||||
|
@ -352,11 +351,11 @@ func (p *parser) expr() Expr {
|
||||||
op := p.peek().typ
|
op := p.peek().typ
|
||||||
if !op.isOperator() {
|
if !op.isOperator() {
|
||||||
// Check for subquery.
|
// Check for subquery.
|
||||||
if op == itemLeftBracket {
|
if op == ItemLeftBracket {
|
||||||
expr = p.subqueryOrRangeSelector(expr, false)
|
expr = p.subqueryOrRangeSelector(expr, false)
|
||||||
if s, ok := expr.(*SubqueryExpr); ok {
|
if s, ok := expr.(*SubqueryExpr); ok {
|
||||||
// Parse optional offset.
|
// Parse optional offset.
|
||||||
if p.peek().typ == itemOffset {
|
if p.peek().typ == ItemOffset {
|
||||||
offset := p.offset()
|
offset := p.offset()
|
||||||
s.Offset = offset
|
s.Offset = offset
|
||||||
}
|
}
|
||||||
|
@ -377,7 +376,7 @@ func (p *parser) expr() Expr {
|
||||||
|
|
||||||
returnBool := false
|
returnBool := false
|
||||||
// Parse bool modifier.
|
// Parse bool modifier.
|
||||||
if p.peek().typ == itemBool {
|
if p.peek().typ == ItemBool {
|
||||||
if !op.isComparisonOperator() {
|
if !op.isComparisonOperator() {
|
||||||
p.errorf("bool modifier can only be used on comparison operators")
|
p.errorf("bool modifier can only be used on comparison operators")
|
||||||
}
|
}
|
||||||
|
@ -386,22 +385,22 @@ func (p *parser) expr() Expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse ON/IGNORING clause.
|
// Parse ON/IGNORING clause.
|
||||||
if p.peek().typ == itemOn || p.peek().typ == itemIgnoring {
|
if p.peek().typ == ItemOn || p.peek().typ == ItemIgnoring {
|
||||||
if p.peek().typ == itemOn {
|
if p.peek().typ == ItemOn {
|
||||||
vecMatching.On = true
|
vecMatching.On = true
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
vecMatching.MatchingLabels = p.labels()
|
vecMatching.MatchingLabels = p.labels()
|
||||||
|
|
||||||
// Parse grouping.
|
// Parse grouping.
|
||||||
if t := p.peek().typ; t == itemGroupLeft || t == itemGroupRight {
|
if t := p.peek().typ; t == ItemGroupLeft || t == ItemGroupRight {
|
||||||
p.next()
|
p.next()
|
||||||
if t == itemGroupLeft {
|
if t == ItemGroupLeft {
|
||||||
vecMatching.Card = CardManyToOne
|
vecMatching.Card = CardManyToOne
|
||||||
} else {
|
} else {
|
||||||
vecMatching.Card = CardOneToMany
|
vecMatching.Card = CardOneToMany
|
||||||
}
|
}
|
||||||
if p.peek().typ == itemLeftParen {
|
if p.peek().typ == ItemLeftParen {
|
||||||
vecMatching.Include = p.labels()
|
vecMatching.Include = p.labels()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,35 +457,35 @@ func (p *parser) balance(lhs Expr, op ItemType, rhs Expr, vecMatching *VectorMat
|
||||||
//
|
//
|
||||||
func (p *parser) unaryExpr() Expr {
|
func (p *parser) unaryExpr() Expr {
|
||||||
switch t := p.peek(); t.typ {
|
switch t := p.peek(); t.typ {
|
||||||
case itemADD, itemSUB:
|
case ItemADD, ItemSUB:
|
||||||
p.next()
|
p.next()
|
||||||
e := p.unaryExpr()
|
e := p.unaryExpr()
|
||||||
|
|
||||||
// Simplify unary expressions for number literals.
|
// Simplify unary expressions for number literals.
|
||||||
if nl, ok := e.(*NumberLiteral); ok {
|
if nl, ok := e.(*NumberLiteral); ok {
|
||||||
if t.typ == itemSUB {
|
if t.typ == ItemSUB {
|
||||||
nl.Val *= -1
|
nl.Val *= -1
|
||||||
}
|
}
|
||||||
return nl
|
return nl
|
||||||
}
|
}
|
||||||
return &UnaryExpr{Op: t.typ, Expr: e}
|
return &UnaryExpr{Op: t.typ, Expr: e}
|
||||||
|
|
||||||
case itemLeftParen:
|
case ItemLeftParen:
|
||||||
p.next()
|
p.next()
|
||||||
e := p.expr()
|
e := p.expr()
|
||||||
p.expect(itemRightParen, "paren expression")
|
p.expect(ItemRightParen, "paren expression")
|
||||||
|
|
||||||
return &ParenExpr{Expr: e}
|
return &ParenExpr{Expr: e}
|
||||||
}
|
}
|
||||||
e := p.primaryExpr()
|
e := p.primaryExpr()
|
||||||
|
|
||||||
// Expression might be followed by a range selector.
|
// Expression might be followed by a range selector.
|
||||||
if p.peek().typ == itemLeftBracket {
|
if p.peek().typ == ItemLeftBracket {
|
||||||
e = p.subqueryOrRangeSelector(e, true)
|
e = p.subqueryOrRangeSelector(e, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse optional offset.
|
// Parse optional offset.
|
||||||
if p.peek().typ == itemOffset {
|
if p.peek().typ == ItemOffset {
|
||||||
offset := p.offset()
|
offset := p.offset()
|
||||||
|
|
||||||
switch s := e.(type) {
|
switch s := e.(type) {
|
||||||
|
@ -520,7 +519,7 @@ func (p *parser) subqueryOrRangeSelector(expr Expr, checkRange bool) Expr {
|
||||||
var erange time.Duration
|
var erange time.Duration
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
erangeStr := p.expect(itemDuration, ctx).val
|
erangeStr := p.expect(ItemDuration, ctx).val
|
||||||
erange, err = parseDuration(erangeStr)
|
erange, err = parseDuration(erangeStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.error(err)
|
p.error(err)
|
||||||
|
@ -528,8 +527,8 @@ func (p *parser) subqueryOrRangeSelector(expr Expr, checkRange bool) Expr {
|
||||||
|
|
||||||
var itm item
|
var itm item
|
||||||
if checkRange {
|
if checkRange {
|
||||||
itm = p.expectOneOf(itemRightBracket, itemColon, ctx)
|
itm = p.expectOneOf(ItemRightBracket, ItemColon, ctx)
|
||||||
if itm.typ == itemRightBracket {
|
if itm.typ == ItemRightBracket {
|
||||||
// Range selector.
|
// Range selector.
|
||||||
vs, ok := expr.(*VectorSelector)
|
vs, ok := expr.(*VectorSelector)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -542,20 +541,20 @@ func (p *parser) subqueryOrRangeSelector(expr Expr, checkRange bool) Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
itm = p.expect(itemColon, ctx)
|
itm = p.expect(ItemColon, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subquery.
|
// Subquery.
|
||||||
var estep time.Duration
|
var estep time.Duration
|
||||||
|
|
||||||
itm = p.expectOneOf(itemRightBracket, itemDuration, ctx)
|
itm = p.expectOneOf(ItemRightBracket, ItemDuration, ctx)
|
||||||
if itm.typ == itemDuration {
|
if itm.typ == ItemDuration {
|
||||||
estepStr := itm.val
|
estepStr := itm.val
|
||||||
estep, err = parseDuration(estepStr)
|
estep, err = parseDuration(estepStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.error(err)
|
p.error(err)
|
||||||
}
|
}
|
||||||
p.expect(itemRightBracket, ctx)
|
p.expect(ItemRightBracket, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SubqueryExpr{
|
return &SubqueryExpr{
|
||||||
|
@ -584,26 +583,26 @@ func (p *parser) number(val string) float64 {
|
||||||
//
|
//
|
||||||
func (p *parser) primaryExpr() Expr {
|
func (p *parser) primaryExpr() Expr {
|
||||||
switch t := p.next(); {
|
switch t := p.next(); {
|
||||||
case t.typ == itemNumber:
|
case t.typ == ItemNumber:
|
||||||
f := p.number(t.val)
|
f := p.number(t.val)
|
||||||
return &NumberLiteral{f}
|
return &NumberLiteral{f}
|
||||||
|
|
||||||
case t.typ == itemString:
|
case t.typ == ItemString:
|
||||||
return &StringLiteral{p.unquoteString(t.val)}
|
return &StringLiteral{p.unquoteString(t.val)}
|
||||||
|
|
||||||
case t.typ == itemLeftBrace:
|
case t.typ == ItemLeftBrace:
|
||||||
// Metric selector without metric name.
|
// Metric selector without metric name.
|
||||||
p.backup()
|
p.backup()
|
||||||
return p.VectorSelector("")
|
return p.VectorSelector("")
|
||||||
|
|
||||||
case t.typ == itemIdentifier:
|
case t.typ == ItemIdentifier:
|
||||||
// Check for function call.
|
// Check for function call.
|
||||||
if p.peek().typ == itemLeftParen {
|
if p.peek().typ == ItemLeftParen {
|
||||||
return p.call(t.val)
|
return p.call(t.val)
|
||||||
}
|
}
|
||||||
fallthrough // Else metric selector.
|
fallthrough // Else metric selector.
|
||||||
|
|
||||||
case t.typ == itemMetricIdentifier:
|
case t.typ == ItemMetricIdentifier:
|
||||||
return p.VectorSelector(t.val)
|
return p.VectorSelector(t.val)
|
||||||
|
|
||||||
case t.typ.isAggregator():
|
case t.typ.isAggregator():
|
||||||
|
@ -623,10 +622,10 @@ func (p *parser) primaryExpr() Expr {
|
||||||
func (p *parser) labels() []string {
|
func (p *parser) labels() []string {
|
||||||
const ctx = "grouping opts"
|
const ctx = "grouping opts"
|
||||||
|
|
||||||
p.expect(itemLeftParen, ctx)
|
p.expect(ItemLeftParen, ctx)
|
||||||
|
|
||||||
labels := []string{}
|
labels := []string{}
|
||||||
if p.peek().typ != itemRightParen {
|
if p.peek().typ != ItemRightParen {
|
||||||
for {
|
for {
|
||||||
id := p.next()
|
id := p.next()
|
||||||
if !isLabel(id.val) {
|
if !isLabel(id.val) {
|
||||||
|
@ -634,13 +633,13 @@ func (p *parser) labels() []string {
|
||||||
}
|
}
|
||||||
labels = append(labels, id.val)
|
labels = append(labels, id.val)
|
||||||
|
|
||||||
if p.peek().typ != itemComma {
|
if p.peek().typ != ItemComma {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expect(itemRightParen, ctx)
|
p.expect(ItemRightParen, ctx)
|
||||||
|
|
||||||
return labels
|
return labels
|
||||||
}
|
}
|
||||||
|
@ -662,8 +661,8 @@ func (p *parser) aggrExpr() *AggregateExpr {
|
||||||
|
|
||||||
modifiersFirst := false
|
modifiersFirst := false
|
||||||
|
|
||||||
if t := p.peek().typ; t == itemBy || t == itemWithout {
|
if t := p.peek().typ; t == ItemBy || t == ItemWithout {
|
||||||
if t == itemWithout {
|
if t == ItemWithout {
|
||||||
without = true
|
without = true
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
|
@ -671,21 +670,21 @@ func (p *parser) aggrExpr() *AggregateExpr {
|
||||||
modifiersFirst = true
|
modifiersFirst = true
|
||||||
}
|
}
|
||||||
|
|
||||||
p.expect(itemLeftParen, ctx)
|
p.expect(ItemLeftParen, ctx)
|
||||||
var param Expr
|
var param Expr
|
||||||
if agop.typ.isAggregatorWithParam() {
|
if agop.typ.isAggregatorWithParam() {
|
||||||
param = p.expr()
|
param = p.expr()
|
||||||
p.expect(itemComma, ctx)
|
p.expect(ItemComma, ctx)
|
||||||
}
|
}
|
||||||
e := p.expr()
|
e := p.expr()
|
||||||
p.expect(itemRightParen, ctx)
|
p.expect(ItemRightParen, ctx)
|
||||||
|
|
||||||
if !modifiersFirst {
|
if !modifiersFirst {
|
||||||
if t := p.peek().typ; t == itemBy || t == itemWithout {
|
if t := p.peek().typ; t == ItemBy || t == ItemWithout {
|
||||||
if len(grouping) > 0 {
|
if len(grouping) > 0 {
|
||||||
p.errorf("aggregation must only contain one grouping clause")
|
p.errorf("aggregation must only contain one grouping clause")
|
||||||
}
|
}
|
||||||
if t == itemWithout {
|
if t == ItemWithout {
|
||||||
without = true
|
without = true
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
|
@ -714,9 +713,9 @@ func (p *parser) call(name string) *Call {
|
||||||
p.errorf("unknown function with name %q", name)
|
p.errorf("unknown function with name %q", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.expect(itemLeftParen, ctx)
|
p.expect(ItemLeftParen, ctx)
|
||||||
// Might be call without args.
|
// Might be call without args.
|
||||||
if p.peek().typ == itemRightParen {
|
if p.peek().typ == ItemRightParen {
|
||||||
p.next() // Consume.
|
p.next() // Consume.
|
||||||
return &Call{fn, nil}
|
return &Call{fn, nil}
|
||||||
}
|
}
|
||||||
|
@ -727,14 +726,14 @@ func (p *parser) call(name string) *Call {
|
||||||
args = append(args, e)
|
args = append(args, e)
|
||||||
|
|
||||||
// Terminate if no more arguments.
|
// Terminate if no more arguments.
|
||||||
if p.peek().typ != itemComma {
|
if p.peek().typ != ItemComma {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call must be closed.
|
// Call must be closed.
|
||||||
p.expect(itemRightParen, ctx)
|
p.expect(ItemRightParen, ctx)
|
||||||
|
|
||||||
return &Call{Func: fn, Args: args}
|
return &Call{Func: fn, Args: args}
|
||||||
}
|
}
|
||||||
|
@ -745,7 +744,7 @@ func (p *parser) call(name string) *Call {
|
||||||
//
|
//
|
||||||
func (p *parser) labelSet() labels.Labels {
|
func (p *parser) labelSet() labels.Labels {
|
||||||
set := []labels.Label{}
|
set := []labels.Label{}
|
||||||
for _, lm := range p.labelMatchers(itemEQL) {
|
for _, lm := range p.labelMatchers(ItemEQL) {
|
||||||
set = append(set, labels.Label{Name: lm.Name, Value: lm.Value})
|
set = append(set, labels.Label{Name: lm.Name, Value: lm.Value})
|
||||||
}
|
}
|
||||||
return labels.New(set...)
|
return labels.New(set...)
|
||||||
|
@ -760,16 +759,16 @@ func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
|
||||||
|
|
||||||
matchers := []*labels.Matcher{}
|
matchers := []*labels.Matcher{}
|
||||||
|
|
||||||
p.expect(itemLeftBrace, ctx)
|
p.expect(ItemLeftBrace, ctx)
|
||||||
|
|
||||||
// Check if no matchers are provided.
|
// Check if no matchers are provided.
|
||||||
if p.peek().typ == itemRightBrace {
|
if p.peek().typ == ItemRightBrace {
|
||||||
p.next()
|
p.next()
|
||||||
return matchers
|
return matchers
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
label := p.expect(itemIdentifier, ctx)
|
label := p.expect(ItemIdentifier, ctx)
|
||||||
|
|
||||||
op := p.next().typ
|
op := p.next().typ
|
||||||
if !op.isOperator() {
|
if !op.isOperator() {
|
||||||
|
@ -785,18 +784,18 @@ func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
|
||||||
p.errorf("operator must be one of %q, is %q", operators, op)
|
p.errorf("operator must be one of %q, is %q", operators, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
val := p.unquoteString(p.expect(itemString, ctx).val)
|
val := p.unquoteString(p.expect(ItemString, ctx).val)
|
||||||
|
|
||||||
// Map the item to the respective match type.
|
// Map the item to the respective match type.
|
||||||
var matchType labels.MatchType
|
var matchType labels.MatchType
|
||||||
switch op {
|
switch op {
|
||||||
case itemEQL:
|
case ItemEQL:
|
||||||
matchType = labels.MatchEqual
|
matchType = labels.MatchEqual
|
||||||
case itemNEQ:
|
case ItemNEQ:
|
||||||
matchType = labels.MatchNotEqual
|
matchType = labels.MatchNotEqual
|
||||||
case itemEQLRegex:
|
case ItemEQLRegex:
|
||||||
matchType = labels.MatchRegexp
|
matchType = labels.MatchRegexp
|
||||||
case itemNEQRegex:
|
case ItemNEQRegex:
|
||||||
matchType = labels.MatchNotRegexp
|
matchType = labels.MatchNotRegexp
|
||||||
default:
|
default:
|
||||||
p.errorf("item %q is not a metric match type", op)
|
p.errorf("item %q is not a metric match type", op)
|
||||||
|
@ -809,23 +808,23 @@ func (p *parser) labelMatchers(operators ...ItemType) []*labels.Matcher {
|
||||||
|
|
||||||
matchers = append(matchers, m)
|
matchers = append(matchers, m)
|
||||||
|
|
||||||
if p.peek().typ == itemIdentifier {
|
if p.peek().typ == ItemIdentifier {
|
||||||
p.errorf("missing comma before next identifier %q", p.peek().val)
|
p.errorf("missing comma before next identifier %q", p.peek().val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate list if last matcher.
|
// Terminate list if last matcher.
|
||||||
if p.peek().typ != itemComma {
|
if p.peek().typ != ItemComma {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
|
|
||||||
// Allow comma after each item in a multi-line listing.
|
// Allow comma after each item in a multi-line listing.
|
||||||
if p.peek().typ == itemRightBrace {
|
if p.peek().typ == ItemRightBrace {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.expect(itemRightBrace, ctx)
|
p.expect(ItemRightBrace, ctx)
|
||||||
|
|
||||||
return matchers
|
return matchers
|
||||||
}
|
}
|
||||||
|
@ -840,14 +839,14 @@ func (p *parser) metric() labels.Labels {
|
||||||
var m labels.Labels
|
var m labels.Labels
|
||||||
|
|
||||||
t := p.peek().typ
|
t := p.peek().typ
|
||||||
if t == itemIdentifier || t == itemMetricIdentifier {
|
if t == ItemIdentifier || t == ItemMetricIdentifier {
|
||||||
name = p.next().val
|
name = p.next().val
|
||||||
t = p.peek().typ
|
t = p.peek().typ
|
||||||
}
|
}
|
||||||
if t != itemLeftBrace && name == "" {
|
if t != ItemLeftBrace && name == "" {
|
||||||
p.errorf("missing metric name or metric selector")
|
p.errorf("missing metric name or metric selector")
|
||||||
}
|
}
|
||||||
if t == itemLeftBrace {
|
if t == ItemLeftBrace {
|
||||||
m = p.labelSet()
|
m = p.labelSet()
|
||||||
}
|
}
|
||||||
if name != "" {
|
if name != "" {
|
||||||
|
@ -865,7 +864,7 @@ func (p *parser) offset() time.Duration {
|
||||||
const ctx = "offset"
|
const ctx = "offset"
|
||||||
|
|
||||||
p.next()
|
p.next()
|
||||||
offi := p.expect(itemDuration, ctx)
|
offi := p.expect(ItemDuration, ctx)
|
||||||
|
|
||||||
offset, err := parseDuration(offi.val)
|
offset, err := parseDuration(offi.val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -883,8 +882,8 @@ func (p *parser) offset() time.Duration {
|
||||||
func (p *parser) VectorSelector(name string) *VectorSelector {
|
func (p *parser) VectorSelector(name string) *VectorSelector {
|
||||||
var matchers []*labels.Matcher
|
var matchers []*labels.Matcher
|
||||||
// Parse label matching if any.
|
// Parse label matching if any.
|
||||||
if t := p.peek(); t.typ == itemLeftBrace {
|
if t := p.peek(); t.typ == ItemLeftBrace {
|
||||||
matchers = p.labelMatchers(itemEQL, itemNEQ, itemEQLRegex, itemNEQRegex)
|
matchers = p.labelMatchers(ItemEQL, ItemNEQ, ItemEQLRegex, ItemNEQRegex)
|
||||||
}
|
}
|
||||||
// Metric name must not be set in the label matchers and before at the same time.
|
// Metric name must not be set in the label matchers and before at the same time.
|
||||||
if name != "" {
|
if name != "" {
|
||||||
|
@ -970,10 +969,10 @@ func (p *parser) checkType(node Node) (typ ValueType) {
|
||||||
p.errorf("aggregation operator expected in aggregation expression but got %q", n.Op)
|
p.errorf("aggregation operator expected in aggregation expression but got %q", n.Op)
|
||||||
}
|
}
|
||||||
p.expectType(n.Expr, ValueTypeVector, "aggregation expression")
|
p.expectType(n.Expr, ValueTypeVector, "aggregation expression")
|
||||||
if n.Op == itemTopK || n.Op == itemBottomK || n.Op == itemQuantile {
|
if n.Op == ItemTopK || n.Op == ItemBottomK || n.Op == ItemQuantile {
|
||||||
p.expectType(n.Param, ValueTypeScalar, "aggregation parameter")
|
p.expectType(n.Param, ValueTypeScalar, "aggregation parameter")
|
||||||
}
|
}
|
||||||
if n.Op == itemCountValues {
|
if n.Op == ItemCountValues {
|
||||||
p.expectType(n.Param, ValueTypeString, "aggregation parameter")
|
p.expectType(n.Param, ValueTypeString, "aggregation parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1035,7 +1034,7 @@ func (p *parser) checkType(node Node) (typ ValueType) {
|
||||||
p.checkType(n.Expr)
|
p.checkType(n.Expr)
|
||||||
|
|
||||||
case *UnaryExpr:
|
case *UnaryExpr:
|
||||||
if n.Op != itemADD && n.Op != itemSUB {
|
if n.Op != ItemADD && n.Op != ItemSUB {
|
||||||
p.errorf("only + and - operators allowed for unary expressions")
|
p.errorf("only + and - operators allowed for unary expressions")
|
||||||
}
|
}
|
||||||
if t := p.checkType(n.Expr); t != ValueTypeScalar && t != ValueTypeVector {
|
if t := p.checkType(n.Expr); t != ValueTypeScalar && t != ValueTypeVector {
|
||||||
|
|
|
@ -71,77 +71,77 @@ var testExpr = []struct {
|
||||||
expected: &NumberLiteral{-493},
|
expected: &NumberLiteral{-493},
|
||||||
}, {
|
}, {
|
||||||
input: "1 + 1",
|
input: "1 + 1",
|
||||||
expected: &BinaryExpr{itemADD, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
expected: &BinaryExpr{ItemADD, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
||||||
}, {
|
}, {
|
||||||
input: "1 - 1",
|
input: "1 - 1",
|
||||||
expected: &BinaryExpr{itemSUB, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
expected: &BinaryExpr{ItemSUB, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
||||||
}, {
|
}, {
|
||||||
input: "1 * 1",
|
input: "1 * 1",
|
||||||
expected: &BinaryExpr{itemMUL, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
expected: &BinaryExpr{ItemMUL, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
||||||
}, {
|
}, {
|
||||||
input: "1 % 1",
|
input: "1 % 1",
|
||||||
expected: &BinaryExpr{itemMOD, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
expected: &BinaryExpr{ItemMOD, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
||||||
}, {
|
}, {
|
||||||
input: "1 / 1",
|
input: "1 / 1",
|
||||||
expected: &BinaryExpr{itemDIV, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
expected: &BinaryExpr{ItemDIV, &NumberLiteral{1}, &NumberLiteral{1}, nil, false},
|
||||||
}, {
|
}, {
|
||||||
input: "1 == bool 1",
|
input: "1 == bool 1",
|
||||||
expected: &BinaryExpr{itemEQL, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
expected: &BinaryExpr{ItemEQL, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
||||||
}, {
|
}, {
|
||||||
input: "1 != bool 1",
|
input: "1 != bool 1",
|
||||||
expected: &BinaryExpr{itemNEQ, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
expected: &BinaryExpr{ItemNEQ, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
||||||
}, {
|
}, {
|
||||||
input: "1 > bool 1",
|
input: "1 > bool 1",
|
||||||
expected: &BinaryExpr{itemGTR, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
expected: &BinaryExpr{ItemGTR, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
||||||
}, {
|
}, {
|
||||||
input: "1 >= bool 1",
|
input: "1 >= bool 1",
|
||||||
expected: &BinaryExpr{itemGTE, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
expected: &BinaryExpr{ItemGTE, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
||||||
}, {
|
}, {
|
||||||
input: "1 < bool 1",
|
input: "1 < bool 1",
|
||||||
expected: &BinaryExpr{itemLSS, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
expected: &BinaryExpr{ItemLSS, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
||||||
}, {
|
}, {
|
||||||
input: "1 <= bool 1",
|
input: "1 <= bool 1",
|
||||||
expected: &BinaryExpr{itemLTE, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
expected: &BinaryExpr{ItemLTE, &NumberLiteral{1}, &NumberLiteral{1}, nil, true},
|
||||||
}, {
|
}, {
|
||||||
input: "+1 + -2 * 1",
|
input: "+1 + -2 * 1",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemADD,
|
Op: ItemADD,
|
||||||
LHS: &NumberLiteral{1},
|
LHS: &NumberLiteral{1},
|
||||||
RHS: &BinaryExpr{
|
RHS: &BinaryExpr{
|
||||||
Op: itemMUL, LHS: &NumberLiteral{-2}, RHS: &NumberLiteral{1},
|
Op: ItemMUL, LHS: &NumberLiteral{-2}, RHS: &NumberLiteral{1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: "1 + 2/(3*1)",
|
input: "1 + 2/(3*1)",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemADD,
|
Op: ItemADD,
|
||||||
LHS: &NumberLiteral{1},
|
LHS: &NumberLiteral{1},
|
||||||
RHS: &BinaryExpr{
|
RHS: &BinaryExpr{
|
||||||
Op: itemDIV,
|
Op: ItemDIV,
|
||||||
LHS: &NumberLiteral{2},
|
LHS: &NumberLiteral{2},
|
||||||
RHS: &ParenExpr{&BinaryExpr{
|
RHS: &ParenExpr{&BinaryExpr{
|
||||||
Op: itemMUL, LHS: &NumberLiteral{3}, RHS: &NumberLiteral{1},
|
Op: ItemMUL, LHS: &NumberLiteral{3}, RHS: &NumberLiteral{1},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: "1 < bool 2 - 1 * 2",
|
input: "1 < bool 2 - 1 * 2",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLSS,
|
Op: ItemLSS,
|
||||||
ReturnBool: true,
|
ReturnBool: true,
|
||||||
LHS: &NumberLiteral{1},
|
LHS: &NumberLiteral{1},
|
||||||
RHS: &BinaryExpr{
|
RHS: &BinaryExpr{
|
||||||
Op: itemSUB,
|
Op: ItemSUB,
|
||||||
LHS: &NumberLiteral{2},
|
LHS: &NumberLiteral{2},
|
||||||
RHS: &BinaryExpr{
|
RHS: &BinaryExpr{
|
||||||
Op: itemMUL, LHS: &NumberLiteral{1}, RHS: &NumberLiteral{2},
|
Op: ItemMUL, LHS: &NumberLiteral{1}, RHS: &NumberLiteral{2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
input: "-some_metric",
|
input: "-some_metric",
|
||||||
expected: &UnaryExpr{
|
expected: &UnaryExpr{
|
||||||
Op: itemSUB,
|
Op: ItemSUB,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -152,7 +152,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "+some_metric",
|
input: "+some_metric",
|
||||||
expected: &UnaryExpr{
|
expected: &UnaryExpr{
|
||||||
Op: itemADD,
|
Op: ItemADD,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -261,7 +261,7 @@ var testExpr = []struct {
|
||||||
{
|
{
|
||||||
input: "foo * bar",
|
input: "foo * bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemMUL,
|
Op: ItemMUL,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -279,7 +279,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo == 1",
|
input: "foo == 1",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemEQL,
|
Op: ItemEQL,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -291,7 +291,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo == bool 1",
|
input: "foo == bool 1",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemEQL,
|
Op: ItemEQL,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -304,7 +304,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "2.5 / bar",
|
input: "2.5 / bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemDIV,
|
Op: ItemDIV,
|
||||||
LHS: &NumberLiteral{2.5},
|
LHS: &NumberLiteral{2.5},
|
||||||
RHS: &VectorSelector{
|
RHS: &VectorSelector{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
|
@ -316,7 +316,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo and bar",
|
input: "foo and bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLAND,
|
Op: ItemLAND,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -334,7 +334,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo or bar",
|
input: "foo or bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLOR,
|
Op: ItemLOR,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -352,7 +352,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo unless bar",
|
input: "foo unless bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLUnless,
|
Op: ItemLUnless,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -371,9 +371,9 @@ var testExpr = []struct {
|
||||||
// Test and/or precedence and reassigning of operands.
|
// Test and/or precedence and reassigning of operands.
|
||||||
input: "foo + bar or bla and blub",
|
input: "foo + bar or bla and blub",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLOR,
|
Op: ItemLOR,
|
||||||
LHS: &BinaryExpr{
|
LHS: &BinaryExpr{
|
||||||
Op: itemADD,
|
Op: ItemADD,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -389,7 +389,7 @@ var testExpr = []struct {
|
||||||
VectorMatching: &VectorMatching{Card: CardOneToOne},
|
VectorMatching: &VectorMatching{Card: CardOneToOne},
|
||||||
},
|
},
|
||||||
RHS: &BinaryExpr{
|
RHS: &BinaryExpr{
|
||||||
Op: itemLAND,
|
Op: ItemLAND,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "bla",
|
Name: "bla",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -410,11 +410,11 @@ var testExpr = []struct {
|
||||||
// Test and/or/unless precedence.
|
// Test and/or/unless precedence.
|
||||||
input: "foo and bar unless baz or qux",
|
input: "foo and bar unless baz or qux",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLOR,
|
Op: ItemLOR,
|
||||||
LHS: &BinaryExpr{
|
LHS: &BinaryExpr{
|
||||||
Op: itemLUnless,
|
Op: ItemLUnless,
|
||||||
LHS: &BinaryExpr{
|
LHS: &BinaryExpr{
|
||||||
Op: itemLAND,
|
Op: ItemLAND,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -449,7 +449,7 @@ var testExpr = []struct {
|
||||||
// Test precedence and reassigning of operands.
|
// Test precedence and reassigning of operands.
|
||||||
input: "bar + on(foo) bla / on(baz, buz) group_right(test) blub",
|
input: "bar + on(foo) bla / on(baz, buz) group_right(test) blub",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemADD,
|
Op: ItemADD,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -457,7 +457,7 @@ var testExpr = []struct {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RHS: &BinaryExpr{
|
RHS: &BinaryExpr{
|
||||||
Op: itemDIV,
|
Op: ItemDIV,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "bla",
|
Name: "bla",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -486,7 +486,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo * on(test,blub) bar",
|
input: "foo * on(test,blub) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemMUL,
|
Op: ItemMUL,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -508,7 +508,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo * on(test,blub) group_left bar",
|
input: "foo * on(test,blub) group_left bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemMUL,
|
Op: ItemMUL,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -530,7 +530,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo and on(test,blub) bar",
|
input: "foo and on(test,blub) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLAND,
|
Op: ItemLAND,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -552,7 +552,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo and on() bar",
|
input: "foo and on() bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLAND,
|
Op: ItemLAND,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -574,7 +574,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo and ignoring(test,blub) bar",
|
input: "foo and ignoring(test,blub) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLAND,
|
Op: ItemLAND,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -595,7 +595,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo and ignoring() bar",
|
input: "foo and ignoring() bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLAND,
|
Op: ItemLAND,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -616,7 +616,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo unless on(bar) baz",
|
input: "foo unless on(bar) baz",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemLUnless,
|
Op: ItemLUnless,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -638,7 +638,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo / on(test,blub) group_left(bar) bar",
|
input: "foo / on(test,blub) group_left(bar) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemDIV,
|
Op: ItemDIV,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -661,7 +661,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo / ignoring(test,blub) group_left(blub) bar",
|
input: "foo / ignoring(test,blub) group_left(blub) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemDIV,
|
Op: ItemDIV,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -683,7 +683,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo / ignoring(test,blub) group_left(bar) bar",
|
input: "foo / ignoring(test,blub) group_left(bar) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemDIV,
|
Op: ItemDIV,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -705,7 +705,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo - on(test,blub) group_right(bar,foo) bar",
|
input: "foo - on(test,blub) group_right(bar,foo) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemSUB,
|
Op: ItemSUB,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -728,7 +728,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "foo - ignoring(test,blub) group_right(bar,foo) bar",
|
input: "foo - ignoring(test,blub) group_right(bar,foo) bar",
|
||||||
expected: &BinaryExpr{
|
expected: &BinaryExpr{
|
||||||
Op: itemSUB,
|
Op: ItemSUB,
|
||||||
LHS: &VectorSelector{
|
LHS: &VectorSelector{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1057,7 +1057,7 @@ var testExpr = []struct {
|
||||||
{
|
{
|
||||||
input: "sum by (foo)(some_metric)",
|
input: "sum by (foo)(some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemSum,
|
Op: ItemSum,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1069,7 +1069,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "avg by (foo)(some_metric)",
|
input: "avg by (foo)(some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemAvg,
|
Op: ItemAvg,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1081,7 +1081,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "max by (foo)(some_metric)",
|
input: "max by (foo)(some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemMax,
|
Op: ItemMax,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1093,7 +1093,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "sum without (foo) (some_metric)",
|
input: "sum without (foo) (some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemSum,
|
Op: ItemSum,
|
||||||
Without: true,
|
Without: true,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
|
@ -1106,7 +1106,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "sum (some_metric) without (foo)",
|
input: "sum (some_metric) without (foo)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemSum,
|
Op: ItemSum,
|
||||||
Without: true,
|
Without: true,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
|
@ -1119,7 +1119,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "stddev(some_metric)",
|
input: "stddev(some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemStddev,
|
Op: ItemStddev,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1130,7 +1130,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "stdvar by (foo)(some_metric)",
|
input: "stdvar by (foo)(some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemStdvar,
|
Op: ItemStdvar,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1142,7 +1142,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "sum by ()(some_metric)",
|
input: "sum by ()(some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemSum,
|
Op: ItemSum,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1154,7 +1154,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "topk(5, some_metric)",
|
input: "topk(5, some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemTopK,
|
Op: ItemTopK,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1166,7 +1166,7 @@ var testExpr = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: "count_values(\"value\", some_metric)",
|
input: "count_values(\"value\", some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemCountValues,
|
Op: ItemCountValues,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
LabelMatchers: []*labels.Matcher{
|
LabelMatchers: []*labels.Matcher{
|
||||||
|
@ -1179,7 +1179,7 @@ var testExpr = []struct {
|
||||||
// Test usage of keywords as label names.
|
// Test usage of keywords as label names.
|
||||||
input: "sum without(and, by, avg, count, alert, annotations)(some_metric)",
|
input: "sum without(and, by, avg, count, alert, annotations)(some_metric)",
|
||||||
expected: &AggregateExpr{
|
expected: &AggregateExpr{
|
||||||
Op: itemSum,
|
Op: ItemSum,
|
||||||
Without: true,
|
Without: true,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
|
@ -1494,7 +1494,7 @@ var testExpr = []struct {
|
||||||
input: "sum without(and, by, avg, count, alert, annotations)(some_metric) [30m:10s]",
|
input: "sum without(and, by, avg, count, alert, annotations)(some_metric) [30m:10s]",
|
||||||
expected: &SubqueryExpr{
|
expected: &SubqueryExpr{
|
||||||
Expr: &AggregateExpr{
|
Expr: &AggregateExpr{
|
||||||
Op: itemSum,
|
Op: ItemSum,
|
||||||
Without: true,
|
Without: true,
|
||||||
Expr: &VectorSelector{
|
Expr: &VectorSelector{
|
||||||
Name: "some_metric",
|
Name: "some_metric",
|
||||||
|
@ -1525,7 +1525,7 @@ var testExpr = []struct {
|
||||||
expected: &SubqueryExpr{
|
expected: &SubqueryExpr{
|
||||||
Expr: &ParenExpr{
|
Expr: &ParenExpr{
|
||||||
Expr: &BinaryExpr{
|
Expr: &BinaryExpr{
|
||||||
Op: itemADD,
|
Op: ItemADD,
|
||||||
VectorMatching: &VectorMatching{
|
VectorMatching: &VectorMatching{
|
||||||
Card: CardOneToOne,
|
Card: CardOneToOne,
|
||||||
},
|
},
|
||||||
|
@ -1551,7 +1551,7 @@ var testExpr = []struct {
|
||||||
expected: &SubqueryExpr{
|
expected: &SubqueryExpr{
|
||||||
Expr: &ParenExpr{
|
Expr: &ParenExpr{
|
||||||
Expr: &BinaryExpr{
|
Expr: &BinaryExpr{
|
||||||
Op: itemADD,
|
Op: ItemADD,
|
||||||
VectorMatching: &VectorMatching{
|
VectorMatching: &VectorMatching{
|
||||||
Card: CardOneToOne,
|
Card: CardOneToOne,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue