internal/logs/parser/ast/ast.go
// Package ast provides the log query language abstract syntax tree.
package ast
import (
"fmt"
"strconv"
"strings"
)
// Op type.
type Op string
// Op types.
const (
LNOT Op = "not"
NOT = "!"
IN = "in"
OR = "||"
AND = "&&"
NE = "!="
EQ = "="
GT = ">"
LT = "<"
GE = ">="
LE = "<="
)
// Node interface.
type Node interface {
String() string
}
// Root node.
type Root struct {
Node Node
}
// String implementation.
func (n Root) String() string {
return fmt.Sprintf(`{ %s }`, n.Node)
}
// Expr node.
type Expr struct {
Node Node
}
// String implementation.
func (n Expr) String() string {
return fmt.Sprintf(`(%s)`, n.Node)
}
// Literal node.
type Literal string
// String implementation.
func (n Literal) String() string {
return fmt.Sprintf(`%s`, string(n))
}
// Tuple node.
type Tuple []Node
// String implementation.
func (n Tuple) String() string {
return fmt.Sprintf(`%#v`, n)
}
// Contains node.
type Contains struct {
Node Node
}
// String implementation.
func (n Contains) String() string {
switch v := n.Node.(type) {
case String:
return fmt.Sprintf(`"*%s*"`, string(v))
default:
return fmt.Sprintf(`%s`, n.Node)
}
}
// String node.
type String string
// String implementation.
func (n String) String() string {
return fmt.Sprintf(`$.message = %q`, string(n))
}
// Property node.
type Property string
// String implementation.
func (n Property) String() string {
return fmt.Sprintf(`$.%s`, string(n))
}
// Field node.
type Field string
// String implementation.
func (n Field) String() string {
return fmt.Sprintf(`$.fields.%s`, string(n))
}
// Subscript node.
type Subscript struct {
Left Node
Right Node
}
// String implementation.
func (n Subscript) String() string {
return fmt.Sprintf(`%s[%s]`, n.Left, n.Right)
}
// Member node.
type Member struct {
Left Node
Right Node
}
// String implementation.
func (n Member) String() string {
return fmt.Sprintf(`%s.%s`, n.Left, n.Right)
}
// Number node.
type Number struct {
Value float64
Unit string
}
// String implementation.
func (n Number) String() string {
v := n.Value
switch n.Unit {
case "kb":
v *= 1 << 10
case "mb":
v *= 1 << 20
case "gb":
v *= 1 << 30
case "s":
v *= 1000
}
return strconv.FormatFloat(v, 'f', -1, 64)
}
// Binary node.
type Binary struct {
Op Op
Left Node
Right Node
}
// String implementation.
func (n Binary) String() string {
switch n.Op {
case IN:
var s []string
for _, v := range n.Right.(Tuple) {
s = append(s, fmt.Sprintf(`%s %s %s`, n.Left, EQ, value(v)))
}
return fmt.Sprintf(`(%s)`, strings.Join(s, " || "))
case EQ, NE, GT, LT, GE, LE:
return fmt.Sprintf(`%s %s %s`, n.Left, n.Op, value(n.Right))
default:
return fmt.Sprintf(`%s %s %s`, n.Left, n.Op, n.Right)
}
}
// Unary node.
type Unary struct {
Op Op
Right Node
}
// String implementation.
func (n Unary) String() string {
switch n.Op {
case LNOT:
return fmt.Sprintf(`!(%s)`, n.Right)
default:
return fmt.Sprintf(`%s%s`, n.Op, n.Right)
}
}
// value from node.
func value(n Node) string {
switch v := n.(type) {
case String:
return fmt.Sprintf("%q", string(v))
case Field:
return fmt.Sprintf("%q", string(v))
default:
return n.String()
}
}