From 96b6f9d3f1b7b7484144860c28ead000eff46df5 Mon Sep 17 00:00:00 2001 From: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> Date: Thu, 29 Sep 2022 12:03:31 -0600 Subject: [PATCH 1/3] Unexport unneeded grammar types --- pkg/ottl/boolean_value.go | 8 +- pkg/ottl/boolean_value_test.go | 134 +++++++-------- pkg/ottl/compare.go | 20 +-- pkg/ottl/compare_test.go | 4 +- pkg/ottl/expression.go | 2 +- pkg/ottl/expression_test.go | 30 ++-- pkg/ottl/functions.go | 8 +- pkg/ottl/functions_test.go | 134 +++++++-------- pkg/ottl/grammar.go | 211 +++++++++++++++++++++++ pkg/ottl/parser.go | 203 +--------------------- pkg/ottl/parser_test.go | 302 ++++++++++++++++----------------- 11 files changed, 536 insertions(+), 520 deletions(-) create mode 100644 pkg/ottl/grammar.go diff --git a/pkg/ottl/boolean_value.go b/pkg/ottl/boolean_value.go index ecdd4f22f825..4f7b3928406c 100644 --- a/pkg/ottl/boolean_value.go +++ b/pkg/ottl/boolean_value.go @@ -55,7 +55,7 @@ func orFuncs[K any](funcs []boolExpressionEvaluator[K]) boolExpressionEvaluator[ } } -func (p *Parser[K]) newComparisonEvaluator(comparison *Comparison) (boolExpressionEvaluator[K], error) { +func (p *Parser[K]) newComparisonEvaluator(comparison *comparison) (boolExpressionEvaluator[K], error) { if comparison == nil { return alwaysTrue[K], nil } @@ -77,7 +77,7 @@ func (p *Parser[K]) newComparisonEvaluator(comparison *Comparison) (boolExpressi } -func (p *Parser[K]) newBooleanExpressionEvaluator(expr *BooleanExpression) (boolExpressionEvaluator[K], error) { +func (p *Parser[K]) newBooleanExpressionEvaluator(expr *booleanExpression) (boolExpressionEvaluator[K], error) { if expr == nil { return alwaysTrue[K], nil } @@ -97,7 +97,7 @@ func (p *Parser[K]) newBooleanExpressionEvaluator(expr *BooleanExpression) (bool return orFuncs(funcs), nil } -func (p *Parser[K]) newBooleanTermEvaluator(term *Term) (boolExpressionEvaluator[K], error) { +func (p *Parser[K]) newBooleanTermEvaluator(term *term) (boolExpressionEvaluator[K], error) { if term == nil { return alwaysTrue[K], nil } @@ -117,7 +117,7 @@ func (p *Parser[K]) newBooleanTermEvaluator(term *Term) (boolExpressionEvaluator return andFuncs(funcs), nil } -func (p *Parser[K]) newBooleanValueEvaluator(value *BooleanValue) (boolExpressionEvaluator[K], error) { +func (p *Parser[K]) newBooleanValueEvaluator(value *booleanValue) (boolExpressionEvaluator[K], error) { if value == nil { return alwaysTrue[K], nil } diff --git a/pkg/ottl/boolean_value_test.go b/pkg/ottl/boolean_value_test.go index 6c1a6770c3dd..9fba3506270b 100644 --- a/pkg/ottl/boolean_value_test.go +++ b/pkg/ottl/boolean_value_test.go @@ -26,11 +26,11 @@ import ( ) // valueFor is a test helper to eliminate a lot of tedium in writing tests of Comparisons. -func valueFor(x any) Value { - val := Value{} +func valueFor(x any) value { + val := value{} switch v := x.(type) { case []byte: - var b Bytes = v + var b byteSlice = v val.Bytes = &b case string: switch { @@ -58,9 +58,9 @@ func valueFor(x any) Value { case *int64: val.Int = v case bool: - val.Bool = Booleanp(Boolean(v)) + val.Bool = Booleanp(boolean(v)) case nil: - var n IsNil = true + var n isNil = true val.IsNil = &n default: panic("test error!") @@ -68,9 +68,9 @@ func valueFor(x any) Value { return val } -// comparison is a test helper that constructs a Comparison object using valueFor -func comparison(left any, right any, op string) *Comparison { - return &Comparison{ +// comparison is a test helper that constructs a comparison object using valueFor +func comparisonHelper(left any, right any, op string) *comparison { + return &comparison{ Left: valueFor(left), Right: valueFor(right), Op: compareOpTable[op], @@ -118,7 +118,7 @@ func Test_newComparisonEvaluator(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - comp := comparison(tt.l, tt.r, tt.op) + comp := comparisonHelper(tt.l, tt.r, tt.op) evaluate, err := p.newComparisonEvaluator(comp) assert.NoError(t, err) assert.Equal(t, tt.want, evaluate(tt.item)) @@ -136,16 +136,16 @@ func Test_newConditionEvaluator_invalid(t *testing.T) { tests := []struct { name string - comparison *Comparison + comparison *comparison }{ { name: "unknown Path", - comparison: &Comparison{ - Left: Value{ + comparison: &comparison{ + Left: value{ Enum: (*EnumSymbol)(ottltest.Strp("SYMBOL_NOT_FOUND")), }, Op: EQ, - Right: Value{ + Right: value{ String: ottltest.Strp("trash"), }, }, @@ -170,18 +170,18 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { tests := []struct { name string want bool - expr *BooleanExpression + expr *booleanExpression }{ {"a", false, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -190,15 +190,15 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { }, }, {"b", true, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(true), }, }, @@ -207,21 +207,21 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { }, }, {"c", false, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(true), }, }, { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -230,17 +230,17 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { }, }, {"d", true, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -249,17 +249,17 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { }, }, {"e", true, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, }, @@ -268,17 +268,17 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { }, }, {"f", false, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -287,25 +287,25 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { }, }, {"g", true, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(false), }, }, }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, }, @@ -314,26 +314,26 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { }, }, {"h", true, - &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ - SubExpr: &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + Value: &booleanValue{ + SubExpr: &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, diff --git a/pkg/ottl/compare.go b/pkg/ottl/compare.go index 98ebf43f7c6a..ee6a9e0d5d6d 100644 --- a/pkg/ottl/compare.go +++ b/pkg/ottl/compare.go @@ -28,14 +28,14 @@ import ( // invalidComparison returns false for everything except NE (where it returns true to indicate that the // objects were definitely not equivalent). // It also gives us an opportunity to log something. -func (p *Parser[K]) invalidComparison(msg string, op CompareOp) bool { +func (p *Parser[K]) invalidComparison(msg string, op compareOp) bool { p.telemetrySettings.Logger.Debug(msg, zap.Any("op", op)) return op == NE } // comparePrimitives implements a generic comparison helper for all Ordered types (derived from Float, Int, or string). // According to benchmarks, it's faster than explicit comparison functions for these types. -func comparePrimitives[T constraints.Ordered](a T, b T, op CompareOp) bool { +func comparePrimitives[T constraints.Ordered](a T, b T, op compareOp) bool { switch op { case EQ: return a == b @@ -54,7 +54,7 @@ func comparePrimitives[T constraints.Ordered](a T, b T, op CompareOp) bool { } } -func compareBools(a bool, b bool, op CompareOp) bool { +func compareBools(a bool, b bool, op compareOp) bool { switch op { case EQ: return a == b @@ -73,7 +73,7 @@ func compareBools(a bool, b bool, op CompareOp) bool { } } -func compareBytes(a []byte, b []byte, op CompareOp) bool { +func compareBytes(a []byte, b []byte, op compareOp) bool { switch op { case EQ: return bytes.Equal(a, b) @@ -92,7 +92,7 @@ func compareBytes(a []byte, b []byte, op CompareOp) bool { } } -func (p *Parser[K]) compareBool(a bool, b any, op CompareOp) bool { +func (p *Parser[K]) compareBool(a bool, b any, op compareOp) bool { switch v := b.(type) { case bool: return compareBools(a, v, op) @@ -101,7 +101,7 @@ func (p *Parser[K]) compareBool(a bool, b any, op CompareOp) bool { } } -func (p *Parser[K]) compareString(a string, b any, op CompareOp) bool { +func (p *Parser[K]) compareString(a string, b any, op compareOp) bool { switch v := b.(type) { case string: return comparePrimitives(a, v, op) @@ -110,7 +110,7 @@ func (p *Parser[K]) compareString(a string, b any, op CompareOp) bool { } } -func (p *Parser[K]) compareByte(a []byte, b any, op CompareOp) bool { +func (p *Parser[K]) compareByte(a []byte, b any, op compareOp) bool { switch v := b.(type) { case nil: return op == NE @@ -124,7 +124,7 @@ func (p *Parser[K]) compareByte(a []byte, b any, op CompareOp) bool { } } -func (p *Parser[K]) compareInt64(a int64, b any, op CompareOp) bool { +func (p *Parser[K]) compareInt64(a int64, b any, op compareOp) bool { switch v := b.(type) { case int64: return comparePrimitives(a, v, op) @@ -135,7 +135,7 @@ func (p *Parser[K]) compareInt64(a int64, b any, op CompareOp) bool { } } -func (p *Parser[K]) compareFloat64(a float64, b any, op CompareOp) bool { +func (p *Parser[K]) compareFloat64(a float64, b any, op compareOp) bool { switch v := b.(type) { case int64: return comparePrimitives(a, float64(v), op) @@ -148,7 +148,7 @@ func (p *Parser[K]) compareFloat64(a float64, b any, op CompareOp) bool { // a and b are the return values from a Getter; we try to compare them // according to the given operator. -func (p *Parser[K]) compare(a any, b any, op CompareOp) bool { +func (p *Parser[K]) compare(a any, b any, op compareOp) bool { // nils are equal to each other and never equal to anything else, // so if they're both nil, report equality. if a == nil && b == nil { diff --git a/pkg/ottl/compare_test.go b/pkg/ottl/compare_test.go index 14c4abcffae3..8fe502799fd8 100644 --- a/pkg/ottl/compare_test.go +++ b/pkg/ottl/compare_test.go @@ -112,7 +112,7 @@ func Test_compare(t *testing.T) { {"non-prim, int type", testA{"hi"}, 5, []bool{false, true, false, false, false, false}}, {"int, non-prim", 5, testA{"hi"}, []bool{false, true, false, false, false, false}}, } - ops := []CompareOp{EQ, NE, LT, LTE, GTE, GT} + ops := []compareOp{EQ, NE, LT, LTE, GTE, GT} for _, tt := range tests { for _, op := range ops { t.Run(fmt.Sprintf("%s %v", tt.name, op), func(t *testing.T) { @@ -239,7 +239,7 @@ func BenchmarkCompareLTNil(b *testing.B) { // this is only used for benchmarking, and is a rough equivalent of the original compare function // before adding LT, LTE, GTE, and GT. -func compareEq(a any, b any, op CompareOp) bool { +func compareEq(a any, b any, op compareOp) bool { switch op { case EQ: return a == b diff --git a/pkg/ottl/expression.go b/pkg/ottl/expression.go index e2a0cec08de1..a8963090bf37 100644 --- a/pkg/ottl/expression.go +++ b/pkg/ottl/expression.go @@ -62,7 +62,7 @@ func (g exprGetter[K]) Get(ctx K) interface{} { return g.expr(ctx) } -func (p *Parser[K]) newGetter(val Value) (Getter[K], error) { +func (p *Parser[K]) newGetter(val value) (Getter[K], error) { if val.IsNil != nil && *val.IsNil { return &literal[K]{value: nil}, nil } diff --git a/pkg/ottl/expression_test.go b/pkg/ottl/expression_test.go index ac7404db0757..76bb80ea151a 100644 --- a/pkg/ottl/expression_test.go +++ b/pkg/ottl/expression_test.go @@ -32,54 +32,54 @@ func hello[K any]() (ExprFunc[K], error) { func Test_newGetter(t *testing.T) { tests := []struct { name string - val Value + val value want interface{} }{ { name: "string literal", - val: Value{ + val: value{ String: ottltest.Strp("str"), }, want: "str", }, { name: "float literal", - val: Value{ + val: value{ Float: ottltest.Floatp(1.2), }, want: 1.2, }, { name: "int literal", - val: Value{ + val: value{ Int: ottltest.Intp(12), }, want: int64(12), }, { name: "bytes literal", - val: Value{ - Bytes: (*Bytes)(&[]byte{1, 2, 3, 4, 5, 6, 7, 8}), + val: value{ + Bytes: (*byteSlice)(&[]byte{1, 2, 3, 4, 5, 6, 7, 8}), }, want: []byte{1, 2, 3, 4, 5, 6, 7, 8}, }, { name: "nil literal", - val: Value{ - IsNil: (*IsNil)(ottltest.Boolp(true)), + val: value{ + IsNil: (*isNil)(ottltest.Boolp(true)), }, want: nil, }, { name: "bool literal", - val: Value{ - Bool: (*Boolean)(ottltest.Boolp(true)), + val: value{ + Bool: (*boolean)(ottltest.Boolp(true)), }, want: true, }, { name: "path expression", - val: Value{ + val: value{ Path: &Path{ Fields: []Field{ { @@ -92,8 +92,8 @@ func Test_newGetter(t *testing.T) { }, { name: "function call", - val: Value{ - Invocation: &Invocation{ + val: value{ + Invocation: &invocation{ Function: "hello", }, }, @@ -101,7 +101,7 @@ func Test_newGetter(t *testing.T) { }, { name: "enum", - val: Value{ + val: value{ Enum: (*EnumSymbol)(ottltest.Strp("TEST_ENUM_ONE")), }, want: int64(1), @@ -127,7 +127,7 @@ func Test_newGetter(t *testing.T) { } t.Run("empty value", func(t *testing.T) { - _, err := p.newGetter(Value{}) + _, err := p.newGetter(value{}) assert.Error(t, err) }) } diff --git a/pkg/ottl/functions.go b/pkg/ottl/functions.go index b59148a0bc5f..e6a641986504 100644 --- a/pkg/ottl/functions.go +++ b/pkg/ottl/functions.go @@ -27,7 +27,7 @@ type EnumParser func(*EnumSymbol) (*Enum, error) type Enum int64 -func (p *Parser[K]) newFunctionCall(inv Invocation) (ExprFunc[K], error) { +func (p *Parser[K]) newFunctionCall(inv invocation) (ExprFunc[K], error) { if f, ok := p.functions[inv.Function]; ok { args, err := p.buildArgs(inv, reflect.TypeOf(f)) if err != nil { @@ -47,7 +47,7 @@ func (p *Parser[K]) newFunctionCall(inv Invocation) (ExprFunc[K], error) { return nil, fmt.Errorf("undefined function %v", inv.Function) } -func (p *Parser[K]) buildArgs(inv Invocation, fType reflect.Type) ([]reflect.Value, error) { +func (p *Parser[K]) buildArgs(inv invocation, fType reflect.Type) ([]reflect.Value, error) { var args []reflect.Value // Some function arguments may be intended to take values from the calling processor // instead of being passed by the caller of the OTTL function, so we have to keep @@ -92,7 +92,7 @@ func (p *Parser[K]) buildArgs(inv Invocation, fType reflect.Type) ([]reflect.Val return args, nil } -func (p *Parser[K]) buildSliceArg(inv Invocation, argType reflect.Type, startingIndex int, args *[]reflect.Value) error { +func (p *Parser[K]) buildSliceArg(inv invocation, argType reflect.Type, startingIndex int, args *[]reflect.Value) error { name := argType.Elem().Name() switch { case name == reflect.String.String(): @@ -144,7 +144,7 @@ func (p *Parser[K]) buildSliceArg(inv Invocation, argType reflect.Type, starting } // Handle interfaces that can be passed as arguments to OTTL function invocations. -func (p *Parser[K]) buildArg(argDef Value, argType reflect.Type, index int, args *[]reflect.Value) error { +func (p *Parser[K]) buildArg(argDef value, argType reflect.Type, index int, args *[]reflect.Value) error { name := argType.Name() switch { case strings.HasPrefix(name, "Setter"): diff --git a/pkg/ottl/functions_test.go b/pkg/ottl/functions_test.go index 536c62239067..303c85722a7e 100644 --- a/pkg/ottl/functions_test.go +++ b/pkg/ottl/functions_test.go @@ -44,20 +44,20 @@ func Test_NewFunctionCall_invalid(t *testing.T) { tests := []struct { name string - inv Invocation + inv invocation }{ { name: "unknown function", - inv: Invocation{ + inv: invocation{ Function: "unknownfunc", - Arguments: []Value{}, + Arguments: []value{}, }, }, { name: "not accessor", - inv: Invocation{ + inv: invocation{ Function: "testing_getsetter", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("not path"), }, @@ -66,11 +66,11 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "not reader (invalid function)", - inv: Invocation{ + inv: invocation{ Function: "testing_getter", - Arguments: []Value{ + Arguments: []value{ { - Invocation: &Invocation{ + Invocation: &invocation{ Function: "unknownfunc", }, }, @@ -79,9 +79,9 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "not enough args", - inv: Invocation{ + inv: invocation{ Function: "testing_multiple_args", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -99,9 +99,9 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "too many args", - inv: Invocation{ + inv: invocation{ Function: "testing_multiple_args", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -122,9 +122,9 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "not enough args with telemetrySettings", - inv: Invocation{ + inv: invocation{ Function: "testing_telemetry_settings_first", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test"), }, @@ -136,9 +136,9 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "too many args with telemetrySettings", - inv: Invocation{ + inv: invocation{ Function: "testing_telemetry_settings_first", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test"), }, @@ -156,9 +156,9 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "not matching arg type", - inv: Invocation{ + inv: invocation{ Function: "testing_string", - Arguments: []Value{ + Arguments: []value{ { Int: ottltest.Intp(10), }, @@ -167,9 +167,9 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "not matching arg type when byte slice", - inv: Invocation{ + inv: invocation{ Function: "testing_byte_slice", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test"), }, @@ -184,15 +184,15 @@ func Test_NewFunctionCall_invalid(t *testing.T) { }, { name: "function call returns error", - inv: Invocation{ + inv: invocation{ Function: "testing_error", }, }, { name: "Enum not found", - inv: Invocation{ + inv: invocation{ Function: "testing_enum", - Arguments: []Value{ + Arguments: []value{ { Enum: (*EnumSymbol)(ottltest.Strp("SYMBOL_NOT_FOUND")), }, @@ -219,13 +219,13 @@ func Test_NewFunctionCall(t *testing.T) { tests := []struct { name string - inv Invocation + inv invocation }{ { name: "string slice arg", - inv: Invocation{ + inv: invocation{ Function: "testing_string_slice", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test"), }, @@ -240,9 +240,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "float slice arg", - inv: Invocation{ + inv: invocation{ Function: "testing_float_slice", - Arguments: []Value{ + Arguments: []value{ { Float: ottltest.Floatp(1.1), }, @@ -257,9 +257,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "int slice arg", - inv: Invocation{ + inv: invocation{ Function: "testing_int_slice", - Arguments: []Value{ + Arguments: []value{ { Int: ottltest.Intp(1), }, @@ -274,9 +274,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "getter slice arg", - inv: Invocation{ + inv: invocation{ Function: "testing_getter_slice", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -296,15 +296,15 @@ func Test_NewFunctionCall(t *testing.T) { Float: ottltest.Floatp(1.1), }, { - Bool: (*Boolean)(ottltest.Boolp(true)), + Bool: (*boolean)(ottltest.Boolp(true)), }, { Enum: (*EnumSymbol)(ottltest.Strp("TEST_ENUM")), }, { - Invocation: &Invocation{ + Invocation: &invocation{ Function: "testing_getter", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -322,9 +322,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "setter arg", - inv: Invocation{ + inv: invocation{ Function: "testing_setter", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -339,9 +339,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "getsetter arg", - inv: Invocation{ + inv: invocation{ Function: "testing_getsetter", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -356,9 +356,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "getter arg", - inv: Invocation{ + inv: invocation{ Function: "testing_getter", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -373,20 +373,20 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "getter arg with nil literal", - inv: Invocation{ + inv: invocation{ Function: "testing_getter", - Arguments: []Value{ + Arguments: []value{ { - IsNil: (*IsNil)(ottltest.Boolp(true)), + IsNil: (*isNil)(ottltest.Boolp(true)), }, }, }, }, { name: "string arg", - inv: Invocation{ + inv: invocation{ Function: "testing_string", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test"), }, @@ -395,9 +395,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "float arg", - inv: Invocation{ + inv: invocation{ Function: "testing_float", - Arguments: []Value{ + Arguments: []value{ { Float: ottltest.Floatp(1.1), }, @@ -406,9 +406,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "int arg", - inv: Invocation{ + inv: invocation{ Function: "testing_int", - Arguments: []Value{ + Arguments: []value{ { Int: ottltest.Intp(1), }, @@ -417,31 +417,31 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "bool arg", - inv: Invocation{ + inv: invocation{ Function: "testing_bool", - Arguments: []Value{ + Arguments: []value{ { - Bool: (*Boolean)(ottltest.Boolp(true)), + Bool: (*boolean)(ottltest.Boolp(true)), }, }, }, }, { - name: "bytes arg", - inv: Invocation{ + name: "byteSlice arg", + inv: invocation{ Function: "testing_byte_slice", - Arguments: []Value{ + Arguments: []value{ { - Bytes: (*Bytes)(&[]byte{1, 2, 3, 4, 5, 6, 7, 8}), + Bytes: (*byteSlice)(&[]byte{1, 2, 3, 4, 5, 6, 7, 8}), }, }, }, }, { name: "multiple args", - inv: Invocation{ + inv: invocation{ Function: "testing_multiple_args", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -471,9 +471,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "Enum arg", - inv: Invocation{ + inv: invocation{ Function: "testing_enum", - Arguments: []Value{ + Arguments: []value{ { Enum: (*EnumSymbol)(ottltest.Strp("TEST_ENUM")), }, @@ -482,9 +482,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "telemetrySettings first", - inv: Invocation{ + inv: invocation{ Function: "testing_telemetry_settings_first", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test0"), }, @@ -499,9 +499,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "telemetrySettings middle", - inv: Invocation{ + inv: invocation{ Function: "testing_telemetry_settings_middle", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test0"), }, @@ -516,9 +516,9 @@ func Test_NewFunctionCall(t *testing.T) { }, { name: "telemetrySettings last", - inv: Invocation{ + inv: invocation{ Function: "testing_telemetry_settings_last", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("test0"), }, diff --git a/pkg/ottl/grammar.go b/pkg/ottl/grammar.go new file mode 100644 index 000000000000..009c37dec271 --- /dev/null +++ b/pkg/ottl/grammar.go @@ -0,0 +1,211 @@ +// Copyright The OpenTelemetry Authors +// +// 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. + +package ottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" +import ( + "encoding/hex" + "fmt" + "github.com/alecthomas/participle/v2/lexer" +) + +// parsedStatement represents a parsed statement. It is the entry point into the statement DSL. +type parsedStatement struct { + Invocation invocation `parser:"@@"` + WhereClause *booleanExpression `parser:"( 'where' @@ )?"` +} + +// booleanValue represents something that evaluates to a boolean -- +// either an equality or inequality, explicit true or false, or +// a parenthesized subexpression. +type booleanValue struct { + Comparison *comparison `parser:"( @@"` + ConstExpr *boolean `parser:"| @Boolean"` + SubExpr *booleanExpression `parser:"| '(' @@ ')' )"` +} + +// opAndBooleanValue represents the right side of an AND boolean expression. +type opAndBooleanValue struct { + Operator string `parser:"@OpAnd"` + Value *booleanValue `parser:"@@"` +} + +// term represents an arbitrary number of boolean values joined by AND. +type term struct { + Left *booleanValue `parser:"@@"` + Right []*opAndBooleanValue `parser:"@@*"` +} + +// opOrTerm represents the right side of an OR boolean expression. +type opOrTerm struct { + Operator string `parser:"@OpOr"` + Term *term `parser:"@@"` +} + +// booleanExpression represents a true/false decision expressed +// as an arbitrary number of terms separated by OR. +type booleanExpression struct { + Left *term `parser:"@@"` + Right []*opOrTerm `parser:"@@*"` +} + +// compareOp is the type of a comparison operator. +type compareOp int + +// These are the allowed values of a compareOp +const ( + EQ compareOp = iota + NE + LT + LTE + GTE + GT +) + +// a fast way to get from a string to a compareOp +var compareOpTable = map[string]compareOp{ + "==": EQ, + "!=": NE, + "<": LT, + "<=": LTE, + ">": GT, + ">=": GTE, +} + +// Capture is how the parser converts an operator string to a compareOp. +func (c *compareOp) Capture(values []string) error { + op, ok := compareOpTable[values[0]] + if !ok { + return fmt.Errorf("'%s' is not a valid operator", values[0]) + } + *c = op + return nil +} + +// String() for compareOp gives us more legible test results and error messages. +func (c *compareOp) String() string { + switch *c { + case EQ: + return "EQ" + case NE: + return "NE" + case LT: + return "LT" + case LTE: + return "LTE" + case GTE: + return "GTE" + case GT: + return "GT" + default: + return "UNKNOWN OP!" + } +} + +// comparison represents an optional boolean condition. +type comparison struct { + Left value `parser:"@@"` + Op compareOp `parser:"@OpComparison"` + Right value `parser:"@@"` +} + +// invocation represents a function call. +type invocation struct { + Function string `parser:"@(Uppercase | Lowercase)+"` + Arguments []value `parser:"'(' ( @@ ( ',' @@ )* )? ')'"` +} + +// value represents a part of a parsed statement which is resolved to a value of some sort. This can be a telemetry path +// expression, function call, or literal. +type value struct { + Invocation *invocation `parser:"( @@"` + Bytes *byteSlice `parser:"| @Bytes"` + String *string `parser:"| @String"` + Float *float64 `parser:"| @Float"` + Int *int64 `parser:"| @Int"` + Bool *boolean `parser:"| @Boolean"` + IsNil *isNil `parser:"| @'nil'"` + Enum *EnumSymbol `parser:"| @Uppercase"` + Path *Path `parser:"| @@ )"` +} + +// Path represents a telemetry path expression. +type Path struct { + Fields []Field `parser:"@@ ( '.' @@ )*"` +} + +// Field is an item within a Path. +type Field struct { + Name string `parser:"@Lowercase"` + MapKey *string `parser:"( '[' @String ']' )?"` +} + +// Statement holds a top level Statement for processing telemetry data. A Statement is a combination of a function +// invocation and the expression to match telemetry for invoking the function. +type Statement[K any] struct { + Function ExprFunc[K] + Condition boolExpressionEvaluator[K] +} + +// byteSlice type for capturing byte slices +type byteSlice []byte + +func (b *byteSlice) Capture(values []string) error { + rawStr := values[0][2:] + newBytes, err := hex.DecodeString(rawStr) + if err != nil { + return err + } + *b = newBytes + return nil +} + +// boolean Type for capturing booleans, see: +// https://github.com/alecthomas/participle#capturing-boolean-value +type boolean bool + +func (b *boolean) Capture(values []string) error { + *b = values[0] == "true" + return nil +} + +type isNil bool + +func (n *isNil) Capture(_ []string) error { + *n = true + return nil +} + +type EnumSymbol string + +// buildLexer constructs a SimpleLexer definition. +// Note that the ordering of these rules matters. +// It's in a separate function so it can be easily tested alone (see lexer_test.go). +func buildLexer() *lexer.StatefulDefinition { + return lexer.MustSimple([]lexer.SimpleRule{ + {Name: `Bytes`, Pattern: `0x[a-fA-F0-9]+`}, + {Name: `Float`, Pattern: `[-+]?\d*\.\d+([eE][-+]?\d+)?`}, + {Name: `Int`, Pattern: `[-+]?\d+`}, + {Name: `String`, Pattern: `"(\\"|[^"])*"`}, + {Name: `OpOr`, Pattern: `\b(or)\b`}, + {Name: `OpAnd`, Pattern: `\b(and)\b`}, + {Name: `OpComparison`, Pattern: `==|!=|>=|<=|>|<`}, + {Name: `Boolean`, Pattern: `\b(true|false)\b`}, + {Name: `LParen`, Pattern: `\(`}, + {Name: `RParen`, Pattern: `\)`}, + {Name: `Punct`, Pattern: `[,.\[\]]`}, + {Name: `Uppercase`, Pattern: `[A-Z_][A-Z0-9_]*`}, + {Name: `Lowercase`, Pattern: `[a-z_][a-z0-9_]*`}, + {Name: "whitespace", Pattern: `\s+`}, + }) +} diff --git a/pkg/ottl/parser.go b/pkg/ottl/parser.go index 18fcbc29235c..f444e5473da8 100644 --- a/pkg/ottl/parser.go +++ b/pkg/ottl/parser.go @@ -15,184 +15,11 @@ package ottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" import ( - "encoding/hex" - "fmt" - "github.com/alecthomas/participle/v2" - "github.com/alecthomas/participle/v2/lexer" "go.opentelemetry.io/collector/component" "go.uber.org/multierr" ) -// ParsedStatement represents a parsed statement. It is the entry point into the statement DSL. -type ParsedStatement struct { - Invocation Invocation `parser:"@@"` - WhereClause *BooleanExpression `parser:"( 'where' @@ )?"` -} - -// BooleanValue represents something that evaluates to a boolean -- -// either an equality or inequality, explicit true or false, or -// a parenthesized subexpression. -type BooleanValue struct { - Comparison *Comparison `parser:"( @@"` - ConstExpr *Boolean `parser:"| @Boolean"` - SubExpr *BooleanExpression `parser:"| '(' @@ ')' )"` -} - -// OpAndBooleanValue represents the right side of an AND boolean expression. -type OpAndBooleanValue struct { - Operator string `parser:"@OpAnd"` - Value *BooleanValue `parser:"@@"` -} - -// Term represents an arbitrary number of boolean values joined by AND. -type Term struct { - Left *BooleanValue `parser:"@@"` - Right []*OpAndBooleanValue `parser:"@@*"` -} - -// OpOrTerm represents the right side of an OR boolean expression. -type OpOrTerm struct { - Operator string `parser:"@OpOr"` - Term *Term `parser:"@@"` -} - -// BooleanExpression represents a true/false decision expressed -// as an arbitrary number of terms separated by OR. -type BooleanExpression struct { - Left *Term `parser:"@@"` - Right []*OpOrTerm `parser:"@@*"` -} - -// CompareOp is the type of a comparison operator. -type CompareOp int - -// These are the allowed values of a CompareOp -const ( - EQ CompareOp = iota - NE - LT - LTE - GTE - GT -) - -// a fast way to get from a string to a compareOp -var compareOpTable = map[string]CompareOp{ - "==": EQ, - "!=": NE, - "<": LT, - "<=": LTE, - ">": GT, - ">=": GTE, -} - -// Capture is how the parser converts an operator string to a CompareOp. -func (c *CompareOp) Capture(values []string) error { - op, ok := compareOpTable[values[0]] - if !ok { - return fmt.Errorf("'%s' is not a valid operator", values[0]) - } - *c = op - return nil -} - -// String() for CompareOp gives us more legible test results and error messages. -func (c CompareOp) String() string { - switch c { - case EQ: - return "EQ" - case NE: - return "NE" - case LT: - return "LT" - case LTE: - return "LTE" - case GTE: - return "GTE" - case GT: - return "GT" - default: - return "UNKNOWN OP!" - } -} - -// Comparison represents an optional boolean condition. -type Comparison struct { - Left Value `parser:"@@"` - Op CompareOp `parser:"@OpComparison"` - Right Value `parser:"@@"` -} - -// Invocation represents a function call. -type Invocation struct { - Function string `parser:"@(Uppercase | Lowercase)+"` - Arguments []Value `parser:"'(' ( @@ ( ',' @@ )* )? ')'"` -} - -// Value represents a part of a parsed statement which is resolved to a value of some sort. This can be a telemetry path -// expression, function call, or literal. -type Value struct { - Invocation *Invocation `parser:"( @@"` - Bytes *Bytes `parser:"| @Bytes"` - String *string `parser:"| @String"` - Float *float64 `parser:"| @Float"` - Int *int64 `parser:"| @Int"` - Bool *Boolean `parser:"| @Boolean"` - IsNil *IsNil `parser:"| @'nil'"` - Enum *EnumSymbol `parser:"| @Uppercase"` - Path *Path `parser:"| @@ )"` -} - -// Path represents a telemetry path expression. -type Path struct { - Fields []Field `parser:"@@ ( '.' @@ )*"` -} - -// Field is an item within a Path. -type Field struct { - Name string `parser:"@Lowercase"` - MapKey *string `parser:"( '[' @String ']' )?"` -} - -// Statement holds a top level Statement for processing telemetry data. A Statement is a combination of a function -// invocation and the expression to match telemetry for invoking the function. -type Statement[K any] struct { - Function ExprFunc[K] - Condition boolExpressionEvaluator[K] -} - -// Bytes type for capturing byte arrays -type Bytes []byte - -func (b *Bytes) Capture(values []string) error { - rawStr := values[0][2:] - bytes, err := hex.DecodeString(rawStr) - if err != nil { - return err - } - *b = bytes - return nil -} - -// Boolean Type for capturing booleans, see: -// https://github.com/alecthomas/participle#capturing-boolean-value -type Boolean bool - -func (b *Boolean) Capture(values []string) error { - *b = values[0] == "true" - return nil -} - -type IsNil bool - -func (n *IsNil) Capture(_ []string) error { - *n = true - return nil -} - -type EnumSymbol string - type Parser[K any] struct { functions map[string]interface{} pathParser PathExpressionParser[K] @@ -243,7 +70,7 @@ func (p *Parser[K]) ParseStatements(statements []string) ([]Statement[K], error) var parser = newParser() -func parseStatement(raw string) (*ParsedStatement, error) { +func parseStatement(raw string) (*parsedStatement, error) { parsed, err := parser.ParseString("", raw) if err != nil { return nil, err @@ -251,33 +78,11 @@ func parseStatement(raw string) (*ParsedStatement, error) { return parsed, nil } -// buildLexer constructs a SimpleLexer definition. -// Note that the ordering of these rules matters. -// It's in a separate function so it can be easily tested alone (see lexer_test.go). -func buildLexer() *lexer.StatefulDefinition { - return lexer.MustSimple([]lexer.SimpleRule{ - {Name: `Bytes`, Pattern: `0x[a-fA-F0-9]+`}, - {Name: `Float`, Pattern: `[-+]?\d*\.\d+([eE][-+]?\d+)?`}, - {Name: `Int`, Pattern: `[-+]?\d+`}, - {Name: `String`, Pattern: `"(\\"|[^"])*"`}, - {Name: `OpOr`, Pattern: `\b(or)\b`}, - {Name: `OpAnd`, Pattern: `\b(and)\b`}, - {Name: `OpComparison`, Pattern: `==|!=|>=|<=|>|<`}, - {Name: `Boolean`, Pattern: `\b(true|false)\b`}, - {Name: `LParen`, Pattern: `\(`}, - {Name: `RParen`, Pattern: `\)`}, - {Name: `Punct`, Pattern: `[,.\[\]]`}, - {Name: `Uppercase`, Pattern: `[A-Z_][A-Z0-9_]*`}, - {Name: `Lowercase`, Pattern: `[a-z_][a-z0-9_]*`}, - {Name: "whitespace", Pattern: `\s+`}, - }) -} - -// newParser returns a parser that can be used to read a string into a ParsedStatement. An error will be returned if the string +// newParser returns a parser that can be used to read a string into a parsedStatement. An error will be returned if the string // is not formatted for the DSL. -func newParser() *participle.Parser[ParsedStatement] { +func newParser() *participle.Parser[parsedStatement] { lex := buildLexer() - parser, err := participle.Build[ParsedStatement]( + parser, err := participle.Build[parsedStatement]( participle.Lexer(lex), participle.Unquote("String"), participle.Elide("whitespace"), diff --git a/pkg/ottl/parser_test.go b/pkg/ottl/parser_test.go index d9d28030626d..530bfabe79a6 100644 --- a/pkg/ottl/parser_test.go +++ b/pkg/ottl/parser_test.go @@ -26,7 +26,7 @@ import ( ) // This is not in ottltest because it depends on a type that's a member of OTTL. -func Booleanp(b Boolean) *Boolean { +func Booleanp(b boolean) *boolean { return &b } @@ -34,15 +34,15 @@ func Test_parse(t *testing.T) { tests := []struct { name string statement string - expected *ParsedStatement + expected *parsedStatement }{ { name: "invocation with string", statement: `set("foo")`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("foo"), }, @@ -54,10 +54,10 @@ func Test_parse(t *testing.T) { { name: "invocation with float", statement: `met(1.2)`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "met", - Arguments: []Value{ + Arguments: []value{ { Float: ottltest.Floatp(1.2), }, @@ -69,10 +69,10 @@ func Test_parse(t *testing.T) { { name: "invocation with int", statement: `fff(12)`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "fff", - Arguments: []Value{ + Arguments: []value{ { Int: ottltest.Intp(12), }, @@ -84,17 +84,17 @@ func Test_parse(t *testing.T) { { name: "complex invocation", statement: `set("foo", getSomething(bear.honey))`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("foo"), }, { - Invocation: &Invocation{ + Invocation: &invocation{ Function: "getSomething", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -118,10 +118,10 @@ func Test_parse(t *testing.T) { { name: "complex path", statement: `set(foo.attributes["bar"].cat, "dog")`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -149,10 +149,10 @@ func Test_parse(t *testing.T) { { name: "where == clause", statement: `set(foo.attributes["bar"].cat, "dog") where name == "fido"`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -174,11 +174,11 @@ func Test_parse(t *testing.T) { }, }, }, - WhereClause: &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ - Comparison: &Comparison{ - Left: Value{ + WhereClause: &booleanExpression{ + Left: &term{ + Left: &booleanValue{ + Comparison: &comparison{ + Left: value{ Path: &Path{ Fields: []Field{ { @@ -188,7 +188,7 @@ func Test_parse(t *testing.T) { }, }, Op: EQ, - Right: Value{ + Right: value{ String: ottltest.Strp("fido"), }, }, @@ -200,10 +200,10 @@ func Test_parse(t *testing.T) { { name: "where != clause", statement: `set(foo.attributes["bar"].cat, "dog") where name != "fido"`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -225,11 +225,11 @@ func Test_parse(t *testing.T) { }, }, }, - WhereClause: &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ - Comparison: &Comparison{ - Left: Value{ + WhereClause: &booleanExpression{ + Left: &term{ + Left: &booleanValue{ + Comparison: &comparison{ + Left: value{ Path: &Path{ Fields: []Field{ { @@ -239,7 +239,7 @@ func Test_parse(t *testing.T) { }, }, Op: NE, - Right: Value{ + Right: value{ String: ottltest.Strp("fido"), }, }, @@ -251,10 +251,10 @@ func Test_parse(t *testing.T) { { name: "ignore extra spaces", statement: `set ( foo.attributes[ "bar"].cat, "dog") where name=="fido"`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -276,11 +276,11 @@ func Test_parse(t *testing.T) { }, }, }, - WhereClause: &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ - Comparison: &Comparison{ - Left: Value{ + WhereClause: &booleanExpression{ + Left: &term{ + Left: &booleanValue{ + Comparison: &comparison{ + Left: value{ Path: &Path{ Fields: []Field{ { @@ -290,7 +290,7 @@ func Test_parse(t *testing.T) { }, }, Op: EQ, - Right: Value{ + Right: value{ String: ottltest.Strp("fido"), }, }, @@ -302,10 +302,10 @@ func Test_parse(t *testing.T) { { name: "handle quotes", statement: `set("fo\"o")`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("fo\"o"), }, @@ -315,17 +315,17 @@ func Test_parse(t *testing.T) { }, }, { - name: "Invocation with boolean false", + name: "invocation with boolean false", statement: `convert_gauge_to_sum("cumulative", false)`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "convert_gauge_to_sum", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("cumulative"), }, { - Bool: (*Boolean)(ottltest.Boolp(false)), + Bool: (*boolean)(ottltest.Boolp(false)), }, }, }, @@ -333,17 +333,17 @@ func Test_parse(t *testing.T) { }, }, { - name: "Invocation with boolean true", + name: "invocation with boolean true", statement: `convert_gauge_to_sum("cumulative", true)`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "convert_gauge_to_sum", - Arguments: []Value{ + Arguments: []value{ { String: ottltest.Strp("cumulative"), }, { - Bool: (*Boolean)(ottltest.Boolp(true)), + Bool: (*boolean)(ottltest.Boolp(true)), }, }, }, @@ -351,12 +351,12 @@ func Test_parse(t *testing.T) { }, }, { - name: "Invocation with bytes", + name: "invocation with bytes", statement: `set(attributes["bytes"], 0x0102030405060708)`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -368,7 +368,7 @@ func Test_parse(t *testing.T) { }, }, { - Bytes: (*Bytes)(&[]byte{1, 2, 3, 4, 5, 6, 7, 8}), + Bytes: (*byteSlice)(&[]byte{1, 2, 3, 4, 5, 6, 7, 8}), }, }, }, @@ -376,12 +376,12 @@ func Test_parse(t *testing.T) { }, }, { - name: "Invocation with nil", + name: "invocation with nil", statement: `set(attributes["test"], nil)`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -393,7 +393,7 @@ func Test_parse(t *testing.T) { }, }, { - IsNil: (*IsNil)(ottltest.Boolp(true)), + IsNil: (*isNil)(ottltest.Boolp(true)), }, }, }, @@ -401,12 +401,12 @@ func Test_parse(t *testing.T) { }, }, { - name: "Invocation with Enum", + name: "invocation with Enum", statement: `set(attributes["test"], TEST_ENUM)`, - expected: &ParsedStatement{ - Invocation: Invocation{ + expected: &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -483,11 +483,11 @@ func testParsePath(val *Path) (GetSetter[interface{}], error) { // Helper for test cases where the WHERE clause is all that matters. // Parse string should start with `set(name, "test") where`... -func setNameTest(b *BooleanExpression) *ParsedStatement { - return &ParsedStatement{ - Invocation: Invocation{ +func setNameTest(b *booleanExpression) *parsedStatement { + return &parsedStatement{ + Invocation: invocation{ Function: "set", - Arguments: []Value{ + Arguments: []value{ { Path: &Path{ Fields: []Field{ @@ -509,13 +509,13 @@ func setNameTest(b *BooleanExpression) *ParsedStatement { func Test_parseWhere(t *testing.T) { tests := []struct { statement string - expected *ParsedStatement + expected *parsedStatement }{ { statement: `true`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, }, @@ -523,15 +523,15 @@ func Test_parseWhere(t *testing.T) { }, { statement: `true and false`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -541,21 +541,21 @@ func Test_parseWhere(t *testing.T) { }, { statement: `true and true and false`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(true), }, }, { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -565,17 +565,17 @@ func Test_parseWhere(t *testing.T) { }, { statement: `true or false`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -585,25 +585,25 @@ func Test_parseWhere(t *testing.T) { }, { statement: `false and true or false`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(true), }, }, }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -613,18 +613,18 @@ func Test_parseWhere(t *testing.T) { }, { statement: `(false and true) or false`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ - SubExpr: &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ + SubExpr: &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ + Value: &booleanValue{ ConstExpr: Booleanp(true), }, }, @@ -633,11 +633,11 @@ func Test_parseWhere(t *testing.T) { }, }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -647,26 +647,26 @@ func Test_parseWhere(t *testing.T) { }, { statement: `false and (true or false)`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ - SubExpr: &BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ + Value: &booleanValue{ + SubExpr: &booleanExpression{ + Left: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(true), }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ + Term: &term{ + Left: &booleanValue{ ConstExpr: Booleanp(false), }, }, @@ -681,11 +681,11 @@ func Test_parseWhere(t *testing.T) { }, { statement: `name != "foo" and name != "bar"`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ - Comparison: &Comparison{ - Left: Value{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ + Comparison: &comparison{ + Left: value{ Path: &Path{ Fields: []Field{ { @@ -695,17 +695,17 @@ func Test_parseWhere(t *testing.T) { }, }, Op: NE, - Right: Value{ + Right: value{ String: ottltest.Strp("foo"), }, }, }, - Right: []*OpAndBooleanValue{ + Right: []*opAndBooleanValue{ { Operator: "and", - Value: &BooleanValue{ - Comparison: &Comparison{ - Left: Value{ + Value: &booleanValue{ + Comparison: &comparison{ + Left: value{ Path: &Path{ Fields: []Field{ { @@ -715,7 +715,7 @@ func Test_parseWhere(t *testing.T) { }, }, Op: NE, - Right: Value{ + Right: value{ String: ottltest.Strp("bar"), }, }, @@ -727,11 +727,11 @@ func Test_parseWhere(t *testing.T) { }, { statement: `name == "foo" or name == "bar"`, - expected: setNameTest(&BooleanExpression{ - Left: &Term{ - Left: &BooleanValue{ - Comparison: &Comparison{ - Left: Value{ + expected: setNameTest(&booleanExpression{ + Left: &term{ + Left: &booleanValue{ + Comparison: &comparison{ + Left: value{ Path: &Path{ Fields: []Field{ { @@ -741,19 +741,19 @@ func Test_parseWhere(t *testing.T) { }, }, Op: EQ, - Right: Value{ + Right: value{ String: ottltest.Strp("foo"), }, }, }, }, - Right: []*OpOrTerm{ + Right: []*opOrTerm{ { Operator: "or", - Term: &Term{ - Left: &BooleanValue{ - Comparison: &Comparison{ - Left: Value{ + Term: &term{ + Left: &booleanValue{ + Comparison: &comparison{ + Left: value{ Path: &Path{ Fields: []Field{ { @@ -763,7 +763,7 @@ func Test_parseWhere(t *testing.T) { }, }, Op: EQ, - Right: Value{ + Right: value{ String: ottltest.Strp("bar"), }, }, From 1f69badcb2a184dcbdc92ebe979b64b08fb349db Mon Sep 17 00:00:00 2001 From: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> Date: Thu, 29 Sep 2022 12:06:08 -0600 Subject: [PATCH 2/3] changelog entry --- unreleased/ottl-cleanup-grammar.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100755 unreleased/ottl-cleanup-grammar.yaml diff --git a/unreleased/ottl-cleanup-grammar.yaml b/unreleased/ottl-cleanup-grammar.yaml new file mode 100755 index 000000000000..59d31688696c --- /dev/null +++ b/unreleased/ottl-cleanup-grammar.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: breaking + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: pkg/ottl + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Unexports several types intended only for the package's grammar. + +# One or more tracking issues related to the change +issues: [14599] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: From 0766b709f1c48e50e8d6d502a16c00293616b50d Mon Sep 17 00:00:00 2001 From: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> Date: Thu, 29 Sep 2022 14:40:29 -0600 Subject: [PATCH 3/3] Fix lint errors --- pkg/ottl/boolean_value_test.go | 40 +++++++++++++++++----------------- pkg/ottl/grammar.go | 1 + pkg/ottl/parser_test.go | 36 +++++++++++++++--------------- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/pkg/ottl/boolean_value_test.go b/pkg/ottl/boolean_value_test.go index 9fba3506270b..feb7bbc2ad90 100644 --- a/pkg/ottl/boolean_value_test.go +++ b/pkg/ottl/boolean_value_test.go @@ -58,7 +58,7 @@ func valueFor(x any) value { case *int64: val.Int = v case bool: - val.Bool = Booleanp(boolean(v)) + val.Bool = booleanp(boolean(v)) case nil: var n isNil = true val.IsNil = &n @@ -176,13 +176,13 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -193,13 +193,13 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, }, @@ -210,19 +210,19 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -233,7 +233,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, Right: []*opOrTerm{ @@ -241,7 +241,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -252,7 +252,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, Right: []*opOrTerm{ @@ -260,7 +260,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, }, @@ -271,7 +271,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, Right: []*opOrTerm{ @@ -279,7 +279,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -290,13 +290,13 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -306,7 +306,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, }, @@ -317,7 +317,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, Right: []*opAndBooleanValue{ { @@ -326,7 +326,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { SubExpr: &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, Right: []*opOrTerm{ @@ -334,7 +334,7 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, diff --git a/pkg/ottl/grammar.go b/pkg/ottl/grammar.go index 009c37dec271..7c2334f93af9 100644 --- a/pkg/ottl/grammar.go +++ b/pkg/ottl/grammar.go @@ -16,6 +16,7 @@ package ottl // import "github.com/open-telemetry/opentelemetry-collector-contri import ( "encoding/hex" "fmt" + "github.com/alecthomas/participle/v2/lexer" ) diff --git a/pkg/ottl/parser_test.go b/pkg/ottl/parser_test.go index 530bfabe79a6..b78a96dcc28d 100644 --- a/pkg/ottl/parser_test.go +++ b/pkg/ottl/parser_test.go @@ -26,7 +26,7 @@ import ( ) // This is not in ottltest because it depends on a type that's a member of OTTL. -func Booleanp(b boolean) *boolean { +func booleanp(b boolean) *boolean { return &b } @@ -516,7 +516,7 @@ func Test_parseWhere(t *testing.T) { expected: setNameTest(&booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, }), @@ -526,13 +526,13 @@ func Test_parseWhere(t *testing.T) { expected: setNameTest(&booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -544,19 +544,19 @@ func Test_parseWhere(t *testing.T) { expected: setNameTest(&booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -568,7 +568,7 @@ func Test_parseWhere(t *testing.T) { expected: setNameTest(&booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, Right: []*opOrTerm{ @@ -576,7 +576,7 @@ func Test_parseWhere(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -588,13 +588,13 @@ func Test_parseWhere(t *testing.T) { expected: setNameTest(&booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, }, @@ -604,7 +604,7 @@ func Test_parseWhere(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -619,13 +619,13 @@ func Test_parseWhere(t *testing.T) { SubExpr: &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, Right: []*opAndBooleanValue{ { Operator: "and", Value: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, }, @@ -638,7 +638,7 @@ func Test_parseWhere(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, }, @@ -650,7 +650,7 @@ func Test_parseWhere(t *testing.T) { expected: setNameTest(&booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, Right: []*opAndBooleanValue{ { @@ -659,7 +659,7 @@ func Test_parseWhere(t *testing.T) { SubExpr: &booleanExpression{ Left: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(true), + ConstExpr: booleanp(true), }, }, Right: []*opOrTerm{ @@ -667,7 +667,7 @@ func Test_parseWhere(t *testing.T) { Operator: "or", Term: &term{ Left: &booleanValue{ - ConstExpr: Booleanp(false), + ConstExpr: booleanp(false), }, }, },