cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.57.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/parser/decode.go

108lines · modecode

1package parser
2
3import (
4 "encoding/json"
5 "errors"
6
7 promParser "github.com/prometheus/prometheus/promql/parser"
8)
9
10type PromQLExpr struct {
11 Value *YamlNode
12 SyntaxError error
13 Query *PromQLNode
14}
15
16// PromQLNode is used to turn the parsed PromQL query expression into a tree.
17// This allows us to walk the tree up & down and look for either parents
18// or children of specific type. Which is useful if you, for example,
19// want to check if all vector selectors are wrapped inside function
20// calls etc.
21type PromQLNode struct {
22 Parent *PromQLNode
23 Expr promParser.Node
24 Children []*PromQLNode
25}
26
27func (pn PromQLNode) MarshalJSON() ([]byte, error) {
28 return json.Marshal(pn.Expr.String())
29}
30
31// Tree takes a parsed PromQL node and turns it into a Node
32// instance with parent and children populated.
33func tree(expr promParser.Node, parent *PromQLNode) *PromQLNode {
34 n := PromQLNode{
35 Parent: parent,
36 Expr: expr,
37 }
38 for _, child := range promParser.Children(expr) {
39 n.Children = append(n.Children, tree(child, &n))
40 }
41
42 return &n
43}
44
45// WalkUpExpr allows to iterate a promQLNode node looking for
46// parents of specific type.
47// Prometheus parser returns interfaces which makes it more difficult
48// to figure out what kind of node we're dealing with, hence this
49// helper takes a type parameter it tries to cast.
50// It starts by checking the node passed to it and then walks
51// up by visiting all parent nodes.
52func WalkUpExpr[T promParser.Node](node *PromQLNode) (nodes []*PromQLNode) {
53 if node == nil {
54 return nodes
55 }
56 if _, ok := node.Expr.(T); ok {
57 nodes = append(nodes, node)
58 }
59 if node.Parent != nil {
60 nodes = append(nodes, WalkUpExpr[T](node.Parent)...)
61 }
62 return nodes
63}
64
65// WalkDownExpr works just like WalkUpExpr but it walks the tree
66// down, visiting all children.
67// It also starts by checking the node passed to it before walking
68// down the tree.
69func WalkDownExpr[T promParser.Node](node *PromQLNode) (nodes []*PromQLNode) {
70 if _, ok := node.Expr.(T); ok {
71 nodes = append(nodes, node)
72 }
73 for _, child := range node.Children {
74 nodes = append(nodes, WalkDownExpr[T](child)...)
75 }
76 return nodes
77}
78
79// WalkUpParent works like WalkUpExpr but checks the parent
80// (if present) instead of the node itself.
81// It returns the nodes where the parent is of given type.
82func WalkUpParent[T promParser.Node](node *PromQLNode) (nodes []*PromQLNode) {
83 if node == nil || node.Parent == nil {
84 return nodes
85 }
86 if _, ok := node.Parent.Expr.(T); ok {
87 nodes = append(nodes, node)
88 }
89 if node.Parent != nil {
90 nodes = append(nodes, WalkUpParent[T](node.Parent)...)
91 }
92 return nodes
93}
94
95func DecodeExpr(expr string) (*PromQLNode, error) {
96 node, err := promParser.ParseExpr(expr)
97 if err == nil {
98 return tree(node, nil), nil
99 }
100
101 var perrs promParser.ParseErrors
102 if ok := errors.As(err, &perrs); ok {
103 for _, perr := range perrs {
104 err = perr.Err
105 }
106 }
107 return nil, err
108}
109