2026-01-05 07:46:21 -05:00
|
|
|
// Copyright The Prometheus Authors
|
2015-03-30 12:12:51 -04:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
2020-02-03 11:23:44 -05:00
|
|
|
package parser
|
2015-03-30 12:12:51 -04:00
|
|
|
|
|
|
|
|
import (
|
2024-12-03 12:33:10 -05:00
|
|
|
"bytes"
|
2015-03-30 12:12:51 -04:00
|
|
|
"fmt"
|
|
|
|
|
"sort"
|
2024-12-03 12:33:10 -05:00
|
|
|
"strconv"
|
2015-03-30 12:12:51 -04:00
|
|
|
"strings"
|
2015-11-15 04:26:38 -05:00
|
|
|
"time"
|
2015-03-30 12:12:51 -04:00
|
|
|
|
2015-08-20 11:18:46 -04:00
|
|
|
"github.com/prometheus/common/model"
|
2020-10-22 05:00:08 -04:00
|
|
|
|
2021-11-08 09:23:17 -05:00
|
|
|
"github.com/prometheus/prometheus/model/labels"
|
2015-03-30 12:12:51 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Tree returns a string of the tree structure of the given node.
|
|
|
|
|
func Tree(node Node) string {
|
|
|
|
|
return tree(node, "")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func tree(node Node, level string) string {
|
2015-04-29 10:35:18 -04:00
|
|
|
if node == nil {
|
|
|
|
|
return fmt.Sprintf("%s |---- %T\n", level, node)
|
|
|
|
|
}
|
2015-03-30 12:12:51 -04:00
|
|
|
typs := strings.Split(fmt.Sprintf("%T", node), ".")[1]
|
|
|
|
|
|
2025-12-05 03:29:10 -05:00
|
|
|
var t strings.Builder
|
2026-02-17 16:35:59 -05:00
|
|
|
fmt.Fprintf(&t, "%s |---- %s :: %s\n", level, typs, node)
|
2015-03-30 12:12:51 -04:00
|
|
|
|
|
|
|
|
level += " · · ·"
|
|
|
|
|
|
2025-05-11 06:49:15 -04:00
|
|
|
for e := range ChildrenIter(node) {
|
2025-12-05 03:29:10 -05:00
|
|
|
t.WriteString(tree(e, level))
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
2019-11-25 06:41:59 -05:00
|
|
|
|
2025-12-05 03:29:10 -05:00
|
|
|
return t.String()
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *EvalStmt) String() string {
|
|
|
|
|
return "EVAL " + node.Expr.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (es Expressions) String() (s string) {
|
2025-05-12 10:17:19 -04:00
|
|
|
switch len(es) {
|
|
|
|
|
case 0:
|
2015-03-30 12:12:51 -04:00
|
|
|
return ""
|
2025-05-12 10:17:19 -04:00
|
|
|
case 1:
|
|
|
|
|
return es[0].String()
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
b := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
|
|
|
b.WriteString(es[0].String())
|
|
|
|
|
for _, e := range es[1:] {
|
|
|
|
|
b.WriteString(", ")
|
|
|
|
|
b.WriteString(e.String())
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
return b.String()
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *AggregateExpr) String() string {
|
2025-05-12 10:17:19 -04:00
|
|
|
b := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
|
|
|
node.writeAggOpStr(b)
|
|
|
|
|
b.WriteString("(")
|
2020-02-03 12:48:27 -05:00
|
|
|
if node.Op.IsAggregatorWithParam() {
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(node.Param.String())
|
|
|
|
|
b.WriteString(", ")
|
2018-01-22 05:14:59 -05:00
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(node.Expr.String())
|
|
|
|
|
b.WriteString(")")
|
2018-01-22 05:14:59 -05:00
|
|
|
|
2025-05-12 10:17:19 -04:00
|
|
|
return b.String()
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *AggregateExpr) ShortString() string {
|
2025-05-12 10:17:19 -04:00
|
|
|
b := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
|
|
|
node.writeAggOpStr(b)
|
|
|
|
|
return b.String()
|
2024-09-02 16:17:45 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-12 10:17:19 -04:00
|
|
|
func (node *AggregateExpr) writeAggOpStr(b *bytes.Buffer) {
|
|
|
|
|
b.WriteString(node.Op.String())
|
2022-07-07 08:43:36 -04:00
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case node.Without:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(" without (")
|
|
|
|
|
writeLabels(b, node.Grouping)
|
|
|
|
|
b.WriteString(") ")
|
2022-07-07 08:43:36 -04:00
|
|
|
case len(node.Grouping) > 0:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(" by (")
|
|
|
|
|
writeLabels(b, node.Grouping)
|
|
|
|
|
b.WriteString(") ")
|
2022-07-07 08:43:36 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 10:17:19 -04:00
|
|
|
func writeLabels(b *bytes.Buffer, ss []string) {
|
2024-08-01 10:07:08 -04:00
|
|
|
for i, s := range ss {
|
2024-12-03 12:33:10 -05:00
|
|
|
if i > 0 {
|
|
|
|
|
b.WriteString(", ")
|
|
|
|
|
}
|
2025-12-14 15:18:06 -05:00
|
|
|
if !model.LegacyValidation.IsValidLabelName(s) {
|
2024-12-03 12:33:10 -05:00
|
|
|
b.Write(strconv.AppendQuote(b.AvailableBuffer(), s))
|
|
|
|
|
} else {
|
|
|
|
|
b.WriteString(s)
|
2024-08-01 10:07:08 -04:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// writeStringsJoin is like strings.Join but appending to a bytes.Buffer.
|
|
|
|
|
func writeStringsJoin(b *bytes.Buffer, elems []string, sep string) {
|
|
|
|
|
if len(elems) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
b.WriteString(elems[0])
|
|
|
|
|
for _, s := range elems[1:] {
|
|
|
|
|
b.WriteString(sep)
|
|
|
|
|
b.WriteString(s)
|
|
|
|
|
}
|
2024-08-01 10:07:08 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *BinaryExpr) returnBool() string {
|
2015-09-09 19:37:05 -04:00
|
|
|
if node.ReturnBool {
|
2024-09-02 16:17:45 -04:00
|
|
|
return " bool"
|
2015-09-09 19:37:05 -04:00
|
|
|
}
|
2024-09-02 16:17:45 -04:00
|
|
|
return ""
|
|
|
|
|
}
|
2015-09-09 19:37:05 -04:00
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *BinaryExpr) String() string {
|
2022-07-07 08:43:36 -04:00
|
|
|
matching := node.getMatchingStr()
|
2025-05-12 10:08:03 -04:00
|
|
|
return node.LHS.String() + " " + node.Op.String() + node.returnBool() + matching + " " + node.RHS.String()
|
2024-09-02 16:17:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *BinaryExpr) ShortString() string {
|
2025-05-12 10:08:03 -04:00
|
|
|
return node.Op.String() + node.returnBool() + node.getMatchingStr()
|
2022-07-07 08:43:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *BinaryExpr) getMatchingStr() string {
|
2015-03-30 12:12:51 -04:00
|
|
|
matching := ""
|
2025-12-15 07:38:12 -05:00
|
|
|
var b bytes.Buffer
|
2015-03-30 12:12:51 -04:00
|
|
|
vm := node.VectorMatching
|
2025-12-03 08:14:35 -05:00
|
|
|
if vm != nil {
|
|
|
|
|
if len(vm.MatchingLabels) > 0 || vm.On || vm.Card == CardManyToOne || vm.Card == CardOneToMany {
|
|
|
|
|
vmTag := "ignoring"
|
|
|
|
|
if vm.On {
|
|
|
|
|
vmTag = "on"
|
|
|
|
|
}
|
2025-12-15 08:39:15 -05:00
|
|
|
b.WriteString(" " + vmTag + " (")
|
2025-12-15 07:38:12 -05:00
|
|
|
writeLabels(&b, vm.MatchingLabels)
|
|
|
|
|
b.WriteString(")")
|
|
|
|
|
matching = b.String()
|
2016-04-21 06:45:06 -04:00
|
|
|
}
|
2022-07-07 08:43:36 -04:00
|
|
|
|
2016-05-28 13:45:35 -04:00
|
|
|
if vm.Card == CardManyToOne || vm.Card == CardOneToMany {
|
2022-07-07 08:43:36 -04:00
|
|
|
vmCard := "right"
|
2016-05-28 13:45:35 -04:00
|
|
|
if vm.Card == CardManyToOne {
|
2022-07-07 08:43:36 -04:00
|
|
|
vmCard = "left"
|
2016-05-28 13:45:35 -04:00
|
|
|
}
|
2025-12-15 07:38:12 -05:00
|
|
|
b.Reset()
|
2025-12-15 08:39:15 -05:00
|
|
|
b.WriteString(" group_" + vmCard + " (")
|
2025-12-15 07:38:12 -05:00
|
|
|
writeLabels(&b, vm.Include)
|
|
|
|
|
b.WriteString(")")
|
|
|
|
|
matching += b.String()
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
2025-12-03 12:46:35 -05:00
|
|
|
|
|
|
|
|
if vm.FillValues.LHS != nil || vm.FillValues.RHS != nil {
|
|
|
|
|
if vm.FillValues.LHS == vm.FillValues.RHS {
|
|
|
|
|
matching += fmt.Sprintf(" fill (%v)", *vm.FillValues.LHS)
|
|
|
|
|
} else {
|
|
|
|
|
if vm.FillValues.LHS != nil {
|
|
|
|
|
matching += fmt.Sprintf(" fill_left (%v)", *vm.FillValues.LHS)
|
|
|
|
|
}
|
|
|
|
|
if vm.FillValues.RHS != nil {
|
|
|
|
|
matching += fmt.Sprintf(" fill_right (%v)", *vm.FillValues.RHS)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
2022-07-07 08:43:36 -04:00
|
|
|
return matching
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
2025-03-27 09:39:23 -04:00
|
|
|
func (node *DurationExpr) String() string {
|
2025-05-12 10:17:19 -04:00
|
|
|
b := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
|
|
|
node.writeTo(b)
|
|
|
|
|
return b.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *DurationExpr) writeTo(b *bytes.Buffer) {
|
|
|
|
|
if node.Wrapped {
|
|
|
|
|
b.WriteByte('(')
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-25 11:39:27 -04:00
|
|
|
switch {
|
|
|
|
|
case node.Op == STEP:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString("step()")
|
2025-12-10 10:16:08 -05:00
|
|
|
case node.Op == RANGE:
|
|
|
|
|
b.WriteString("range()")
|
2025-06-25 11:39:27 -04:00
|
|
|
case node.Op == MIN:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString("min(")
|
|
|
|
|
b.WriteString(node.LHS.String())
|
|
|
|
|
b.WriteString(", ")
|
|
|
|
|
b.WriteString(node.RHS.String())
|
|
|
|
|
b.WriteByte(')')
|
2025-06-25 11:39:27 -04:00
|
|
|
case node.Op == MAX:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString("max(")
|
|
|
|
|
b.WriteString(node.LHS.String())
|
|
|
|
|
b.WriteString(", ")
|
|
|
|
|
b.WriteString(node.RHS.String())
|
|
|
|
|
b.WriteByte(')')
|
2025-06-25 11:39:27 -04:00
|
|
|
case node.LHS == nil:
|
|
|
|
|
// This is a unary duration expression.
|
2025-07-01 05:57:31 -04:00
|
|
|
switch node.Op {
|
|
|
|
|
case SUB:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(node.Op.String())
|
|
|
|
|
b.WriteString(node.RHS.String())
|
2025-07-01 05:57:31 -04:00
|
|
|
case ADD:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(node.RHS.String())
|
2025-07-01 05:57:31 -04:00
|
|
|
default:
|
|
|
|
|
// This should never happen.
|
|
|
|
|
panic(fmt.Sprintf("unexpected unary duration expression: %s", node.Op))
|
|
|
|
|
}
|
2025-06-25 11:39:27 -04:00
|
|
|
default:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(node.LHS.String())
|
|
|
|
|
b.WriteByte(' ')
|
|
|
|
|
b.WriteString(node.Op.String())
|
|
|
|
|
b.WriteByte(' ')
|
|
|
|
|
b.WriteString(node.RHS.String())
|
2025-03-27 09:39:23 -04:00
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
|
2025-03-27 09:39:23 -04:00
|
|
|
if node.Wrapped {
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteByte(')')
|
2025-03-27 09:39:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *DurationExpr) ShortString() string {
|
|
|
|
|
return node.Op.String()
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-30 12:12:51 -04:00
|
|
|
func (node *Call) String() string {
|
2025-05-12 10:08:03 -04:00
|
|
|
return node.Func.Name + "(" + node.Args.String() + ")"
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *Call) ShortString() string {
|
|
|
|
|
return node.Func.Name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *MatrixSelector) atOffset() (string, string) {
|
|
|
|
|
vecSelector := node.VectorSelector.(*VectorSelector)
|
2015-11-15 04:26:38 -05:00
|
|
|
offset := ""
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
switch {
|
2025-03-27 09:39:23 -04:00
|
|
|
case vecSelector.OriginalOffsetExpr != nil:
|
|
|
|
|
offset = fmt.Sprintf(" offset %s", vecSelector.OriginalOffsetExpr)
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case vecSelector.OriginalOffset > time.Duration(0):
|
2021-01-20 05:57:39 -05:00
|
|
|
offset = fmt.Sprintf(" offset %s", model.Duration(vecSelector.OriginalOffset))
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case vecSelector.OriginalOffset < time.Duration(0):
|
2021-02-23 21:16:28 -05:00
|
|
|
offset = fmt.Sprintf(" offset -%s", model.Duration(-vecSelector.OriginalOffset))
|
2015-11-15 04:26:38 -05:00
|
|
|
}
|
2021-01-20 05:57:39 -05:00
|
|
|
at := ""
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
switch {
|
|
|
|
|
case vecSelector.Timestamp != nil:
|
2021-01-20 05:57:39 -05:00
|
|
|
at = fmt.Sprintf(" @ %.3f", float64(*vecSelector.Timestamp)/1000.0)
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case vecSelector.StartOrEnd == START:
|
2021-02-09 11:03:16 -05:00
|
|
|
at = " @ start()"
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case vecSelector.StartOrEnd == END:
|
2021-02-09 11:03:16 -05:00
|
|
|
at = " @ end()"
|
2021-01-20 05:57:39 -05:00
|
|
|
}
|
2024-09-02 16:17:45 -04:00
|
|
|
return at, offset
|
|
|
|
|
}
|
2021-01-20 05:57:39 -05:00
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *MatrixSelector) String() string {
|
|
|
|
|
at, offset := node.atOffset()
|
2025-10-17 06:17:32 -04:00
|
|
|
// Copy the Vector selector so we can modify it to not print @, offset, and other modifiers twice.
|
2024-09-02 16:17:45 -04:00
|
|
|
vecSelector := *node.VectorSelector.(*VectorSelector)
|
2025-10-17 06:17:32 -04:00
|
|
|
anchored, smoothed := vecSelector.Anchored, vecSelector.Smoothed
|
2021-01-20 05:57:39 -05:00
|
|
|
vecSelector.OriginalOffset = 0
|
2025-03-27 09:39:23 -04:00
|
|
|
vecSelector.OriginalOffsetExpr = nil
|
2021-01-20 05:57:39 -05:00
|
|
|
vecSelector.Timestamp = nil
|
2021-02-09 11:03:16 -05:00
|
|
|
vecSelector.StartOrEnd = 0
|
2025-10-17 06:17:32 -04:00
|
|
|
vecSelector.Anchored = false
|
|
|
|
|
vecSelector.Smoothed = false
|
2021-01-20 05:57:39 -05:00
|
|
|
|
2025-09-25 05:34:59 -04:00
|
|
|
extendedAttribute := ""
|
|
|
|
|
switch {
|
2025-10-17 06:17:32 -04:00
|
|
|
case anchored:
|
2025-09-25 05:34:59 -04:00
|
|
|
extendedAttribute = " anchored"
|
2025-10-17 06:17:32 -04:00
|
|
|
case smoothed:
|
2025-09-25 05:34:59 -04:00
|
|
|
extendedAttribute = " smoothed"
|
|
|
|
|
}
|
2025-03-27 09:39:23 -04:00
|
|
|
rangeStr := model.Duration(node.Range).String()
|
|
|
|
|
if node.RangeExpr != nil {
|
|
|
|
|
rangeStr = node.RangeExpr.String()
|
|
|
|
|
}
|
2025-09-25 05:34:59 -04:00
|
|
|
str := fmt.Sprintf("%s[%s]%s%s%s", vecSelector.String(), rangeStr, extendedAttribute, at, offset)
|
2020-01-10 09:25:41 -05:00
|
|
|
|
2021-01-20 05:57:39 -05:00
|
|
|
return str
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *MatrixSelector) ShortString() string {
|
|
|
|
|
at, offset := node.atOffset()
|
2025-03-27 09:39:23 -04:00
|
|
|
rangeStr := model.Duration(node.Range).String()
|
|
|
|
|
if node.RangeExpr != nil {
|
|
|
|
|
rangeStr = node.RangeExpr.String()
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("[%s]%s%s", rangeStr, at, offset)
|
2024-09-02 16:17:45 -04:00
|
|
|
}
|
|
|
|
|
|
2018-12-22 08:47:13 -05:00
|
|
|
func (node *SubqueryExpr) String() string {
|
2022-07-07 08:43:36 -04:00
|
|
|
return fmt.Sprintf("%s%s", node.Expr.String(), node.getSubqueryTimeSuffix())
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *SubqueryExpr) ShortString() string {
|
|
|
|
|
return node.getSubqueryTimeSuffix()
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-07 08:43:36 -04:00
|
|
|
// getSubqueryTimeSuffix returns the '[<range>:<step>] @ <timestamp> offset <offset>' suffix of the subquery.
|
|
|
|
|
func (node *SubqueryExpr) getSubqueryTimeSuffix() string {
|
2018-12-22 08:47:13 -05:00
|
|
|
step := ""
|
|
|
|
|
if node.Step != 0 {
|
2019-01-04 08:47:38 -05:00
|
|
|
step = model.Duration(node.Step).String()
|
2025-03-27 09:39:23 -04:00
|
|
|
} else if node.StepExpr != nil {
|
|
|
|
|
step = node.StepExpr.String()
|
2018-12-22 08:47:13 -05:00
|
|
|
}
|
2019-11-26 01:45:51 -05:00
|
|
|
offset := ""
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
switch {
|
2025-03-27 09:39:23 -04:00
|
|
|
case node.OriginalOffsetExpr != nil:
|
|
|
|
|
offset = fmt.Sprintf(" offset %s", node.OriginalOffsetExpr)
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case node.OriginalOffset > time.Duration(0):
|
2021-01-20 05:57:39 -05:00
|
|
|
offset = fmt.Sprintf(" offset %s", model.Duration(node.OriginalOffset))
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case node.OriginalOffset < time.Duration(0):
|
2021-02-23 21:16:28 -05:00
|
|
|
offset = fmt.Sprintf(" offset -%s", model.Duration(-node.OriginalOffset))
|
2019-11-26 01:45:51 -05:00
|
|
|
}
|
2021-01-20 05:57:39 -05:00
|
|
|
at := ""
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
switch {
|
|
|
|
|
case node.Timestamp != nil:
|
2021-01-20 05:57:39 -05:00
|
|
|
at = fmt.Sprintf(" @ %.3f", float64(*node.Timestamp)/1000.0)
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case node.StartOrEnd == START:
|
2021-02-09 11:03:16 -05:00
|
|
|
at = " @ start()"
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case node.StartOrEnd == END:
|
2021-02-09 11:03:16 -05:00
|
|
|
at = " @ end()"
|
2021-01-20 05:57:39 -05:00
|
|
|
}
|
2025-03-27 09:39:23 -04:00
|
|
|
rangeStr := model.Duration(node.Range).String()
|
|
|
|
|
if node.RangeExpr != nil {
|
|
|
|
|
rangeStr = node.RangeExpr.String()
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("[%s:%s]%s%s", rangeStr, step, at, offset)
|
2018-12-22 08:47:13 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-30 12:12:51 -04:00
|
|
|
func (node *NumberLiteral) String() string {
|
2025-03-27 09:39:23 -04:00
|
|
|
if node.Duration {
|
|
|
|
|
if node.Val < 0 {
|
|
|
|
|
return fmt.Sprintf("-%s", model.Duration(-node.Val*1e9).String())
|
|
|
|
|
}
|
|
|
|
|
return model.Duration(node.Val * 1e9).String()
|
|
|
|
|
}
|
2025-03-03 04:03:45 -05:00
|
|
|
return strconv.FormatFloat(node.Val, 'f', -1, 64)
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *ParenExpr) String() string {
|
2025-05-12 10:08:03 -04:00
|
|
|
return "(" + node.Expr.String() + ")"
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *StringLiteral) String() string {
|
2025-05-12 10:08:03 -04:00
|
|
|
return strconv.Quote(node.Val)
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (node *UnaryExpr) String() string {
|
2025-05-12 10:08:03 -04:00
|
|
|
return node.Op.String() + node.Expr.String()
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-02 16:17:45 -04:00
|
|
|
func (node *UnaryExpr) ShortString() string {
|
|
|
|
|
return node.Op.String()
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-30 12:12:51 -04:00
|
|
|
func (node *VectorSelector) String() string {
|
2021-09-01 03:48:18 -04:00
|
|
|
var labelStrings []string
|
|
|
|
|
if len(node.LabelMatchers) > 1 {
|
|
|
|
|
labelStrings = make([]string, 0, len(node.LabelMatchers)-1)
|
|
|
|
|
}
|
2015-03-30 12:12:51 -04:00
|
|
|
for _, matcher := range node.LabelMatchers {
|
2024-05-06 05:51:08 -04:00
|
|
|
// Only include the __name__ label if its equality matching and matches the name, but don't skip if it's an explicit empty name matcher.
|
|
|
|
|
if matcher.Name == labels.MetricName && matcher.Type == labels.MatchEqual && matcher.Value == node.Name && matcher.Value != "" {
|
2015-03-30 12:12:51 -04:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
labelStrings = append(labelStrings, matcher.String())
|
|
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
b := bytes.NewBuffer(make([]byte, 0, 1024))
|
|
|
|
|
b.WriteString(node.Name)
|
|
|
|
|
if len(labelStrings) != 0 {
|
|
|
|
|
b.WriteByte('{')
|
|
|
|
|
sort.Strings(labelStrings)
|
|
|
|
|
writeStringsJoin(b, labelStrings, ",")
|
|
|
|
|
b.WriteByte('}')
|
2021-01-20 05:57:39 -05:00
|
|
|
}
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
switch {
|
|
|
|
|
case node.Timestamp != nil:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(" @ ")
|
2025-08-22 05:58:01 -04:00
|
|
|
b.Write(strconv.AppendFloat(b.AvailableBuffer(), float64(*node.Timestamp)/1000.0, 'f', 3, 64))
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case node.StartOrEnd == START:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(" @ start()")
|
style: Replace `else if` cascades with `switch`
Wiser coders than myself have come to the conclusion that a `switch`
statement is almost always superior to a statement that includes any
`else if`.
The exceptions that I have found in our codebase are just these two:
* The `if else` is followed by an additional statement before the next
condition (separated by a `;`).
* The whole thing is within a `for` loop and `break` statements are
used. In this case, using `switch` would require tagging the `for`
loop, which probably tips the balance.
Why are `switch` statements more readable?
For one, fewer curly braces. But more importantly, the conditions all
have the same alignment, so the whole thing follows the natural flow
of going down a list of conditions. With `else if`, in contrast, all
conditions but the first are "hidden" behind `} else if `, harder to
spot and (for no good reason) presented differently from the first
condition.
I'm sure the aforemention wise coders can list even more reasons.
In any case, I like it so much that I have found myself recommending
it in code reviews. I would like to make it a habit in our code base,
without making it a hard requirement that we would test on the CI. But
for that, there has to be a role model, so this commit eliminates all
`if else` occurrences, unless it is autogenerated code or fits one of
the exceptions above.
Signed-off-by: beorn7 <beorn@grafana.com>
2023-04-12 10:14:31 -04:00
|
|
|
case node.StartOrEnd == END:
|
2025-05-12 10:17:19 -04:00
|
|
|
b.WriteString(" @ end()")
|
2015-11-15 04:26:38 -05:00
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
switch {
|
2025-09-25 05:34:59 -04:00
|
|
|
case node.Anchored:
|
|
|
|
|
b.WriteString(" anchored")
|
|
|
|
|
case node.Smoothed:
|
|
|
|
|
b.WriteString(" smoothed")
|
|
|
|
|
}
|
|
|
|
|
switch {
|
2025-05-12 10:17:19 -04:00
|
|
|
case node.OriginalOffsetExpr != nil:
|
|
|
|
|
b.WriteString(" offset ")
|
|
|
|
|
node.OriginalOffsetExpr.writeTo(b)
|
|
|
|
|
case node.OriginalOffset > time.Duration(0):
|
|
|
|
|
b.WriteString(" offset ")
|
|
|
|
|
b.WriteString(model.Duration(node.OriginalOffset).String())
|
|
|
|
|
case node.OriginalOffset < time.Duration(0):
|
|
|
|
|
b.WriteString(" offset -")
|
|
|
|
|
b.WriteString(model.Duration(-node.OriginalOffset).String())
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|
2025-05-12 10:17:19 -04:00
|
|
|
return b.String()
|
2015-03-30 12:12:51 -04:00
|
|
|
}
|