From d9afdf5f969e625411318020a70a01226a870997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Wed, 6 Sep 2023 02:58:26 +0200 Subject: [PATCH 1/9] Add any and all expression support. The syntax is inspired by Sentinel [Any, All Expressions](https://docs.hashicorp.com/sentinel/language/boolexpr#any-all-expressions) and the [For Statements](https://docs.hashicorp.com/sentinel/language/loops#for-statements). Supporting this sort of complex conditions is useful for the Vault SAML auth method. --- evaluate.go | 99 ++- evaluate_test.go | 22 +- go.mod | 11 +- go.sum | 4 +- grammar/ast.go | 25 + grammar/ast_test.go | 66 ++ grammar/grammar.go | 1415 ++++++++++++++++++++++++--------------- grammar/grammar.peg | 37 + grammar/grammar_test.go | 151 ++++- 9 files changed, 1296 insertions(+), 534 deletions(-) diff --git a/evaluate.go b/evaluate.go index fcfa3c3..7abd748 100644 --- a/evaluate.go +++ b/evaluate.go @@ -223,7 +223,7 @@ func getMatchExprValue(expression *grammar.MatchExpression, rvalue reflect.Kind) // be handled by the MatchOperator's NotPresentDisposition method. // // Returns false if the Selector Path has a length of 1, or if the parent of -// the Selector's Path is not a map, a pointerstructure.ErrrNotFound error is +// the Selector's Path is not a map, a pointerstructure.ErrNotFound error is // returned. func evaluateNotPresent(ptr pointerstructure.Pointer, datum interface{}) bool { if len(ptr.Parts) < 2 { @@ -237,10 +237,10 @@ func evaluateNotPresent(ptr pointerstructure.Pointer, datum interface{}) bool { return reflect.ValueOf(val).Kind() == reflect.Map } -func evaluateMatchExpression(expression *grammar.MatchExpression, datum interface{}, opt ...Option) (bool, error) { +func getValue(datum interface{}, path []string, opt ...Option) (interface{}, bool, error) { opts := getOpts(opt...) ptr := pointerstructure.Pointer{ - Parts: expression.Selector.Path, + Parts: path, Config: pointerstructure.Config{ TagName: opts.withTagName, ValueTransformationHook: opts.withHookFn, @@ -256,15 +256,31 @@ func evaluateMatchExpression(expression *grammar.MatchExpression, datum interfac err = nil val = *opts.withUnknown case evaluateNotPresent(ptr, datum): - return expression.Operator.NotPresentDisposition(), nil + return nil, false, nil } } if err != nil { - return false, fmt.Errorf("error finding value in datum: %w", err) + return false, false, fmt.Errorf("error finding value in datum: %w", err) } } + return val, true, nil +} + +func evaluateMatchExpression(expression *grammar.MatchExpression, datum interface{}, opt ...Option) (bool, error) { + val, present, err := getValue( + datum, + expression.Selector.Path, + opt..., + ) + if err != nil { + return false, err + } + if !present { + return expression.Operator.NotPresentDisposition(), nil + } + if jn, ok := val.(json.Number); ok { if jni, err := jn.Int64(); err == nil { val = jni @@ -314,6 +330,77 @@ func evaluateMatchExpression(expression *grammar.MatchExpression, datum interfac } } +func evaluateCollectionExpression(expression *grammar.CollectionExpression, datum interface{}, opt ...Option) (bool, error) { + val, present, err := getValue( + datum, + expression.Selector.Path, + opt..., + ) + if err != nil { + return false, err + } + if !present { + return expression.Type == grammar.AllExpression, nil + } + + v := reflect.ValueOf(val) + + var keys []reflect.Value + if v.Kind() == reflect.Map { + keys = v.MapKeys() + } + + switch v.Kind() { + case reflect.Slice, reflect.Array, reflect.Map: + for i := 0; i < v.Len(); i++ { + + vars := map[string]interface{}{} + + if v.Kind() == reflect.Map { + key := keys[i] + if expression.Key != "_" { + vars[expression.Key] = key.Interface() + } + if expression.Value != "" && expression.Value != "_" { + vars[expression.Value] = v.MapIndex(key).Interface() + } + } else { + value := v.Index(i).Interface() + if expression.Value == "" { + // This means we are using the version with one placeholder + // like "all things as t { ... }". For lists t will iterate + // over the elements, not the indexes to match the behavior + // of the Sentinel for loop (or the "for t in things" in + // Python). This should match what users expect. + if expression.Key != "_" { + vars[expression.Key] = value + } + } else { + if expression.Key != "_" { + vars[expression.Key] = i + } + if expression.Value != "_" { + vars[expression.Value] = value + } + } + } + + result, err := evaluate(expression.Inner, pointerstructure.Defaults{vars, datum}, opt...) + if err != nil { + return false, err + } + if (result && expression.Type == grammar.AnyExpression) || (!result && expression.Type == grammar.AllExpression) { + return result, nil + } + } + + return expression.Type == grammar.AllExpression, nil + + default: + return false, fmt.Errorf(`%s is not a list or a map`, expression.Selector.String()) + } +} + func evaluate(ast grammar.Expression, datum interface{}, opt ...Option) (bool, error) { switch node := ast.(type) { case *grammar.UnaryExpression: @@ -342,6 +429,8 @@ func evaluate(ast grammar.Expression, datum interface{}, opt ...Option) (bool, e } case *grammar.MatchExpression: return evaluateMatchExpression(node, datum, opt...) + case *grammar.CollectionExpression: + return evaluateCollectionExpression(node, datum, opt...) } return false, fmt.Errorf("Invalid AST node") } diff --git a/evaluate_test.go b/evaluate_test.go index c00d709..2e53802 100644 --- a/evaluate_test.go +++ b/evaluate_test.go @@ -238,7 +238,7 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{ {expression: "foo.bar != false", result: true}, {expression: "foo.baz != false", result: false}, {expression: "foo.baz != true", result: true}, - {expression: "foo.bar.baz == 3", result: false, err: `error finding value in datum: /foo/bar/baz: at part 2, invalid value kind: bool`}, + {expression: "foo.bar.baz == 3", result: false, err: `error finding value in datum: /foo/bar/baz at part 2: invalid value kind (bool)`}, }, }, "Nested Structs and Maps": { @@ -311,6 +311,24 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{ {expression: `"2" in "/Nested/SliceOfInfs"`, result: false}, {expression: `"true" in "/Nested/SliceOfInfs"`, result: true}, {expression: `"/Nested/Map/email" matches "(foz|foo)@example.com"`, result: true}, + // all + {expression: `all Nested.SliceOfInts as _ { TopInt == 5 }`, result: true}, + {expression: `all Nested.SliceOfInts as i { i != 42 }`, result: true}, + {expression: `all Nested.SliceOfInts as i { i == 1 }`, result: false}, + {expression: `all Nested.Map as v { v == "bar" }`, result: false}, + {expression: `all Nested.Map as v { v != "hello" }`, result: true}, + {expression: `all Nested.Map as _, _ { TopInt == 5 }`, result: true}, + {expression: `all Nested.Map as k, _ { k != "foo" }`, result: false}, + {expression: `all Nested.Map as k, _ { k != "hello" }`, result: true}, + {expression: `all Nested.Map as k, v { k != "foo" or v != "baz" }`, result: true}, + {expression: `all TopInt as k, v { k != "foo" or v != "baz" }`, err: "TopInt is not a list or a map"}, + // any + {expression: `any Nested.SliceOfInts as i { i == 1 }`, result: true}, + {expression: `any Nested.SliceOfInts as i { i == 42 }`, result: false}, + {expression: `any Nested.Map as v { v != "bar" }`, result: true}, + {expression: `any Nested.Map as v { v == "bar" }`, result: true}, + {expression: `any Nested.Map as v { v == "hello" }`, result: false}, + {expression: `any Nested.Map as k, v { k == "foo" and v == "bar" }`, result: true}, // Missing key in map tests {expression: "Nested.Map.notfound == 4", result: false}, {expression: "Nested.Map.notfound != 4", result: true}, @@ -399,7 +417,7 @@ func TestWithHookFn(t *testing.T) { {expression: `"/I/I"=="bar"`, result: true}, { expression: `"/S/I"=="foo"`, result: false, - err: "error finding value in datum: /S/I: at part 1, invalid value kind: string", + err: "error finding value in datum: /S/I at part 1: invalid value kind (string)", }, }, }, diff --git a/go.mod b/go.mod index 1a55899..5e3f71a 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,17 @@ module github.com/hashicorp/go-bexpr -go 1.14 +go 1.18 require ( github.com/mitchellh/pointerstructure v1.2.1 github.com/stretchr/testify v1.8.2 ) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/mitchellh/pointerstructure v1.2.1 => github.com/remilapeyre/pointerstructure v0.0.0-20230906004826-80d813010704 diff --git a/go.sum b/go.sum index c6ceb45..999d82e 100644 --- a/go.sum +++ b/go.sum @@ -3,10 +3,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= -github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/remilapeyre/pointerstructure v0.0.0-20230906004826-80d813010704 h1:KnesY9UJKkVhupIN3bac36cb6Kc0mTTG7BkHNrdQgSo= +github.com/remilapeyre/pointerstructure v0.0.0-20230906004826-80d813010704/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/grammar/ast.go b/grammar/ast.go index 93c5402..23d7eef 100644 --- a/grammar/ast.go +++ b/grammar/ast.go @@ -192,3 +192,28 @@ func (expr *MatchExpression) ExpressionDump(w io.Writer, indent string, level in fmt.Fprintf(w, "%[1]s%[3]s {\n%[2]sSelector: %[4]v\n%[1]s}\n", strings.Repeat(indent, level), strings.Repeat(indent, level+1), expr.Operator.String(), expr.Selector) } } + +type CollectionExpressionType string + +const ( + AllExpression CollectionExpressionType = "All" + AnyExpression CollectionExpressionType = "Any" +) + +type CollectionExpression struct { + Type CollectionExpressionType + Selector Selector + Inner Expression + Key, Value string +} + +func (expr *CollectionExpression) ExpressionDump(w io.Writer, indent string, level int) { + localIndent := strings.Repeat(indent, level) + if expr.Value == "" { + fmt.Fprintf(w, "%s%s %s on %v {\n", localIndent, expr.Type, expr.Key, expr.Selector) + } else { + fmt.Fprintf(w, "%s%s (%s, %s) on %v {\n", localIndent, expr.Type, expr.Key, expr.Value, expr.Selector) + } + expr.Inner.ExpressionDump(w, indent, level+1) + fmt.Fprintf(w, "%s}\n", localIndent) +} diff --git a/grammar/ast_test.go b/grammar/ast_test.go index f552950..1a5fda1 100644 --- a/grammar/ast_test.go +++ b/grammar/ast_test.go @@ -78,6 +78,72 @@ func TestAST_Dump(t *testing.T) { }, expected: "UNKNOWN {\n Is Empty {\n Selector: foo.bar\n }\n Is Empty {\n Selector: foo.bar\n }\n}\n", }, + "All single variation": { + expr: &CollectionExpression{ + Key: "k", + Value: "", + Type: AllExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"obj"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"v"}, + }, + Operator: 0, + Value: &MatchValue{ + Raw: "hello", + }, + }, + }, + expected: "All k on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + }, + "All": { + expr: &CollectionExpression{ + Key: "k", + Value: "v", + Type: AllExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"obj"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"v"}, + }, + Operator: 0, + Value: &MatchValue{ + Raw: "hello", + }, + }, + }, + expected: "All (k, v) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + }, + "Any": { + expr: &CollectionExpression{ + Key: "k", + Value: "_", + Type: AnyExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"obj"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"v"}, + }, + Operator: 0, + Value: &MatchValue{ + Raw: "hello", + }, + }, + }, + expected: "Any (k, _) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + }, } for name, tcase := range tests { diff --git a/grammar/grammar.go b/grammar/grammar.go index 7aee78a..fd8a81a 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "math" "os" "sort" @@ -26,13 +25,13 @@ var g = &grammar{ pos: position{line: 12, col: 1, offset: 103}, expr: &choiceExpr{ pos: position{line: 12, col: 10, offset: 112}, - alternatives: []interface{}{ + alternatives: []any{ &actionExpr{ pos: position{line: 12, col: 10, offset: 112}, run: (*parser).callonInput2, expr: &seqExpr{ pos: position{line: 12, col: 10, offset: 112}, - exprs: []interface{}{ + exprs: []any{ &zeroOrOneExpr{ pos: position{line: 12, col: 10, offset: 112}, expr: &ruleRefExpr{ @@ -93,7 +92,7 @@ var g = &grammar{ run: (*parser).callonInput17, expr: &seqExpr{ pos: position{line: 14, col: 5, offset: 180}, - exprs: []interface{}{ + exprs: []any{ &zeroOrOneExpr{ pos: position{line: 14, col: 5, offset: 180}, expr: &ruleRefExpr{ @@ -131,13 +130,13 @@ var g = &grammar{ pos: position{line: 18, col: 1, offset: 233}, expr: &choiceExpr{ pos: position{line: 18, col: 17, offset: 249}, - alternatives: []interface{}{ + alternatives: []any{ &actionExpr{ pos: position{line: 18, col: 17, offset: 249}, run: (*parser).callonOrExpression2, expr: &seqExpr{ pos: position{line: 18, col: 17, offset: 249}, - exprs: []interface{}{ + exprs: []any{ &labeledExpr{ pos: position{line: 18, col: 17, offset: 249}, label: "left", @@ -183,48 +182,72 @@ var g = &grammar{ }, }, }, + &actionExpr{ + pos: position{line: 26, col: 5, offset: 478}, + run: (*parser).callonOrExpression14, + expr: &labeledExpr{ + pos: position{line: 26, col: 5, offset: 478}, + label: "expr", + expr: &ruleRefExpr{ + pos: position{line: 26, col: 10, offset: 483}, + name: "CollectionExpression", + }, + }, + }, + &actionExpr{ + pos: position{line: 28, col: 5, offset: 530}, + run: (*parser).callonOrExpression17, + expr: &labeledExpr{ + pos: position{line: 28, col: 5, offset: 530}, + label: "expr", + expr: &ruleRefExpr{ + pos: position{line: 28, col: 10, offset: 535}, + name: "CollectionExpressionWithKey", + }, + }, + }, }, }, }, { name: "AndExpression", - pos: position{line: 28, col: 1, offset: 477}, + pos: position{line: 32, col: 1, offset: 588}, expr: &choiceExpr{ - pos: position{line: 28, col: 18, offset: 494}, - alternatives: []interface{}{ + pos: position{line: 32, col: 18, offset: 605}, + alternatives: []any{ &actionExpr{ - pos: position{line: 28, col: 18, offset: 494}, + pos: position{line: 32, col: 18, offset: 605}, run: (*parser).callonAndExpression2, expr: &seqExpr{ - pos: position{line: 28, col: 18, offset: 494}, - exprs: []interface{}{ + pos: position{line: 32, col: 18, offset: 605}, + exprs: []any{ &labeledExpr{ - pos: position{line: 28, col: 18, offset: 494}, + pos: position{line: 32, col: 18, offset: 605}, label: "left", expr: &ruleRefExpr{ - pos: position{line: 28, col: 23, offset: 499}, + pos: position{line: 32, col: 23, offset: 610}, name: "NotExpression", }, }, &ruleRefExpr{ - pos: position{line: 28, col: 37, offset: 513}, + pos: position{line: 32, col: 37, offset: 624}, name: "_", }, &litMatcher{ - pos: position{line: 28, col: 39, offset: 515}, + pos: position{line: 32, col: 39, offset: 626}, val: "and", ignoreCase: false, want: "\"and\"", }, &ruleRefExpr{ - pos: position{line: 28, col: 45, offset: 521}, + pos: position{line: 32, col: 45, offset: 632}, name: "_", }, &labeledExpr{ - pos: position{line: 28, col: 47, offset: 523}, + pos: position{line: 32, col: 47, offset: 634}, label: "right", expr: &ruleRefExpr{ - pos: position{line: 28, col: 53, offset: 529}, + pos: position{line: 32, col: 53, offset: 640}, name: "AndExpression", }, }, @@ -232,13 +255,13 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 34, col: 5, offset: 681}, + pos: position{line: 38, col: 5, offset: 792}, run: (*parser).callonAndExpression11, expr: &labeledExpr{ - pos: position{line: 34, col: 5, offset: 681}, + pos: position{line: 38, col: 5, offset: 792}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 34, col: 10, offset: 686}, + pos: position{line: 38, col: 10, offset: 797}, name: "NotExpression", }, }, @@ -248,31 +271,31 @@ var g = &grammar{ }, { name: "NotExpression", - pos: position{line: 38, col: 1, offset: 725}, + pos: position{line: 42, col: 1, offset: 836}, expr: &choiceExpr{ - pos: position{line: 38, col: 18, offset: 742}, - alternatives: []interface{}{ + pos: position{line: 42, col: 18, offset: 853}, + alternatives: []any{ &actionExpr{ - pos: position{line: 38, col: 18, offset: 742}, + pos: position{line: 42, col: 18, offset: 853}, run: (*parser).callonNotExpression2, expr: &seqExpr{ - pos: position{line: 38, col: 18, offset: 742}, - exprs: []interface{}{ + pos: position{line: 42, col: 18, offset: 853}, + exprs: []any{ &litMatcher{ - pos: position{line: 38, col: 18, offset: 742}, + pos: position{line: 42, col: 18, offset: 853}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 38, col: 24, offset: 748}, + pos: position{line: 42, col: 24, offset: 859}, name: "_", }, &labeledExpr{ - pos: position{line: 38, col: 26, offset: 750}, + pos: position{line: 42, col: 26, offset: 861}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 38, col: 31, offset: 755}, + pos: position{line: 42, col: 31, offset: 866}, name: "NotExpression", }, }, @@ -280,13 +303,13 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 49, col: 5, offset: 1142}, + pos: position{line: 53, col: 5, offset: 1253}, run: (*parser).callonNotExpression8, expr: &labeledExpr{ - pos: position{line: 49, col: 5, offset: 1142}, + pos: position{line: 53, col: 5, offset: 1253}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 49, col: 10, offset: 1147}, + pos: position{line: 53, col: 10, offset: 1258}, name: "ParenthesizedExpression", }, }, @@ -294,49 +317,328 @@ var g = &grammar{ }, }, }, + { + name: "CollectionExpression", + pos: position{line: 57, col: 1, offset: 1307}, + expr: &actionExpr{ + pos: position{line: 57, col: 25, offset: 1331}, + run: (*parser).callonCollectionExpression1, + expr: &seqExpr{ + pos: position{line: 57, col: 25, offset: 1331}, + exprs: []any{ + &labeledExpr{ + pos: position{line: 57, col: 25, offset: 1331}, + label: "operator", + expr: &choiceExpr{ + pos: position{line: 57, col: 35, offset: 1341}, + alternatives: []any{ + &litMatcher{ + pos: position{line: 57, col: 35, offset: 1341}, + val: "all", + ignoreCase: false, + want: "\"all\"", + }, + &litMatcher{ + pos: position{line: 57, col: 41, offset: 1347}, + val: "any", + ignoreCase: false, + want: "\"any\"", + }, + }, + }, + }, + &ruleRefExpr{ + pos: position{line: 57, col: 48, offset: 1354}, + name: "_", + }, + &labeledExpr{ + pos: position{line: 57, col: 50, offset: 1356}, + label: "selector", + expr: &ruleRefExpr{ + pos: position{line: 57, col: 59, offset: 1365}, + name: "Selector", + }, + }, + &ruleRefExpr{ + pos: position{line: 57, col: 68, offset: 1374}, + name: "_", + }, + &litMatcher{ + pos: position{line: 57, col: 70, offset: 1376}, + val: "as", + ignoreCase: false, + want: "\"as\"", + }, + &ruleRefExpr{ + pos: position{line: 57, col: 75, offset: 1381}, + name: "_", + }, + &labeledExpr{ + pos: position{line: 57, col: 77, offset: 1383}, + label: "ident", + expr: &choiceExpr{ + pos: position{line: 57, col: 84, offset: 1390}, + alternatives: []any{ + &ruleRefExpr{ + pos: position{line: 57, col: 84, offset: 1390}, + name: "Identifier", + }, + &litMatcher{ + pos: position{line: 57, col: 97, offset: 1403}, + val: "_", + ignoreCase: false, + want: "\"_\"", + }, + }, + }, + }, + &zeroOrOneExpr{ + pos: position{line: 57, col: 102, offset: 1408}, + expr: &ruleRefExpr{ + pos: position{line: 57, col: 102, offset: 1408}, + name: "_", + }, + }, + &litMatcher{ + pos: position{line: 57, col: 105, offset: 1411}, + val: "{", + ignoreCase: false, + want: "\"{\"", + }, + &zeroOrOneExpr{ + pos: position{line: 57, col: 109, offset: 1415}, + expr: &ruleRefExpr{ + pos: position{line: 57, col: 109, offset: 1415}, + name: "_", + }, + }, + &labeledExpr{ + pos: position{line: 57, col: 112, offset: 1418}, + label: "expr", + expr: &ruleRefExpr{ + pos: position{line: 57, col: 117, offset: 1423}, + name: "OrExpression", + }, + }, + &zeroOrOneExpr{ + pos: position{line: 57, col: 130, offset: 1436}, + expr: &ruleRefExpr{ + pos: position{line: 57, col: 130, offset: 1436}, + name: "_", + }, + }, + &litMatcher{ + pos: position{line: 57, col: 133, offset: 1439}, + val: "}", + ignoreCase: false, + want: "\"}\"", + }, + }, + }, + }, + }, + { + name: "CollectionExpressionWithKey", + pos: position{line: 61, col: 1, offset: 1528}, + expr: &actionExpr{ + pos: position{line: 61, col: 32, offset: 1559}, + run: (*parser).callonCollectionExpressionWithKey1, + expr: &seqExpr{ + pos: position{line: 61, col: 32, offset: 1559}, + exprs: []any{ + &labeledExpr{ + pos: position{line: 61, col: 32, offset: 1559}, + label: "operator", + expr: &choiceExpr{ + pos: position{line: 61, col: 42, offset: 1569}, + alternatives: []any{ + &litMatcher{ + pos: position{line: 61, col: 42, offset: 1569}, + val: "all", + ignoreCase: false, + want: "\"all\"", + }, + &litMatcher{ + pos: position{line: 61, col: 48, offset: 1575}, + val: "any", + ignoreCase: false, + want: "\"any\"", + }, + }, + }, + }, + &ruleRefExpr{ + pos: position{line: 61, col: 55, offset: 1582}, + name: "_", + }, + &labeledExpr{ + pos: position{line: 61, col: 57, offset: 1584}, + label: "selector", + expr: &ruleRefExpr{ + pos: position{line: 61, col: 66, offset: 1593}, + name: "Selector", + }, + }, + &ruleRefExpr{ + pos: position{line: 61, col: 75, offset: 1602}, + name: "_", + }, + &litMatcher{ + pos: position{line: 61, col: 77, offset: 1604}, + val: "as", + ignoreCase: false, + want: "\"as\"", + }, + &ruleRefExpr{ + pos: position{line: 61, col: 82, offset: 1609}, + name: "_", + }, + &labeledExpr{ + pos: position{line: 61, col: 84, offset: 1611}, + label: "key", + expr: &choiceExpr{ + pos: position{line: 61, col: 89, offset: 1616}, + alternatives: []any{ + &ruleRefExpr{ + pos: position{line: 61, col: 89, offset: 1616}, + name: "Identifier", + }, + &litMatcher{ + pos: position{line: 61, col: 102, offset: 1629}, + val: "_", + ignoreCase: false, + want: "\"_\"", + }, + }, + }, + }, + &zeroOrOneExpr{ + pos: position{line: 61, col: 107, offset: 1634}, + expr: &ruleRefExpr{ + pos: position{line: 61, col: 107, offset: 1634}, + name: "_", + }, + }, + &litMatcher{ + pos: position{line: 61, col: 110, offset: 1637}, + val: ",", + ignoreCase: false, + want: "\",\"", + }, + &zeroOrOneExpr{ + pos: position{line: 61, col: 114, offset: 1641}, + expr: &ruleRefExpr{ + pos: position{line: 61, col: 114, offset: 1641}, + name: "_", + }, + }, + &labeledExpr{ + pos: position{line: 61, col: 117, offset: 1644}, + label: "value", + expr: &choiceExpr{ + pos: position{line: 61, col: 124, offset: 1651}, + alternatives: []any{ + &ruleRefExpr{ + pos: position{line: 61, col: 124, offset: 1651}, + name: "Identifier", + }, + &litMatcher{ + pos: position{line: 61, col: 137, offset: 1664}, + val: "_", + ignoreCase: false, + want: "\"_\"", + }, + }, + }, + }, + &zeroOrOneExpr{ + pos: position{line: 61, col: 142, offset: 1669}, + expr: &ruleRefExpr{ + pos: position{line: 61, col: 142, offset: 1669}, + name: "_", + }, + }, + &litMatcher{ + pos: position{line: 61, col: 145, offset: 1672}, + val: "{", + ignoreCase: false, + want: "\"{\"", + }, + &zeroOrOneExpr{ + pos: position{line: 61, col: 149, offset: 1676}, + expr: &ruleRefExpr{ + pos: position{line: 61, col: 149, offset: 1676}, + name: "_", + }, + }, + &labeledExpr{ + pos: position{line: 61, col: 152, offset: 1679}, + label: "expr", + expr: &ruleRefExpr{ + pos: position{line: 61, col: 157, offset: 1684}, + name: "OrExpression", + }, + }, + &zeroOrOneExpr{ + pos: position{line: 61, col: 170, offset: 1697}, + expr: &ruleRefExpr{ + pos: position{line: 61, col: 170, offset: 1697}, + name: "_", + }, + }, + &litMatcher{ + pos: position{line: 61, col: 173, offset: 1700}, + val: "}", + ignoreCase: false, + want: "\"}\"", + }, + }, + }, + }, + }, { name: "ParenthesizedExpression", displayName: "\"grouping\"", - pos: position{line: 53, col: 1, offset: 1196}, + pos: position{line: 90, col: 1, offset: 2160}, expr: &choiceExpr{ - pos: position{line: 53, col: 39, offset: 1234}, - alternatives: []interface{}{ + pos: position{line: 90, col: 39, offset: 2198}, + alternatives: []any{ &actionExpr{ - pos: position{line: 53, col: 39, offset: 1234}, + pos: position{line: 90, col: 39, offset: 2198}, run: (*parser).callonParenthesizedExpression2, expr: &seqExpr{ - pos: position{line: 53, col: 39, offset: 1234}, - exprs: []interface{}{ + pos: position{line: 90, col: 39, offset: 2198}, + exprs: []any{ &litMatcher{ - pos: position{line: 53, col: 39, offset: 1234}, + pos: position{line: 90, col: 39, offset: 2198}, val: "(", ignoreCase: false, want: "\"(\"", }, &zeroOrOneExpr{ - pos: position{line: 53, col: 43, offset: 1238}, + pos: position{line: 90, col: 43, offset: 2202}, expr: &ruleRefExpr{ - pos: position{line: 53, col: 43, offset: 1238}, + pos: position{line: 90, col: 43, offset: 2202}, name: "_", }, }, &labeledExpr{ - pos: position{line: 53, col: 46, offset: 1241}, + pos: position{line: 90, col: 46, offset: 2205}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 53, col: 51, offset: 1246}, + pos: position{line: 90, col: 51, offset: 2210}, name: "OrExpression", }, }, &zeroOrOneExpr{ - pos: position{line: 53, col: 64, offset: 1259}, + pos: position{line: 90, col: 64, offset: 2223}, expr: &ruleRefExpr{ - pos: position{line: 53, col: 64, offset: 1259}, + pos: position{line: 90, col: 64, offset: 2223}, name: "_", }, }, &litMatcher{ - pos: position{line: 53, col: 67, offset: 1262}, + pos: position{line: 90, col: 67, offset: 2226}, val: ")", ignoreCase: false, want: "\")\"", @@ -345,55 +647,55 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 55, col: 5, offset: 1292}, + pos: position{line: 92, col: 5, offset: 2256}, run: (*parser).callonParenthesizedExpression12, expr: &labeledExpr{ - pos: position{line: 55, col: 5, offset: 1292}, + pos: position{line: 92, col: 5, offset: 2256}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 55, col: 10, offset: 1297}, + pos: position{line: 92, col: 10, offset: 2261}, name: "MatchExpression", }, }, }, &seqExpr{ - pos: position{line: 57, col: 5, offset: 1339}, - exprs: []interface{}{ + pos: position{line: 94, col: 5, offset: 2303}, + exprs: []any{ &litMatcher{ - pos: position{line: 57, col: 5, offset: 1339}, + pos: position{line: 94, col: 5, offset: 2303}, val: "(", ignoreCase: false, want: "\"(\"", }, &zeroOrOneExpr{ - pos: position{line: 57, col: 9, offset: 1343}, + pos: position{line: 94, col: 9, offset: 2307}, expr: &ruleRefExpr{ - pos: position{line: 57, col: 9, offset: 1343}, + pos: position{line: 94, col: 9, offset: 2307}, name: "_", }, }, &ruleRefExpr{ - pos: position{line: 57, col: 12, offset: 1346}, + pos: position{line: 94, col: 12, offset: 2310}, name: "OrExpression", }, &zeroOrOneExpr{ - pos: position{line: 57, col: 25, offset: 1359}, + pos: position{line: 94, col: 25, offset: 2323}, expr: &ruleRefExpr{ - pos: position{line: 57, col: 25, offset: 1359}, + pos: position{line: 94, col: 25, offset: 2323}, name: "_", }, }, ¬Expr{ - pos: position{line: 57, col: 28, offset: 1362}, + pos: position{line: 94, col: 28, offset: 2326}, expr: &litMatcher{ - pos: position{line: 57, col: 29, offset: 1363}, + pos: position{line: 94, col: 29, offset: 2327}, val: ")", ignoreCase: false, want: "\")\"", }, }, &andCodeExpr{ - pos: position{line: 57, col: 33, offset: 1367}, + pos: position{line: 94, col: 33, offset: 2331}, run: (*parser).callonParenthesizedExpression24, }, }, @@ -404,20 +706,20 @@ var g = &grammar{ { name: "MatchExpression", displayName: "\"match\"", - pos: position{line: 61, col: 1, offset: 1426}, + pos: position{line: 98, col: 1, offset: 2390}, expr: &choiceExpr{ - pos: position{line: 61, col: 28, offset: 1453}, - alternatives: []interface{}{ + pos: position{line: 98, col: 28, offset: 2417}, + alternatives: []any{ &ruleRefExpr{ - pos: position{line: 61, col: 28, offset: 1453}, + pos: position{line: 98, col: 28, offset: 2417}, name: "MatchSelectorOpValue", }, &ruleRefExpr{ - pos: position{line: 61, col: 51, offset: 1476}, + pos: position{line: 98, col: 51, offset: 2440}, name: "MatchSelectorOp", }, &ruleRefExpr{ - pos: position{line: 61, col: 69, offset: 1494}, + pos: position{line: 98, col: 69, offset: 2458}, name: "MatchValueOpSelector", }, }, @@ -426,59 +728,59 @@ var g = &grammar{ { name: "MatchSelectorOpValue", displayName: "\"match\"", - pos: position{line: 63, col: 1, offset: 1516}, + pos: position{line: 100, col: 1, offset: 2480}, expr: &actionExpr{ - pos: position{line: 63, col: 33, offset: 1548}, + pos: position{line: 100, col: 33, offset: 2512}, run: (*parser).callonMatchSelectorOpValue1, expr: &seqExpr{ - pos: position{line: 63, col: 33, offset: 1548}, - exprs: []interface{}{ + pos: position{line: 100, col: 33, offset: 2512}, + exprs: []any{ &labeledExpr{ - pos: position{line: 63, col: 33, offset: 1548}, + pos: position{line: 100, col: 33, offset: 2512}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 63, col: 42, offset: 1557}, + pos: position{line: 100, col: 42, offset: 2521}, name: "Selector", }, }, &labeledExpr{ - pos: position{line: 63, col: 51, offset: 1566}, + pos: position{line: 100, col: 51, offset: 2530}, label: "operator", expr: &choiceExpr{ - pos: position{line: 63, col: 61, offset: 1576}, - alternatives: []interface{}{ + pos: position{line: 100, col: 61, offset: 2540}, + alternatives: []any{ &ruleRefExpr{ - pos: position{line: 63, col: 61, offset: 1576}, + pos: position{line: 100, col: 61, offset: 2540}, name: "MatchEqual", }, &ruleRefExpr{ - pos: position{line: 63, col: 74, offset: 1589}, + pos: position{line: 100, col: 74, offset: 2553}, name: "MatchNotEqual", }, &ruleRefExpr{ - pos: position{line: 63, col: 90, offset: 1605}, + pos: position{line: 100, col: 90, offset: 2569}, name: "MatchContains", }, &ruleRefExpr{ - pos: position{line: 63, col: 106, offset: 1621}, + pos: position{line: 100, col: 106, offset: 2585}, name: "MatchNotContains", }, &ruleRefExpr{ - pos: position{line: 63, col: 125, offset: 1640}, + pos: position{line: 100, col: 125, offset: 2604}, name: "MatchMatches", }, &ruleRefExpr{ - pos: position{line: 63, col: 140, offset: 1655}, + pos: position{line: 100, col: 140, offset: 2619}, name: "MatchNotMatches", }, }, }, }, &labeledExpr{ - pos: position{line: 63, col: 157, offset: 1672}, + pos: position{line: 100, col: 157, offset: 2636}, label: "value", expr: &ruleRefExpr{ - pos: position{line: 63, col: 163, offset: 1678}, + pos: position{line: 100, col: 163, offset: 2642}, name: "Value", }, }, @@ -489,33 +791,33 @@ var g = &grammar{ { name: "MatchSelectorOp", displayName: "\"match\"", - pos: position{line: 67, col: 1, offset: 1816}, + pos: position{line: 104, col: 1, offset: 2780}, expr: &actionExpr{ - pos: position{line: 67, col: 28, offset: 1843}, + pos: position{line: 104, col: 28, offset: 2807}, run: (*parser).callonMatchSelectorOp1, expr: &seqExpr{ - pos: position{line: 67, col: 28, offset: 1843}, - exprs: []interface{}{ + pos: position{line: 104, col: 28, offset: 2807}, + exprs: []any{ &labeledExpr{ - pos: position{line: 67, col: 28, offset: 1843}, + pos: position{line: 104, col: 28, offset: 2807}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 67, col: 37, offset: 1852}, + pos: position{line: 104, col: 37, offset: 2816}, name: "Selector", }, }, &labeledExpr{ - pos: position{line: 67, col: 46, offset: 1861}, + pos: position{line: 104, col: 46, offset: 2825}, label: "operator", expr: &choiceExpr{ - pos: position{line: 67, col: 56, offset: 1871}, - alternatives: []interface{}{ + pos: position{line: 104, col: 56, offset: 2835}, + alternatives: []any{ &ruleRefExpr{ - pos: position{line: 67, col: 56, offset: 1871}, + pos: position{line: 104, col: 56, offset: 2835}, name: "MatchIsEmpty", }, &ruleRefExpr{ - pos: position{line: 67, col: 71, offset: 1886}, + pos: position{line: 104, col: 71, offset: 2850}, name: "MatchIsNotEmpty", }, }, @@ -528,46 +830,46 @@ var g = &grammar{ { name: "MatchValueOpSelector", displayName: "\"match\"", - pos: position{line: 71, col: 1, offset: 2019}, + pos: position{line: 108, col: 1, offset: 2983}, expr: &choiceExpr{ - pos: position{line: 71, col: 33, offset: 2051}, - alternatives: []interface{}{ + pos: position{line: 108, col: 33, offset: 3015}, + alternatives: []any{ &actionExpr{ - pos: position{line: 71, col: 33, offset: 2051}, + pos: position{line: 108, col: 33, offset: 3015}, run: (*parser).callonMatchValueOpSelector2, expr: &seqExpr{ - pos: position{line: 71, col: 33, offset: 2051}, - exprs: []interface{}{ + pos: position{line: 108, col: 33, offset: 3015}, + exprs: []any{ &labeledExpr{ - pos: position{line: 71, col: 33, offset: 2051}, + pos: position{line: 108, col: 33, offset: 3015}, label: "value", expr: &ruleRefExpr{ - pos: position{line: 71, col: 39, offset: 2057}, + pos: position{line: 108, col: 39, offset: 3021}, name: "Value", }, }, &labeledExpr{ - pos: position{line: 71, col: 45, offset: 2063}, + pos: position{line: 108, col: 45, offset: 3027}, label: "operator", expr: &choiceExpr{ - pos: position{line: 71, col: 55, offset: 2073}, - alternatives: []interface{}{ + pos: position{line: 108, col: 55, offset: 3037}, + alternatives: []any{ &ruleRefExpr{ - pos: position{line: 71, col: 55, offset: 2073}, + pos: position{line: 108, col: 55, offset: 3037}, name: "MatchIn", }, &ruleRefExpr{ - pos: position{line: 71, col: 65, offset: 2083}, + pos: position{line: 108, col: 65, offset: 3047}, name: "MatchNotIn", }, }, }, }, &labeledExpr{ - pos: position{line: 71, col: 77, offset: 2095}, + pos: position{line: 108, col: 77, offset: 3059}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 71, col: 86, offset: 2104}, + pos: position{line: 108, col: 86, offset: 3068}, name: "Selector", }, }, @@ -575,38 +877,38 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 73, col: 5, offset: 2246}, - exprs: []interface{}{ + pos: position{line: 110, col: 5, offset: 3210}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 73, col: 5, offset: 2246}, + pos: position{line: 110, col: 5, offset: 3210}, name: "Value", }, &labeledExpr{ - pos: position{line: 73, col: 11, offset: 2252}, + pos: position{line: 110, col: 11, offset: 3216}, label: "operator", expr: &choiceExpr{ - pos: position{line: 73, col: 21, offset: 2262}, - alternatives: []interface{}{ + pos: position{line: 110, col: 21, offset: 3226}, + alternatives: []any{ &ruleRefExpr{ - pos: position{line: 73, col: 21, offset: 2262}, + pos: position{line: 110, col: 21, offset: 3226}, name: "MatchIn", }, &ruleRefExpr{ - pos: position{line: 73, col: 31, offset: 2272}, + pos: position{line: 110, col: 31, offset: 3236}, name: "MatchNotIn", }, }, }, }, ¬Expr{ - pos: position{line: 73, col: 43, offset: 2284}, + pos: position{line: 110, col: 43, offset: 3248}, expr: &ruleRefExpr{ - pos: position{line: 73, col: 44, offset: 2285}, + pos: position{line: 110, col: 44, offset: 3249}, name: "Selector", }, }, &andCodeExpr{ - pos: position{line: 73, col: 53, offset: 2294}, + pos: position{line: 110, col: 53, offset: 3258}, run: (*parser).callonMatchValueOpSelector20, }, }, @@ -616,30 +918,30 @@ var g = &grammar{ }, { name: "MatchEqual", - pos: position{line: 77, col: 1, offset: 2348}, + pos: position{line: 114, col: 1, offset: 3312}, expr: &actionExpr{ - pos: position{line: 77, col: 15, offset: 2362}, + pos: position{line: 114, col: 15, offset: 3326}, run: (*parser).callonMatchEqual1, expr: &seqExpr{ - pos: position{line: 77, col: 15, offset: 2362}, - exprs: []interface{}{ + pos: position{line: 114, col: 15, offset: 3326}, + exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 77, col: 15, offset: 2362}, + pos: position{line: 114, col: 15, offset: 3326}, expr: &ruleRefExpr{ - pos: position{line: 77, col: 15, offset: 2362}, + pos: position{line: 114, col: 15, offset: 3326}, name: "_", }, }, &litMatcher{ - pos: position{line: 77, col: 18, offset: 2365}, + pos: position{line: 114, col: 18, offset: 3329}, val: "==", ignoreCase: false, want: "\"==\"", }, &zeroOrOneExpr{ - pos: position{line: 77, col: 23, offset: 2370}, + pos: position{line: 114, col: 23, offset: 3334}, expr: &ruleRefExpr{ - pos: position{line: 77, col: 23, offset: 2370}, + pos: position{line: 114, col: 23, offset: 3334}, name: "_", }, }, @@ -649,30 +951,30 @@ var g = &grammar{ }, { name: "MatchNotEqual", - pos: position{line: 80, col: 1, offset: 2403}, + pos: position{line: 117, col: 1, offset: 3367}, expr: &actionExpr{ - pos: position{line: 80, col: 18, offset: 2420}, + pos: position{line: 117, col: 18, offset: 3384}, run: (*parser).callonMatchNotEqual1, expr: &seqExpr{ - pos: position{line: 80, col: 18, offset: 2420}, - exprs: []interface{}{ + pos: position{line: 117, col: 18, offset: 3384}, + exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 80, col: 18, offset: 2420}, + pos: position{line: 117, col: 18, offset: 3384}, expr: &ruleRefExpr{ - pos: position{line: 80, col: 18, offset: 2420}, + pos: position{line: 117, col: 18, offset: 3384}, name: "_", }, }, &litMatcher{ - pos: position{line: 80, col: 21, offset: 2423}, + pos: position{line: 117, col: 21, offset: 3387}, val: "!=", ignoreCase: false, want: "\"!=\"", }, &zeroOrOneExpr{ - pos: position{line: 80, col: 26, offset: 2428}, + pos: position{line: 117, col: 26, offset: 3392}, expr: &ruleRefExpr{ - pos: position{line: 80, col: 26, offset: 2428}, + pos: position{line: 117, col: 26, offset: 3392}, name: "_", }, }, @@ -682,29 +984,29 @@ var g = &grammar{ }, { name: "MatchIsEmpty", - pos: position{line: 83, col: 1, offset: 2464}, + pos: position{line: 120, col: 1, offset: 3428}, expr: &actionExpr{ - pos: position{line: 83, col: 17, offset: 2480}, + pos: position{line: 120, col: 17, offset: 3444}, run: (*parser).callonMatchIsEmpty1, expr: &seqExpr{ - pos: position{line: 83, col: 17, offset: 2480}, - exprs: []interface{}{ + pos: position{line: 120, col: 17, offset: 3444}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 83, col: 17, offset: 2480}, + pos: position{line: 120, col: 17, offset: 3444}, name: "_", }, &litMatcher{ - pos: position{line: 83, col: 19, offset: 2482}, + pos: position{line: 120, col: 19, offset: 3446}, val: "is", ignoreCase: false, want: "\"is\"", }, &ruleRefExpr{ - pos: position{line: 83, col: 24, offset: 2487}, + pos: position{line: 120, col: 24, offset: 3451}, name: "_", }, &litMatcher{ - pos: position{line: 83, col: 26, offset: 2489}, + pos: position{line: 120, col: 26, offset: 3453}, val: "empty", ignoreCase: false, want: "\"empty\"", @@ -715,39 +1017,39 @@ var g = &grammar{ }, { name: "MatchIsNotEmpty", - pos: position{line: 86, col: 1, offset: 2529}, + pos: position{line: 123, col: 1, offset: 3493}, expr: &actionExpr{ - pos: position{line: 86, col: 20, offset: 2548}, + pos: position{line: 123, col: 20, offset: 3512}, run: (*parser).callonMatchIsNotEmpty1, expr: &seqExpr{ - pos: position{line: 86, col: 20, offset: 2548}, - exprs: []interface{}{ + pos: position{line: 123, col: 20, offset: 3512}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 86, col: 20, offset: 2548}, + pos: position{line: 123, col: 20, offset: 3512}, name: "_", }, &litMatcher{ - pos: position{line: 86, col: 21, offset: 2549}, + pos: position{line: 123, col: 21, offset: 3513}, val: "is", ignoreCase: false, want: "\"is\"", }, &ruleRefExpr{ - pos: position{line: 86, col: 26, offset: 2554}, + pos: position{line: 123, col: 26, offset: 3518}, name: "_", }, &litMatcher{ - pos: position{line: 86, col: 28, offset: 2556}, + pos: position{line: 123, col: 28, offset: 3520}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 86, col: 34, offset: 2562}, + pos: position{line: 123, col: 34, offset: 3526}, name: "_", }, &litMatcher{ - pos: position{line: 86, col: 36, offset: 2564}, + pos: position{line: 123, col: 36, offset: 3528}, val: "empty", ignoreCase: false, want: "\"empty\"", @@ -758,25 +1060,25 @@ var g = &grammar{ }, { name: "MatchIn", - pos: position{line: 89, col: 1, offset: 2607}, + pos: position{line: 126, col: 1, offset: 3571}, expr: &actionExpr{ - pos: position{line: 89, col: 12, offset: 2618}, + pos: position{line: 126, col: 12, offset: 3582}, run: (*parser).callonMatchIn1, expr: &seqExpr{ - pos: position{line: 89, col: 12, offset: 2618}, - exprs: []interface{}{ + pos: position{line: 126, col: 12, offset: 3582}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 89, col: 12, offset: 2618}, + pos: position{line: 126, col: 12, offset: 3582}, name: "_", }, &litMatcher{ - pos: position{line: 89, col: 14, offset: 2620}, + pos: position{line: 126, col: 14, offset: 3584}, val: "in", ignoreCase: false, want: "\"in\"", }, &ruleRefExpr{ - pos: position{line: 89, col: 19, offset: 2625}, + pos: position{line: 126, col: 19, offset: 3589}, name: "_", }, }, @@ -785,35 +1087,35 @@ var g = &grammar{ }, { name: "MatchNotIn", - pos: position{line: 92, col: 1, offset: 2654}, + pos: position{line: 129, col: 1, offset: 3618}, expr: &actionExpr{ - pos: position{line: 92, col: 15, offset: 2668}, + pos: position{line: 129, col: 15, offset: 3632}, run: (*parser).callonMatchNotIn1, expr: &seqExpr{ - pos: position{line: 92, col: 15, offset: 2668}, - exprs: []interface{}{ + pos: position{line: 129, col: 15, offset: 3632}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 92, col: 15, offset: 2668}, + pos: position{line: 129, col: 15, offset: 3632}, name: "_", }, &litMatcher{ - pos: position{line: 92, col: 17, offset: 2670}, + pos: position{line: 129, col: 17, offset: 3634}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 92, col: 23, offset: 2676}, + pos: position{line: 129, col: 23, offset: 3640}, name: "_", }, &litMatcher{ - pos: position{line: 92, col: 25, offset: 2678}, + pos: position{line: 129, col: 25, offset: 3642}, val: "in", ignoreCase: false, want: "\"in\"", }, &ruleRefExpr{ - pos: position{line: 92, col: 30, offset: 2683}, + pos: position{line: 129, col: 30, offset: 3647}, name: "_", }, }, @@ -822,25 +1124,25 @@ var g = &grammar{ }, { name: "MatchContains", - pos: position{line: 95, col: 1, offset: 2715}, + pos: position{line: 132, col: 1, offset: 3679}, expr: &actionExpr{ - pos: position{line: 95, col: 18, offset: 2732}, + pos: position{line: 132, col: 18, offset: 3696}, run: (*parser).callonMatchContains1, expr: &seqExpr{ - pos: position{line: 95, col: 18, offset: 2732}, - exprs: []interface{}{ + pos: position{line: 132, col: 18, offset: 3696}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 95, col: 18, offset: 2732}, + pos: position{line: 132, col: 18, offset: 3696}, name: "_", }, &litMatcher{ - pos: position{line: 95, col: 20, offset: 2734}, + pos: position{line: 132, col: 20, offset: 3698}, val: "contains", ignoreCase: false, want: "\"contains\"", }, &ruleRefExpr{ - pos: position{line: 95, col: 31, offset: 2745}, + pos: position{line: 132, col: 31, offset: 3709}, name: "_", }, }, @@ -849,35 +1151,35 @@ var g = &grammar{ }, { name: "MatchNotContains", - pos: position{line: 98, col: 1, offset: 2774}, + pos: position{line: 135, col: 1, offset: 3738}, expr: &actionExpr{ - pos: position{line: 98, col: 21, offset: 2794}, + pos: position{line: 135, col: 21, offset: 3758}, run: (*parser).callonMatchNotContains1, expr: &seqExpr{ - pos: position{line: 98, col: 21, offset: 2794}, - exprs: []interface{}{ + pos: position{line: 135, col: 21, offset: 3758}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 98, col: 21, offset: 2794}, + pos: position{line: 135, col: 21, offset: 3758}, name: "_", }, &litMatcher{ - pos: position{line: 98, col: 23, offset: 2796}, + pos: position{line: 135, col: 23, offset: 3760}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 98, col: 29, offset: 2802}, + pos: position{line: 135, col: 29, offset: 3766}, name: "_", }, &litMatcher{ - pos: position{line: 98, col: 31, offset: 2804}, + pos: position{line: 135, col: 31, offset: 3768}, val: "contains", ignoreCase: false, want: "\"contains\"", }, &ruleRefExpr{ - pos: position{line: 98, col: 42, offset: 2815}, + pos: position{line: 135, col: 42, offset: 3779}, name: "_", }, }, @@ -886,25 +1188,25 @@ var g = &grammar{ }, { name: "MatchMatches", - pos: position{line: 101, col: 1, offset: 2847}, + pos: position{line: 138, col: 1, offset: 3811}, expr: &actionExpr{ - pos: position{line: 101, col: 17, offset: 2863}, + pos: position{line: 138, col: 17, offset: 3827}, run: (*parser).callonMatchMatches1, expr: &seqExpr{ - pos: position{line: 101, col: 17, offset: 2863}, - exprs: []interface{}{ + pos: position{line: 138, col: 17, offset: 3827}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 101, col: 17, offset: 2863}, + pos: position{line: 138, col: 17, offset: 3827}, name: "_", }, &litMatcher{ - pos: position{line: 101, col: 19, offset: 2865}, + pos: position{line: 138, col: 19, offset: 3829}, val: "matches", ignoreCase: false, want: "\"matches\"", }, &ruleRefExpr{ - pos: position{line: 101, col: 29, offset: 2875}, + pos: position{line: 138, col: 29, offset: 3839}, name: "_", }, }, @@ -913,35 +1215,35 @@ var g = &grammar{ }, { name: "MatchNotMatches", - pos: position{line: 104, col: 1, offset: 2909}, + pos: position{line: 141, col: 1, offset: 3873}, expr: &actionExpr{ - pos: position{line: 104, col: 20, offset: 2928}, + pos: position{line: 141, col: 20, offset: 3892}, run: (*parser).callonMatchNotMatches1, expr: &seqExpr{ - pos: position{line: 104, col: 20, offset: 2928}, - exprs: []interface{}{ + pos: position{line: 141, col: 20, offset: 3892}, + exprs: []any{ &ruleRefExpr{ - pos: position{line: 104, col: 20, offset: 2928}, + pos: position{line: 141, col: 20, offset: 3892}, name: "_", }, &litMatcher{ - pos: position{line: 104, col: 22, offset: 2930}, + pos: position{line: 141, col: 22, offset: 3894}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 104, col: 28, offset: 2936}, + pos: position{line: 141, col: 28, offset: 3900}, name: "_", }, &litMatcher{ - pos: position{line: 104, col: 30, offset: 2938}, + pos: position{line: 141, col: 30, offset: 3902}, val: "matches", ignoreCase: false, want: "\"matches\"", }, &ruleRefExpr{ - pos: position{line: 104, col: 40, offset: 2948}, + pos: position{line: 141, col: 40, offset: 3912}, name: "_", }, }, @@ -951,31 +1253,31 @@ var g = &grammar{ { name: "Selector", displayName: "\"selector\"", - pos: position{line: 108, col: 1, offset: 2986}, + pos: position{line: 145, col: 1, offset: 3950}, expr: &choiceExpr{ - pos: position{line: 108, col: 24, offset: 3009}, - alternatives: []interface{}{ + pos: position{line: 145, col: 24, offset: 3973}, + alternatives: []any{ &actionExpr{ - pos: position{line: 108, col: 24, offset: 3009}, + pos: position{line: 145, col: 24, offset: 3973}, run: (*parser).callonSelector2, expr: &seqExpr{ - pos: position{line: 108, col: 24, offset: 3009}, - exprs: []interface{}{ + pos: position{line: 145, col: 24, offset: 3973}, + exprs: []any{ &labeledExpr{ - pos: position{line: 108, col: 24, offset: 3009}, + pos: position{line: 145, col: 24, offset: 3973}, label: "first", expr: &ruleRefExpr{ - pos: position{line: 108, col: 30, offset: 3015}, + pos: position{line: 145, col: 30, offset: 3979}, name: "Identifier", }, }, &labeledExpr{ - pos: position{line: 108, col: 41, offset: 3026}, + pos: position{line: 145, col: 41, offset: 3990}, label: "rest", expr: &zeroOrMoreExpr{ - pos: position{line: 108, col: 46, offset: 3031}, + pos: position{line: 145, col: 46, offset: 3995}, expr: &ruleRefExpr{ - pos: position{line: 108, col: 46, offset: 3031}, + pos: position{line: 145, col: 46, offset: 3995}, name: "SelectorOrIndex", }, }, @@ -984,30 +1286,30 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 119, col: 5, offset: 3295}, + pos: position{line: 156, col: 5, offset: 4259}, run: (*parser).callonSelector9, expr: &seqExpr{ - pos: position{line: 119, col: 5, offset: 3295}, - exprs: []interface{}{ + pos: position{line: 156, col: 5, offset: 4259}, + exprs: []any{ &litMatcher{ - pos: position{line: 119, col: 5, offset: 3295}, + pos: position{line: 156, col: 5, offset: 4259}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &labeledExpr{ - pos: position{line: 119, col: 9, offset: 3299}, + pos: position{line: 156, col: 9, offset: 4263}, label: "ptrsegs", expr: &zeroOrMoreExpr{ - pos: position{line: 119, col: 17, offset: 3307}, + pos: position{line: 156, col: 17, offset: 4271}, expr: &ruleRefExpr{ - pos: position{line: 119, col: 17, offset: 3307}, + pos: position{line: 156, col: 17, offset: 4271}, name: "JsonPointerSegment", }, }, }, &litMatcher{ - pos: position{line: 119, col: 37, offset: 3327}, + pos: position{line: 156, col: 37, offset: 4291}, val: "\"", ignoreCase: false, want: "\"\\\"\"", @@ -1020,26 +1322,26 @@ var g = &grammar{ }, { name: "JsonPointerSegment", - pos: position{line: 140, col: 1, offset: 3805}, + pos: position{line: 177, col: 1, offset: 4769}, expr: &actionExpr{ - pos: position{line: 140, col: 23, offset: 3827}, + pos: position{line: 177, col: 23, offset: 4791}, run: (*parser).callonJsonPointerSegment1, expr: &seqExpr{ - pos: position{line: 140, col: 23, offset: 3827}, - exprs: []interface{}{ + pos: position{line: 177, col: 23, offset: 4791}, + exprs: []any{ &litMatcher{ - pos: position{line: 140, col: 23, offset: 3827}, + pos: position{line: 177, col: 23, offset: 4791}, val: "/", ignoreCase: false, want: "\"/\"", }, &labeledExpr{ - pos: position{line: 140, col: 27, offset: 3831}, + pos: position{line: 177, col: 27, offset: 4795}, label: "ident", expr: &oneOrMoreExpr{ - pos: position{line: 140, col: 33, offset: 3837}, + pos: position{line: 177, col: 33, offset: 4801}, expr: &charClassMatcher{ - pos: position{line: 140, col: 33, offset: 3837}, + pos: position{line: 177, col: 33, offset: 4801}, val: "[\\pL\\pN-_.~:|]", chars: []rune{'-', '_', '.', '~', ':', '|'}, classes: []*unicode.RangeTable{rangeTable("L"), rangeTable("N")}, @@ -1054,24 +1356,24 @@ var g = &grammar{ }, { name: "Identifier", - pos: position{line: 144, col: 1, offset: 3892}, + pos: position{line: 181, col: 1, offset: 4856}, expr: &actionExpr{ - pos: position{line: 144, col: 15, offset: 3906}, + pos: position{line: 181, col: 15, offset: 4870}, run: (*parser).callonIdentifier1, expr: &seqExpr{ - pos: position{line: 144, col: 15, offset: 3906}, - exprs: []interface{}{ + pos: position{line: 181, col: 15, offset: 4870}, + exprs: []any{ &charClassMatcher{ - pos: position{line: 144, col: 15, offset: 3906}, + pos: position{line: 181, col: 15, offset: 4870}, val: "[a-zA-Z]", ranges: []rune{'a', 'z', 'A', 'Z'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 144, col: 24, offset: 3915}, + pos: position{line: 181, col: 24, offset: 4879}, expr: &charClassMatcher{ - pos: position{line: 144, col: 24, offset: 3915}, + pos: position{line: 181, col: 24, offset: 4879}, val: "[a-zA-Z0-9_/]", chars: []rune{'_', '/'}, ranges: []rune{'a', 'z', 'A', 'Z', '0', '9'}, @@ -1085,27 +1387,27 @@ var g = &grammar{ }, { name: "SelectorOrIndex", - pos: position{line: 148, col: 1, offset: 3965}, + pos: position{line: 185, col: 1, offset: 4929}, expr: &choiceExpr{ - pos: position{line: 148, col: 20, offset: 3984}, - alternatives: []interface{}{ + pos: position{line: 185, col: 20, offset: 4948}, + alternatives: []any{ &actionExpr{ - pos: position{line: 148, col: 20, offset: 3984}, + pos: position{line: 185, col: 20, offset: 4948}, run: (*parser).callonSelectorOrIndex2, expr: &seqExpr{ - pos: position{line: 148, col: 20, offset: 3984}, - exprs: []interface{}{ + pos: position{line: 185, col: 20, offset: 4948}, + exprs: []any{ &litMatcher{ - pos: position{line: 148, col: 20, offset: 3984}, + pos: position{line: 185, col: 20, offset: 4948}, val: ".", ignoreCase: false, want: "\".\"", }, &labeledExpr{ - pos: position{line: 148, col: 24, offset: 3988}, + pos: position{line: 185, col: 24, offset: 4952}, label: "ident", expr: &ruleRefExpr{ - pos: position{line: 148, col: 30, offset: 3994}, + pos: position{line: 185, col: 30, offset: 4958}, name: "Identifier", }, }, @@ -1113,36 +1415,36 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 150, col: 5, offset: 4032}, + pos: position{line: 187, col: 5, offset: 4996}, run: (*parser).callonSelectorOrIndex7, expr: &labeledExpr{ - pos: position{line: 150, col: 5, offset: 4032}, + pos: position{line: 187, col: 5, offset: 4996}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 150, col: 10, offset: 4037}, + pos: position{line: 187, col: 10, offset: 5001}, name: "IndexExpression", }, }, }, &actionExpr{ - pos: position{line: 152, col: 5, offset: 4079}, + pos: position{line: 189, col: 5, offset: 5043}, run: (*parser).callonSelectorOrIndex10, expr: &seqExpr{ - pos: position{line: 152, col: 5, offset: 4079}, - exprs: []interface{}{ + pos: position{line: 189, col: 5, offset: 5043}, + exprs: []any{ &litMatcher{ - pos: position{line: 152, col: 5, offset: 4079}, + pos: position{line: 189, col: 5, offset: 5043}, val: ".", ignoreCase: false, want: "\".\"", }, &labeledExpr{ - pos: position{line: 152, col: 9, offset: 4083}, + pos: position{line: 189, col: 9, offset: 5047}, label: "idx", expr: &oneOrMoreExpr{ - pos: position{line: 152, col: 13, offset: 4087}, + pos: position{line: 189, col: 13, offset: 5051}, expr: &charClassMatcher{ - pos: position{line: 152, col: 13, offset: 4087}, + pos: position{line: 189, col: 13, offset: 5051}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1159,46 +1461,46 @@ var g = &grammar{ { name: "IndexExpression", displayName: "\"index\"", - pos: position{line: 156, col: 1, offset: 4133}, + pos: position{line: 193, col: 1, offset: 5097}, expr: &choiceExpr{ - pos: position{line: 156, col: 28, offset: 4160}, - alternatives: []interface{}{ + pos: position{line: 193, col: 28, offset: 5124}, + alternatives: []any{ &actionExpr{ - pos: position{line: 156, col: 28, offset: 4160}, + pos: position{line: 193, col: 28, offset: 5124}, run: (*parser).callonIndexExpression2, expr: &seqExpr{ - pos: position{line: 156, col: 28, offset: 4160}, - exprs: []interface{}{ + pos: position{line: 193, col: 28, offset: 5124}, + exprs: []any{ &litMatcher{ - pos: position{line: 156, col: 28, offset: 4160}, + pos: position{line: 193, col: 28, offset: 5124}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 156, col: 32, offset: 4164}, + pos: position{line: 193, col: 32, offset: 5128}, expr: &ruleRefExpr{ - pos: position{line: 156, col: 32, offset: 4164}, + pos: position{line: 193, col: 32, offset: 5128}, name: "_", }, }, &labeledExpr{ - pos: position{line: 156, col: 35, offset: 4167}, + pos: position{line: 193, col: 35, offset: 5131}, label: "lit", expr: &ruleRefExpr{ - pos: position{line: 156, col: 39, offset: 4171}, + pos: position{line: 193, col: 39, offset: 5135}, name: "StringLiteral", }, }, &zeroOrOneExpr{ - pos: position{line: 156, col: 53, offset: 4185}, + pos: position{line: 193, col: 53, offset: 5149}, expr: &ruleRefExpr{ - pos: position{line: 156, col: 53, offset: 4185}, + pos: position{line: 193, col: 53, offset: 5149}, name: "_", }, }, &litMatcher{ - pos: position{line: 156, col: 56, offset: 4188}, + pos: position{line: 193, col: 56, offset: 5152}, val: "]", ignoreCase: false, want: "\"]\"", @@ -1207,72 +1509,72 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 158, col: 5, offset: 4217}, - exprs: []interface{}{ + pos: position{line: 195, col: 5, offset: 5181}, + exprs: []any{ &litMatcher{ - pos: position{line: 158, col: 5, offset: 4217}, + pos: position{line: 195, col: 5, offset: 5181}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 158, col: 9, offset: 4221}, + pos: position{line: 195, col: 9, offset: 5185}, expr: &ruleRefExpr{ - pos: position{line: 158, col: 9, offset: 4221}, + pos: position{line: 195, col: 9, offset: 5185}, name: "_", }, }, ¬Expr{ - pos: position{line: 158, col: 12, offset: 4224}, + pos: position{line: 195, col: 12, offset: 5188}, expr: &ruleRefExpr{ - pos: position{line: 158, col: 13, offset: 4225}, + pos: position{line: 195, col: 13, offset: 5189}, name: "StringLiteral", }, }, &andCodeExpr{ - pos: position{line: 158, col: 27, offset: 4239}, + pos: position{line: 195, col: 27, offset: 5203}, run: (*parser).callonIndexExpression18, }, }, }, &seqExpr{ - pos: position{line: 160, col: 5, offset: 4291}, - exprs: []interface{}{ + pos: position{line: 197, col: 5, offset: 5255}, + exprs: []any{ &litMatcher{ - pos: position{line: 160, col: 5, offset: 4291}, + pos: position{line: 197, col: 5, offset: 5255}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 160, col: 9, offset: 4295}, + pos: position{line: 197, col: 9, offset: 5259}, expr: &ruleRefExpr{ - pos: position{line: 160, col: 9, offset: 4295}, + pos: position{line: 197, col: 9, offset: 5259}, name: "_", }, }, &ruleRefExpr{ - pos: position{line: 160, col: 12, offset: 4298}, + pos: position{line: 197, col: 12, offset: 5262}, name: "StringLiteral", }, &zeroOrOneExpr{ - pos: position{line: 160, col: 26, offset: 4312}, + pos: position{line: 197, col: 26, offset: 5276}, expr: &ruleRefExpr{ - pos: position{line: 160, col: 26, offset: 4312}, + pos: position{line: 197, col: 26, offset: 5276}, name: "_", }, }, ¬Expr{ - pos: position{line: 160, col: 29, offset: 4315}, + pos: position{line: 197, col: 29, offset: 5279}, expr: &litMatcher{ - pos: position{line: 160, col: 30, offset: 4316}, + pos: position{line: 197, col: 30, offset: 5280}, val: "]", ignoreCase: false, want: "\"]\"", }, }, &andCodeExpr{ - pos: position{line: 160, col: 34, offset: 4320}, + pos: position{line: 197, col: 34, offset: 5284}, run: (*parser).callonIndexExpression28, }, }, @@ -1283,42 +1585,42 @@ var g = &grammar{ { name: "Value", displayName: "\"value\"", - pos: position{line: 164, col: 1, offset: 4383}, + pos: position{line: 201, col: 1, offset: 5347}, expr: &choiceExpr{ - pos: position{line: 164, col: 18, offset: 4400}, - alternatives: []interface{}{ + pos: position{line: 201, col: 18, offset: 5364}, + alternatives: []any{ &actionExpr{ - pos: position{line: 164, col: 18, offset: 4400}, + pos: position{line: 201, col: 18, offset: 5364}, run: (*parser).callonValue2, expr: &labeledExpr{ - pos: position{line: 164, col: 18, offset: 4400}, + pos: position{line: 201, col: 18, offset: 5364}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 164, col: 27, offset: 4409}, + pos: position{line: 201, col: 27, offset: 5373}, name: "Selector", }, }, }, &actionExpr{ - pos: position{line: 166, col: 5, offset: 4485}, + pos: position{line: 203, col: 5, offset: 5449}, run: (*parser).callonValue5, expr: &labeledExpr{ - pos: position{line: 166, col: 5, offset: 4485}, + pos: position{line: 203, col: 5, offset: 5449}, label: "n", expr: &ruleRefExpr{ - pos: position{line: 166, col: 7, offset: 4487}, + pos: position{line: 203, col: 7, offset: 5451}, name: "NumberLiteral", }, }, }, &actionExpr{ - pos: position{line: 168, col: 5, offset: 4551}, + pos: position{line: 205, col: 5, offset: 5515}, run: (*parser).callonValue8, expr: &labeledExpr{ - pos: position{line: 168, col: 5, offset: 4551}, + pos: position{line: 205, col: 5, offset: 5515}, label: "s", expr: &ruleRefExpr{ - pos: position{line: 168, col: 7, offset: 4553}, + pos: position{line: 205, col: 7, offset: 5517}, name: "StringLiteral", }, }, @@ -1329,33 +1631,33 @@ var g = &grammar{ { name: "NumberLiteral", displayName: "\"number\"", - pos: position{line: 172, col: 1, offset: 4616}, + pos: position{line: 209, col: 1, offset: 5580}, expr: &choiceExpr{ - pos: position{line: 172, col: 27, offset: 4642}, - alternatives: []interface{}{ + pos: position{line: 209, col: 27, offset: 5606}, + alternatives: []any{ &actionExpr{ - pos: position{line: 172, col: 27, offset: 4642}, + pos: position{line: 209, col: 27, offset: 5606}, run: (*parser).callonNumberLiteral2, expr: &seqExpr{ - pos: position{line: 172, col: 27, offset: 4642}, - exprs: []interface{}{ + pos: position{line: 209, col: 27, offset: 5606}, + exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 172, col: 27, offset: 4642}, + pos: position{line: 209, col: 27, offset: 5606}, expr: &litMatcher{ - pos: position{line: 172, col: 27, offset: 4642}, + pos: position{line: 209, col: 27, offset: 5606}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &ruleRefExpr{ - pos: position{line: 172, col: 32, offset: 4647}, + pos: position{line: 209, col: 32, offset: 5611}, name: "IntegerOrFloat", }, &andExpr{ - pos: position{line: 172, col: 47, offset: 4662}, + pos: position{line: 209, col: 47, offset: 5626}, expr: &ruleRefExpr{ - pos: position{line: 172, col: 48, offset: 4663}, + pos: position{line: 209, col: 48, offset: 5627}, name: "AfterNumbers", }, }, @@ -1363,30 +1665,30 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 174, col: 5, offset: 4712}, - exprs: []interface{}{ + pos: position{line: 211, col: 5, offset: 5676}, + exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 174, col: 5, offset: 4712}, + pos: position{line: 211, col: 5, offset: 5676}, expr: &litMatcher{ - pos: position{line: 174, col: 5, offset: 4712}, + pos: position{line: 211, col: 5, offset: 5676}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &ruleRefExpr{ - pos: position{line: 174, col: 10, offset: 4717}, + pos: position{line: 211, col: 10, offset: 5681}, name: "IntegerOrFloat", }, ¬Expr{ - pos: position{line: 174, col: 25, offset: 4732}, + pos: position{line: 211, col: 25, offset: 5696}, expr: &ruleRefExpr{ - pos: position{line: 174, col: 26, offset: 4733}, + pos: position{line: 211, col: 26, offset: 5697}, name: "AfterNumbers", }, }, &andCodeExpr{ - pos: position{line: 174, col: 39, offset: 4746}, + pos: position{line: 211, col: 39, offset: 5710}, run: (*parser).callonNumberLiteral15, }, }, @@ -1396,22 +1698,22 @@ var g = &grammar{ }, { name: "AfterNumbers", - pos: position{line: 178, col: 1, offset: 4806}, + pos: position{line: 215, col: 1, offset: 5770}, expr: &andExpr{ - pos: position{line: 178, col: 17, offset: 4822}, + pos: position{line: 215, col: 17, offset: 5786}, expr: &choiceExpr{ - pos: position{line: 178, col: 19, offset: 4824}, - alternatives: []interface{}{ + pos: position{line: 215, col: 19, offset: 5788}, + alternatives: []any{ &ruleRefExpr{ - pos: position{line: 178, col: 19, offset: 4824}, + pos: position{line: 215, col: 19, offset: 5788}, name: "_", }, &ruleRefExpr{ - pos: position{line: 178, col: 23, offset: 4828}, + pos: position{line: 215, col: 23, offset: 5792}, name: "EOF", }, &litMatcher{ - pos: position{line: 178, col: 29, offset: 4834}, + pos: position{line: 215, col: 29, offset: 5798}, val: ")", ignoreCase: false, want: "\")\"", @@ -1422,33 +1724,33 @@ var g = &grammar{ }, { name: "IntegerOrFloat", - pos: position{line: 180, col: 1, offset: 4840}, + pos: position{line: 217, col: 1, offset: 5804}, expr: &seqExpr{ - pos: position{line: 180, col: 19, offset: 4858}, - exprs: []interface{}{ + pos: position{line: 217, col: 19, offset: 5822}, + exprs: []any{ &choiceExpr{ - pos: position{line: 180, col: 20, offset: 4859}, - alternatives: []interface{}{ + pos: position{line: 217, col: 20, offset: 5823}, + alternatives: []any{ &litMatcher{ - pos: position{line: 180, col: 20, offset: 4859}, + pos: position{line: 217, col: 20, offset: 5823}, val: "0", ignoreCase: false, want: "\"0\"", }, &seqExpr{ - pos: position{line: 180, col: 26, offset: 4865}, - exprs: []interface{}{ + pos: position{line: 217, col: 26, offset: 5829}, + exprs: []any{ &charClassMatcher{ - pos: position{line: 180, col: 26, offset: 4865}, + pos: position{line: 217, col: 26, offset: 5829}, val: "[1-9]", ranges: []rune{'1', '9'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 180, col: 31, offset: 4870}, + pos: position{line: 217, col: 31, offset: 5834}, expr: &charClassMatcher{ - pos: position{line: 180, col: 31, offset: 4870}, + pos: position{line: 217, col: 31, offset: 5834}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1460,20 +1762,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 180, col: 39, offset: 4878}, + pos: position{line: 217, col: 39, offset: 5842}, expr: &seqExpr{ - pos: position{line: 180, col: 40, offset: 4879}, - exprs: []interface{}{ + pos: position{line: 217, col: 40, offset: 5843}, + exprs: []any{ &litMatcher{ - pos: position{line: 180, col: 40, offset: 4879}, + pos: position{line: 217, col: 40, offset: 5843}, val: ".", ignoreCase: false, want: "\".\"", }, &oneOrMoreExpr{ - pos: position{line: 180, col: 44, offset: 4883}, + pos: position{line: 217, col: 44, offset: 5847}, expr: &charClassMatcher{ - pos: position{line: 180, col: 44, offset: 4883}, + pos: position{line: 217, col: 44, offset: 5847}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1489,34 +1791,34 @@ var g = &grammar{ { name: "StringLiteral", displayName: "\"string\"", - pos: position{line: 182, col: 1, offset: 4893}, + pos: position{line: 219, col: 1, offset: 5857}, expr: &choiceExpr{ - pos: position{line: 182, col: 27, offset: 4919}, - alternatives: []interface{}{ + pos: position{line: 219, col: 27, offset: 5883}, + alternatives: []any{ &actionExpr{ - pos: position{line: 182, col: 27, offset: 4919}, + pos: position{line: 219, col: 27, offset: 5883}, run: (*parser).callonStringLiteral2, expr: &choiceExpr{ - pos: position{line: 182, col: 28, offset: 4920}, - alternatives: []interface{}{ + pos: position{line: 219, col: 28, offset: 5884}, + alternatives: []any{ &seqExpr{ - pos: position{line: 182, col: 28, offset: 4920}, - exprs: []interface{}{ + pos: position{line: 219, col: 28, offset: 5884}, + exprs: []any{ &litMatcher{ - pos: position{line: 182, col: 28, offset: 4920}, + pos: position{line: 219, col: 28, offset: 5884}, val: "`", ignoreCase: false, want: "\"`\"", }, &zeroOrMoreExpr{ - pos: position{line: 182, col: 32, offset: 4924}, + pos: position{line: 219, col: 32, offset: 5888}, expr: &ruleRefExpr{ - pos: position{line: 182, col: 32, offset: 4924}, + pos: position{line: 219, col: 32, offset: 5888}, name: "RawStringChar", }, }, &litMatcher{ - pos: position{line: 182, col: 47, offset: 4939}, + pos: position{line: 219, col: 47, offset: 5903}, val: "`", ignoreCase: false, want: "\"`\"", @@ -1524,23 +1826,23 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 182, col: 53, offset: 4945}, - exprs: []interface{}{ + pos: position{line: 219, col: 53, offset: 5909}, + exprs: []any{ &litMatcher{ - pos: position{line: 182, col: 53, offset: 4945}, + pos: position{line: 219, col: 53, offset: 5909}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &zeroOrMoreExpr{ - pos: position{line: 182, col: 57, offset: 4949}, + pos: position{line: 219, col: 57, offset: 5913}, expr: &ruleRefExpr{ - pos: position{line: 182, col: 57, offset: 4949}, + pos: position{line: 219, col: 57, offset: 5913}, name: "DoubleStringChar", }, }, &litMatcher{ - pos: position{line: 182, col: 75, offset: 4967}, + pos: position{line: 219, col: 75, offset: 5931}, val: "\"", ignoreCase: false, want: "\"\\\"\"", @@ -1551,42 +1853,42 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 184, col: 5, offset: 5019}, - exprs: []interface{}{ + pos: position{line: 221, col: 5, offset: 5983}, + exprs: []any{ &choiceExpr{ - pos: position{line: 184, col: 6, offset: 5020}, - alternatives: []interface{}{ + pos: position{line: 221, col: 6, offset: 5984}, + alternatives: []any{ &seqExpr{ - pos: position{line: 184, col: 6, offset: 5020}, - exprs: []interface{}{ + pos: position{line: 221, col: 6, offset: 5984}, + exprs: []any{ &litMatcher{ - pos: position{line: 184, col: 6, offset: 5020}, + pos: position{line: 221, col: 6, offset: 5984}, val: "`", ignoreCase: false, want: "\"`\"", }, &zeroOrMoreExpr{ - pos: position{line: 184, col: 10, offset: 5024}, + pos: position{line: 221, col: 10, offset: 5988}, expr: &ruleRefExpr{ - pos: position{line: 184, col: 10, offset: 5024}, + pos: position{line: 221, col: 10, offset: 5988}, name: "RawStringChar", }, }, }, }, &seqExpr{ - pos: position{line: 184, col: 27, offset: 5041}, - exprs: []interface{}{ + pos: position{line: 221, col: 27, offset: 6005}, + exprs: []any{ &litMatcher{ - pos: position{line: 184, col: 27, offset: 5041}, + pos: position{line: 221, col: 27, offset: 6005}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &zeroOrMoreExpr{ - pos: position{line: 184, col: 31, offset: 5045}, + pos: position{line: 221, col: 31, offset: 6009}, expr: &ruleRefExpr{ - pos: position{line: 184, col: 31, offset: 5045}, + pos: position{line: 221, col: 31, offset: 6009}, name: "DoubleStringChar", }, }, @@ -1595,11 +1897,11 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 184, col: 50, offset: 5064}, + pos: position{line: 221, col: 50, offset: 6028}, name: "EOF", }, &andCodeExpr{ - pos: position{line: 184, col: 54, offset: 5068}, + pos: position{line: 221, col: 54, offset: 6032}, run: (*parser).callonStringLiteral25, }, }, @@ -1609,42 +1911,42 @@ var g = &grammar{ }, { name: "RawStringChar", - pos: position{line: 188, col: 1, offset: 5132}, + pos: position{line: 225, col: 1, offset: 6096}, expr: &seqExpr{ - pos: position{line: 188, col: 18, offset: 5149}, - exprs: []interface{}{ + pos: position{line: 225, col: 18, offset: 6113}, + exprs: []any{ ¬Expr{ - pos: position{line: 188, col: 18, offset: 5149}, + pos: position{line: 225, col: 18, offset: 6113}, expr: &litMatcher{ - pos: position{line: 188, col: 19, offset: 5150}, + pos: position{line: 225, col: 19, offset: 6114}, val: "`", ignoreCase: false, want: "\"`\"", }, }, &anyMatcher{ - line: 188, col: 23, offset: 5154, + line: 225, col: 23, offset: 6118, }, }, }, }, { name: "DoubleStringChar", - pos: position{line: 189, col: 1, offset: 5156}, + pos: position{line: 226, col: 1, offset: 6120}, expr: &seqExpr{ - pos: position{line: 189, col: 21, offset: 5176}, - exprs: []interface{}{ + pos: position{line: 226, col: 21, offset: 6140}, + exprs: []any{ ¬Expr{ - pos: position{line: 189, col: 21, offset: 5176}, + pos: position{line: 226, col: 21, offset: 6140}, expr: &litMatcher{ - pos: position{line: 189, col: 22, offset: 5177}, + pos: position{line: 226, col: 22, offset: 6141}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, }, &anyMatcher{ - line: 189, col: 26, offset: 5181, + line: 226, col: 26, offset: 6145, }, }, }, @@ -1652,11 +1954,11 @@ var g = &grammar{ { name: "_", displayName: "\"whitespace\"", - pos: position{line: 191, col: 1, offset: 5184}, + pos: position{line: 228, col: 1, offset: 6148}, expr: &oneOrMoreExpr{ - pos: position{line: 191, col: 19, offset: 5202}, + pos: position{line: 228, col: 19, offset: 6166}, expr: &charClassMatcher{ - pos: position{line: 191, col: 19, offset: 5202}, + pos: position{line: 228, col: 19, offset: 6166}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, @@ -1666,38 +1968,38 @@ var g = &grammar{ }, { name: "EOF", - pos: position{line: 193, col: 1, offset: 5214}, + pos: position{line: 230, col: 1, offset: 6178}, expr: ¬Expr{ - pos: position{line: 193, col: 8, offset: 5221}, + pos: position{line: 230, col: 8, offset: 6185}, expr: &anyMatcher{ - line: 193, col: 9, offset: 5222, + line: 230, col: 9, offset: 6186, }, }, }, }, } -func (c *current) onInput2(expr interface{}) (interface{}, error) { +func (c *current) onInput2(expr any) (any, error) { return expr, nil } -func (p *parser) callonInput2() (interface{}, error) { +func (p *parser) callonInput2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onInput2(stack["expr"]) } -func (c *current) onInput17(expr interface{}) (interface{}, error) { +func (c *current) onInput17(expr any) (any, error) { return expr, nil } -func (p *parser) callonInput17() (interface{}, error) { +func (p *parser) callonInput17() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onInput17(stack["expr"]) } -func (c *current) onOrExpression2(left, right interface{}) (interface{}, error) { +func (c *current) onOrExpression2(left, right any) (any, error) { return &BinaryExpression{ Operator: BinaryOpOr, Left: left.(Expression), @@ -1705,23 +2007,43 @@ func (c *current) onOrExpression2(left, right interface{}) (interface{}, error) }, nil } -func (p *parser) callonOrExpression2() (interface{}, error) { +func (p *parser) callonOrExpression2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onOrExpression2(stack["left"], stack["right"]) } -func (c *current) onOrExpression11(expr interface{}) (interface{}, error) { +func (c *current) onOrExpression11(expr any) (any, error) { return expr, nil } -func (p *parser) callonOrExpression11() (interface{}, error) { +func (p *parser) callonOrExpression11() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onOrExpression11(stack["expr"]) } -func (c *current) onAndExpression2(left, right interface{}) (interface{}, error) { +func (c *current) onOrExpression14(expr any) (any, error) { + return expr, nil +} + +func (p *parser) callonOrExpression14() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onOrExpression14(stack["expr"]) +} + +func (c *current) onOrExpression17(expr any) (any, error) { + return expr, nil +} + +func (p *parser) callonOrExpression17() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onOrExpression17(stack["expr"]) +} + +func (c *current) onAndExpression2(left, right any) (any, error) { return &BinaryExpression{ Operator: BinaryOpAnd, Left: left.(Expression), @@ -1729,23 +2051,23 @@ func (c *current) onAndExpression2(left, right interface{}) (interface{}, error) }, nil } -func (p *parser) callonAndExpression2() (interface{}, error) { +func (p *parser) callonAndExpression2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onAndExpression2(stack["left"], stack["right"]) } -func (c *current) onAndExpression11(expr interface{}) (interface{}, error) { +func (c *current) onAndExpression11(expr any) (any, error) { return expr, nil } -func (p *parser) callonAndExpression11() (interface{}, error) { +func (p *parser) callonAndExpression11() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onAndExpression11(stack["expr"]) } -func (c *current) onNotExpression2(expr interface{}) (interface{}, error) { +func (c *current) onNotExpression2(expr any) (any, error) { if unary, ok := expr.(*UnaryExpression); ok && unary.Operator == UnaryOpNot { // small optimization to get rid unnecessary levels of AST nodes // for things like: not not foo == 3 which is equivalent to foo == 3 @@ -1758,37 +2080,82 @@ func (c *current) onNotExpression2(expr interface{}) (interface{}, error) { }, nil } -func (p *parser) callonNotExpression2() (interface{}, error) { +func (p *parser) callonNotExpression2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onNotExpression2(stack["expr"]) } -func (c *current) onNotExpression8(expr interface{}) (interface{}, error) { +func (c *current) onNotExpression8(expr any) (any, error) { return expr, nil } -func (p *parser) callonNotExpression8() (interface{}, error) { +func (p *parser) callonNotExpression8() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onNotExpression8(stack["expr"]) } -func (c *current) onParenthesizedExpression2(expr interface{}) (interface{}, error) { +func (c *current) onCollectionExpression1(operator, selector, ident, expr any) (any, error) { + return c.onCollectionExpressionWithKey1(operator, selector, ident, "", expr) +} + +func (p *parser) callonCollectionExpression1() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCollectionExpression1(stack["operator"], stack["selector"], stack["ident"], stack["expr"]) +} + +func (c *current) onCollectionExpressionWithKey1(operator, selector, key, value, expr any) (any, error) { + ce := &CollectionExpression{ + Selector: selector.(Selector), + Inner: expr.(Expression), + } + + if string(operator.([]byte)) == "all" { + ce.Type = AllExpression + } else { + ce.Type = AnyExpression + } + + switch k := key.(type) { + case string: + ce.Key = k + default: + ce.Key = "_" + } + + switch v := value.(type) { + case string: + ce.Value = v + default: + ce.Value = "_" + } + + return ce, nil +} + +func (p *parser) callonCollectionExpressionWithKey1() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCollectionExpressionWithKey1(stack["operator"], stack["selector"], stack["key"], stack["value"], stack["expr"]) +} + +func (c *current) onParenthesizedExpression2(expr any) (any, error) { return expr, nil } -func (p *parser) callonParenthesizedExpression2() (interface{}, error) { +func (p *parser) callonParenthesizedExpression2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onParenthesizedExpression2(stack["expr"]) } -func (c *current) onParenthesizedExpression12(expr interface{}) (interface{}, error) { +func (c *current) onParenthesizedExpression12(expr any) (any, error) { return expr, nil } -func (p *parser) callonParenthesizedExpression12() (interface{}, error) { +func (p *parser) callonParenthesizedExpression12() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onParenthesizedExpression12(stack["expr"]) @@ -1804,37 +2171,37 @@ func (p *parser) callonParenthesizedExpression24() (bool, error) { return p.cur.onParenthesizedExpression24() } -func (c *current) onMatchSelectorOpValue1(selector, operator, value interface{}) (interface{}, error) { +func (c *current) onMatchSelectorOpValue1(selector, operator, value any) (any, error) { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: value.(*MatchValue)}, nil } -func (p *parser) callonMatchSelectorOpValue1() (interface{}, error) { +func (p *parser) callonMatchSelectorOpValue1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchSelectorOpValue1(stack["selector"], stack["operator"], stack["value"]) } -func (c *current) onMatchSelectorOp1(selector, operator interface{}) (interface{}, error) { +func (c *current) onMatchSelectorOp1(selector, operator any) (any, error) { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: nil}, nil } -func (p *parser) callonMatchSelectorOp1() (interface{}, error) { +func (p *parser) callonMatchSelectorOp1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchSelectorOp1(stack["selector"], stack["operator"]) } -func (c *current) onMatchValueOpSelector2(value, operator, selector interface{}) (interface{}, error) { +func (c *current) onMatchValueOpSelector2(value, operator, selector any) (any, error) { return &MatchExpression{Selector: selector.(Selector), Operator: operator.(MatchOperator), Value: value.(*MatchValue)}, nil } -func (p *parser) callonMatchValueOpSelector2() (interface{}, error) { +func (p *parser) callonMatchValueOpSelector2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchValueOpSelector2(stack["value"], stack["operator"], stack["selector"]) } -func (c *current) onMatchValueOpSelector20(operator interface{}) (bool, error) { +func (c *current) onMatchValueOpSelector20(operator any) (bool, error) { return false, errors.New("Invalid selector") } @@ -1844,107 +2211,107 @@ func (p *parser) callonMatchValueOpSelector20() (bool, error) { return p.cur.onMatchValueOpSelector20(stack["operator"]) } -func (c *current) onMatchEqual1() (interface{}, error) { +func (c *current) onMatchEqual1() (any, error) { return MatchEqual, nil } -func (p *parser) callonMatchEqual1() (interface{}, error) { +func (p *parser) callonMatchEqual1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchEqual1() } -func (c *current) onMatchNotEqual1() (interface{}, error) { +func (c *current) onMatchNotEqual1() (any, error) { return MatchNotEqual, nil } -func (p *parser) callonMatchNotEqual1() (interface{}, error) { +func (p *parser) callonMatchNotEqual1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotEqual1() } -func (c *current) onMatchIsEmpty1() (interface{}, error) { +func (c *current) onMatchIsEmpty1() (any, error) { return MatchIsEmpty, nil } -func (p *parser) callonMatchIsEmpty1() (interface{}, error) { +func (p *parser) callonMatchIsEmpty1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchIsEmpty1() } -func (c *current) onMatchIsNotEmpty1() (interface{}, error) { +func (c *current) onMatchIsNotEmpty1() (any, error) { return MatchIsNotEmpty, nil } -func (p *parser) callonMatchIsNotEmpty1() (interface{}, error) { +func (p *parser) callonMatchIsNotEmpty1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchIsNotEmpty1() } -func (c *current) onMatchIn1() (interface{}, error) { +func (c *current) onMatchIn1() (any, error) { return MatchIn, nil } -func (p *parser) callonMatchIn1() (interface{}, error) { +func (p *parser) callonMatchIn1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchIn1() } -func (c *current) onMatchNotIn1() (interface{}, error) { +func (c *current) onMatchNotIn1() (any, error) { return MatchNotIn, nil } -func (p *parser) callonMatchNotIn1() (interface{}, error) { +func (p *parser) callonMatchNotIn1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotIn1() } -func (c *current) onMatchContains1() (interface{}, error) { +func (c *current) onMatchContains1() (any, error) { return MatchIn, nil } -func (p *parser) callonMatchContains1() (interface{}, error) { +func (p *parser) callonMatchContains1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchContains1() } -func (c *current) onMatchNotContains1() (interface{}, error) { +func (c *current) onMatchNotContains1() (any, error) { return MatchNotIn, nil } -func (p *parser) callonMatchNotContains1() (interface{}, error) { +func (p *parser) callonMatchNotContains1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotContains1() } -func (c *current) onMatchMatches1() (interface{}, error) { +func (c *current) onMatchMatches1() (any, error) { return MatchMatches, nil } -func (p *parser) callonMatchMatches1() (interface{}, error) { +func (p *parser) callonMatchMatches1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchMatches1() } -func (c *current) onMatchNotMatches1() (interface{}, error) { +func (c *current) onMatchNotMatches1() (any, error) { return MatchNotMatches, nil } -func (p *parser) callonMatchNotMatches1() (interface{}, error) { +func (p *parser) callonMatchNotMatches1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onMatchNotMatches1() } -func (c *current) onSelector2(first, rest interface{}) (interface{}, error) { +func (c *current) onSelector2(first, rest any) (any, error) { sel := Selector{ Type: SelectorTypeBexpr, Path: []string{first.(string)}, @@ -1957,13 +2324,13 @@ func (c *current) onSelector2(first, rest interface{}) (interface{}, error) { return sel, nil } -func (p *parser) callonSelector2() (interface{}, error) { +func (p *parser) callonSelector2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelector2(stack["first"], stack["rest"]) } -func (c *current) onSelector9(ptrsegs interface{}) (interface{}, error) { +func (c *current) onSelector9(ptrsegs any) (any, error) { sel := Selector{ Type: SelectorTypeJsonPointer, } @@ -1984,67 +2351,67 @@ func (c *current) onSelector9(ptrsegs interface{}) (interface{}, error) { return sel, nil } -func (p *parser) callonSelector9() (interface{}, error) { +func (p *parser) callonSelector9() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelector9(stack["ptrsegs"]) } -func (c *current) onJsonPointerSegment1(ident interface{}) (interface{}, error) { +func (c *current) onJsonPointerSegment1(ident any) (any, error) { return string(c.text)[1:], nil } -func (p *parser) callonJsonPointerSegment1() (interface{}, error) { +func (p *parser) callonJsonPointerSegment1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onJsonPointerSegment1(stack["ident"]) } -func (c *current) onIdentifier1() (interface{}, error) { +func (c *current) onIdentifier1() (any, error) { return string(c.text), nil } -func (p *parser) callonIdentifier1() (interface{}, error) { +func (p *parser) callonIdentifier1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onIdentifier1() } -func (c *current) onSelectorOrIndex2(ident interface{}) (interface{}, error) { +func (c *current) onSelectorOrIndex2(ident any) (any, error) { return ident, nil } -func (p *parser) callonSelectorOrIndex2() (interface{}, error) { +func (p *parser) callonSelectorOrIndex2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelectorOrIndex2(stack["ident"]) } -func (c *current) onSelectorOrIndex7(expr interface{}) (interface{}, error) { +func (c *current) onSelectorOrIndex7(expr any) (any, error) { return expr, nil } -func (p *parser) callonSelectorOrIndex7() (interface{}, error) { +func (p *parser) callonSelectorOrIndex7() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelectorOrIndex7(stack["expr"]) } -func (c *current) onSelectorOrIndex10(idx interface{}) (interface{}, error) { +func (c *current) onSelectorOrIndex10(idx any) (any, error) { return string(c.text)[1:], nil } -func (p *parser) callonSelectorOrIndex10() (interface{}, error) { +func (p *parser) callonSelectorOrIndex10() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onSelectorOrIndex10(stack["idx"]) } -func (c *current) onIndexExpression2(lit interface{}) (interface{}, error) { +func (c *current) onIndexExpression2(lit any) (any, error) { return lit, nil } -func (p *parser) callonIndexExpression2() (interface{}, error) { +func (p *parser) callonIndexExpression2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onIndexExpression2(stack["lit"]) @@ -2070,41 +2437,41 @@ func (p *parser) callonIndexExpression28() (bool, error) { return p.cur.onIndexExpression28() } -func (c *current) onValue2(selector interface{}) (interface{}, error) { +func (c *current) onValue2(selector any) (any, error) { return &MatchValue{Raw: selector.(Selector).String()}, nil } -func (p *parser) callonValue2() (interface{}, error) { +func (p *parser) callonValue2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onValue2(stack["selector"]) } -func (c *current) onValue5(n interface{}) (interface{}, error) { +func (c *current) onValue5(n any) (any, error) { return &MatchValue{Raw: n.(string)}, nil } -func (p *parser) callonValue5() (interface{}, error) { +func (p *parser) callonValue5() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onValue5(stack["n"]) } -func (c *current) onValue8(s interface{}) (interface{}, error) { +func (c *current) onValue8(s any) (any, error) { return &MatchValue{Raw: s.(string)}, nil } -func (p *parser) callonValue8() (interface{}, error) { +func (p *parser) callonValue8() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onValue8(stack["s"]) } -func (c *current) onNumberLiteral2() (interface{}, error) { +func (c *current) onNumberLiteral2() (any, error) { return string(c.text), nil } -func (p *parser) callonNumberLiteral2() (interface{}, error) { +func (p *parser) callonNumberLiteral2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onNumberLiteral2() @@ -2120,11 +2487,11 @@ func (p *parser) callonNumberLiteral15() (bool, error) { return p.cur.onNumberLiteral15() } -func (c *current) onStringLiteral2() (interface{}, error) { +func (c *current) onStringLiteral2() (any, error) { return strconv.Unquote(string(c.text)) } -func (p *parser) callonStringLiteral2() (interface{}, error) { +func (p *parser) callonStringLiteral2() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack return p.cur.onStringLiteral2() @@ -2222,7 +2589,7 @@ func Recover(b bool) Option { // GlobalStore creates an Option to set a key to a certain value in // the globalStore. -func GlobalStore(key string, value interface{}) Option { +func GlobalStore(key string, value any) Option { return func(p *parser) Option { old := p.cur.globalStore[key] p.cur.globalStore[key] = value @@ -2231,7 +2598,7 @@ func GlobalStore(key string, value interface{}) Option { } // ParseFile parses the file identified by filename. -func ParseFile(filename string, opts ...Option) (i interface{}, err error) { +func ParseFile(filename string, opts ...Option) (i any, err error) { f, err := os.Open(filename) if err != nil { return nil, err @@ -2246,8 +2613,8 @@ func ParseFile(filename string, opts ...Option) (i interface{}, err error) { // ParseReader parses the data from r using filename as information in the // error messages. -func ParseReader(filename string, r io.Reader, opts ...Option) (interface{}, error) { - b, err := ioutil.ReadAll(r) +func ParseReader(filename string, r io.Reader, opts ...Option) (any, error) { + b, err := io.ReadAll(r) if err != nil { return nil, err } @@ -2257,7 +2624,7 @@ func ParseReader(filename string, r io.Reader, opts ...Option) (interface{}, err // Parse parses the data from b using filename as information in the // error messages. -func Parse(filename string, b []byte, opts ...Option) (interface{}, error) { +func Parse(filename string, b []byte, opts ...Option) (any, error) { return newParser(filename, b, opts...).parse(g) } @@ -2290,7 +2657,7 @@ type current struct { globalStore storeDict } -type storeDict map[string]interface{} +type storeDict map[string]any // the AST types... @@ -2303,30 +2670,30 @@ type rule struct { pos position name string displayName string - expr interface{} + expr any } type choiceExpr struct { pos position - alternatives []interface{} + alternatives []any } type actionExpr struct { pos position - expr interface{} - run func(*parser) (interface{}, error) + expr any + run func(*parser) (any, error) } type recoveryExpr struct { pos position - expr interface{} - recoverExpr interface{} + expr any + recoverExpr any failureLabel []string } type seqExpr struct { pos position - exprs []interface{} + exprs []any } type throwExpr struct { @@ -2337,19 +2704,21 @@ type throwExpr struct { type labeledExpr struct { pos position label string - expr interface{} + expr any } type expr struct { pos position - expr interface{} + expr any } -type andExpr expr -type notExpr expr -type zeroOrOneExpr expr -type zeroOrMoreExpr expr -type oneOrMoreExpr expr +type ( + andExpr expr + notExpr expr + zeroOrOneExpr expr + zeroOrMoreExpr expr + oneOrMoreExpr expr +) type ruleRefExpr struct { pos position @@ -2484,7 +2853,7 @@ func (p *parser) setOptions(opts []Option) { } type resultTuple struct { - v interface{} + v any b bool end savepoint } @@ -2527,7 +2896,7 @@ type parser struct { // rules table, maps the rule identifier to the rule node rules map[string]*rule // variables stack, map of label to value - vstack []map[string]interface{} + vstack []map[string]any // rule stack, allows identification of the current rule in errors rstack []*rule @@ -2547,7 +2916,7 @@ type parser struct { choiceNoMatch string // recovery expression stack, keeps track of the currently available recovery expression, these are traversed in reverse - recoveryStack []map[string]interface{} + recoveryStack []map[string]any } // push a variable set on the vstack. @@ -2567,7 +2936,7 @@ func (p *parser) pushV() { return } - m = make(map[string]interface{}) + m = make(map[string]any) p.vstack[len(p.vstack)-1] = m } @@ -2583,7 +2952,7 @@ func (p *parser) popV() { } // push a recovery expression with its labels to the recoveryStack -func (p *parser) pushRecovery(labels []string, expr interface{}) { +func (p *parser) pushRecovery(labels []string, expr any) { if cap(p.recoveryStack) == len(p.recoveryStack) { // create new empty slot in the stack p.recoveryStack = append(p.recoveryStack, nil) @@ -2592,7 +2961,7 @@ func (p *parser) pushRecovery(labels []string, expr interface{}) { p.recoveryStack = p.recoveryStack[:len(p.recoveryStack)+1] } - m := make(map[string]interface{}, len(labels)) + m := make(map[string]any, len(labels)) for _, fl := range labels { m[fl] = expr } @@ -2693,7 +3062,7 @@ func (p *parser) buildRulesTable(g *grammar) { } } -func (p *parser) parse(g *grammar) (val interface{}, err error) { +func (p *parser) parse(g *grammar) (val any, err error) { if len(g.rules) == 0 { p.addErr(errNoRule) return nil, p.errs.err() @@ -2767,7 +3136,7 @@ func listJoin(list []string, sep string, lastSep string) string { } } -func (p *parser) parseRule(rule *rule) (interface{}, bool) { +func (p *parser) parseRule(rule *rule) (any, bool) { p.rstack = append(p.rstack, rule) p.pushV() val, ok := p.parseExpr(rule.expr) @@ -2776,14 +3145,14 @@ func (p *parser) parseRule(rule *rule) (interface{}, bool) { return val, ok } -func (p *parser) parseExpr(expr interface{}) (interface{}, bool) { +func (p *parser) parseExpr(expr any) (any, bool) { p.ExprCnt++ if p.ExprCnt > p.maxExprCnt { panic(errMaxExprCnt) } - var val interface{} + var val any var ok bool switch expr := expr.(type) { case *actionExpr: @@ -2826,7 +3195,7 @@ func (p *parser) parseExpr(expr interface{}) (interface{}, bool) { return val, ok } -func (p *parser) parseActionExpr(act *actionExpr) (interface{}, bool) { +func (p *parser) parseActionExpr(act *actionExpr) (any, bool) { start := p.pt val, ok := p.parseExpr(act.expr) if ok { @@ -2842,7 +3211,7 @@ func (p *parser) parseActionExpr(act *actionExpr) (interface{}, bool) { return val, ok } -func (p *parser) parseAndCodeExpr(and *andCodeExpr) (interface{}, bool) { +func (p *parser) parseAndCodeExpr(and *andCodeExpr) (any, bool) { ok, err := and.run(p) if err != nil { @@ -2852,7 +3221,7 @@ func (p *parser) parseAndCodeExpr(and *andCodeExpr) (interface{}, bool) { return nil, ok } -func (p *parser) parseAndExpr(and *andExpr) (interface{}, bool) { +func (p *parser) parseAndExpr(and *andExpr) (any, bool) { pt := p.pt p.pushV() _, ok := p.parseExpr(and.expr) @@ -2862,7 +3231,7 @@ func (p *parser) parseAndExpr(and *andExpr) (interface{}, bool) { return nil, ok } -func (p *parser) parseAnyMatcher(any *anyMatcher) (interface{}, bool) { +func (p *parser) parseAnyMatcher(any *anyMatcher) (any, bool) { if p.pt.rn == utf8.RuneError && p.pt.w == 0 { // EOF - see utf8.DecodeRune p.failAt(false, p.pt.position, ".") @@ -2874,7 +3243,7 @@ func (p *parser) parseAnyMatcher(any *anyMatcher) (interface{}, bool) { return p.sliceFrom(start), true } -func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (interface{}, bool) { +func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (any, bool) { cur := p.pt.rn start := p.pt @@ -2936,7 +3305,7 @@ func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (interface{}, bool return nil, false } -func (p *parser) parseChoiceExpr(ch *choiceExpr) (interface{}, bool) { +func (p *parser) parseChoiceExpr(ch *choiceExpr) (any, bool) { for altI, alt := range ch.alternatives { // dummy assignment to prevent compile error if optimized _ = altI @@ -2951,7 +3320,7 @@ func (p *parser) parseChoiceExpr(ch *choiceExpr) (interface{}, bool) { return nil, false } -func (p *parser) parseLabeledExpr(lab *labeledExpr) (interface{}, bool) { +func (p *parser) parseLabeledExpr(lab *labeledExpr) (any, bool) { p.pushV() val, ok := p.parseExpr(lab.expr) p.popV() @@ -2962,7 +3331,7 @@ func (p *parser) parseLabeledExpr(lab *labeledExpr) (interface{}, bool) { return val, ok } -func (p *parser) parseLitMatcher(lit *litMatcher) (interface{}, bool) { +func (p *parser) parseLitMatcher(lit *litMatcher) (any, bool) { start := p.pt for _, want := range lit.val { cur := p.pt.rn @@ -2980,7 +3349,7 @@ func (p *parser) parseLitMatcher(lit *litMatcher) (interface{}, bool) { return p.sliceFrom(start), true } -func (p *parser) parseNotCodeExpr(not *notCodeExpr) (interface{}, bool) { +func (p *parser) parseNotCodeExpr(not *notCodeExpr) (any, bool) { ok, err := not.run(p) if err != nil { p.addErr(err) @@ -2989,7 +3358,7 @@ func (p *parser) parseNotCodeExpr(not *notCodeExpr) (interface{}, bool) { return nil, !ok } -func (p *parser) parseNotExpr(not *notExpr) (interface{}, bool) { +func (p *parser) parseNotExpr(not *notExpr) (any, bool) { pt := p.pt p.pushV() p.maxFailInvertExpected = !p.maxFailInvertExpected @@ -3001,8 +3370,8 @@ func (p *parser) parseNotExpr(not *notExpr) (interface{}, bool) { return nil, !ok } -func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (interface{}, bool) { - var vals []interface{} +func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (any, bool) { + var vals []any for { p.pushV() @@ -3019,7 +3388,7 @@ func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (interface{}, bool) { } } -func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (interface{}, bool) { +func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (any, bool) { p.pushRecovery(recover.failureLabel, recover.recoverExpr) val, ok := p.parseExpr(recover.expr) @@ -3028,7 +3397,7 @@ func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (interface{}, bool) { return val, ok } -func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (interface{}, bool) { +func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (any, bool) { if ref.name == "" { panic(fmt.Sprintf("%s: invalid rule: missing name", ref.pos)) } @@ -3041,8 +3410,8 @@ func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (interface{}, bool) { return p.parseRule(rule) } -func (p *parser) parseSeqExpr(seq *seqExpr) (interface{}, bool) { - vals := make([]interface{}, 0, len(seq.exprs)) +func (p *parser) parseSeqExpr(seq *seqExpr) (any, bool) { + vals := make([]any, 0, len(seq.exprs)) pt := p.pt for _, expr := range seq.exprs { @@ -3056,7 +3425,7 @@ func (p *parser) parseSeqExpr(seq *seqExpr) (interface{}, bool) { return vals, true } -func (p *parser) parseThrowExpr(expr *throwExpr) (interface{}, bool) { +func (p *parser) parseThrowExpr(expr *throwExpr) (any, bool) { for i := len(p.recoveryStack) - 1; i >= 0; i-- { if recoverExpr, ok := p.recoveryStack[i][expr.label]; ok { @@ -3069,8 +3438,8 @@ func (p *parser) parseThrowExpr(expr *throwExpr) (interface{}, bool) { return nil, false } -func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (interface{}, bool) { - var vals []interface{} +func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (any, bool) { + var vals []any for { p.pushV() @@ -3083,7 +3452,7 @@ func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (interface{}, bool) { } } -func (p *parser) parseZeroOrOneExpr(expr *zeroOrOneExpr) (interface{}, bool) { +func (p *parser) parseZeroOrOneExpr(expr *zeroOrOneExpr) (any, bool) { p.pushV() val, _ := p.parseExpr(expr.expr) p.popV() diff --git a/grammar/grammar.peg b/grammar/grammar.peg index 728fc7e..920b2b4 100644 --- a/grammar/grammar.peg +++ b/grammar/grammar.peg @@ -23,6 +23,10 @@ OrExpression <- left:AndExpression _ "or" _ right:OrExpression { }, nil } / expr:AndExpression { return expr, nil +} / expr:CollectionExpression { + return expr, nil +} / expr:CollectionExpressionWithKey { + return expr, nil } AndExpression <- left:NotExpression _ "and" _ right:AndExpression { @@ -50,6 +54,39 @@ NotExpression <- "not" _ expr:NotExpression { return expr, nil } +CollectionExpression <- operator:("all"/"any") _ selector:Selector _ "as" _ ident:(Identifier / "_") _? "{" _? expr:OrExpression _? "}" { + return c.onCollectionExpressionWithKey1(operator, selector, ident, "", expr) +} + +CollectionExpressionWithKey <- operator:("all"/"any") _ selector:Selector _ "as" _ key:(Identifier / "_") _? "," _? value:(Identifier / "_") _? "{" _? expr:OrExpression _? "}" { + ce := &CollectionExpression{ + Selector: selector.(Selector), + Inner: expr.(Expression), + } + + if string(operator.([]byte)) == "all" { + ce.Type = AllExpression + } else { + ce.Type = AnyExpression + } + + switch k := key.(type) { + case string: + ce.Key = k + default: + ce.Key = "_" + } + + switch v := value.(type) { + case string: + ce.Value = v + default: + ce.Value = "_" + } + + return ce, nil +} + ParenthesizedExpression "grouping" <- "(" _? expr:OrExpression _? ")" { return expr, nil } / expr:MatchExpression { diff --git a/grammar/grammar_test.go b/grammar/grammar_test.go index 196ad01..7534c39 100644 --- a/grammar/grammar_test.go +++ b/grammar/grammar_test.go @@ -342,7 +342,7 @@ func TestExpressionParsing(t *testing.T) { "Junk at the end 3": { input: "x in foo or ", expected: nil, - err: "1:13 (12): no match found, expected: \"(\", \"-\", \"0\", \"\\\"\", \"`\", \"not\", [ \\t\\r\\n], [1-9] or [a-zA-Z]", + err: "1:13 (12): no match found, expected: \"(\", \"-\", \"0\", \"\\\"\", \"`\", \"all\", \"any\", \"not\", [ \\t\\r\\n], [1-9] or [a-zA-Z]", }, "Junk at the end 4": { input: "x in foo or not ", @@ -374,6 +374,155 @@ func TestExpressionParsing(t *testing.T) { expected: &MatchExpression{Selector: Selector{Type: SelectorTypeBexpr, Path: []string{"foo"}}, Operator: MatchEqual, Value: &MatchValue{Raw: "3"}}, err: "", }, + "all": { + input: `all group.tasks as t { t.name == "hello" }`, + expected: &CollectionExpression{ + Key: "t", + Value: "", + Type: AllExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"group", "tasks"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"t", "name"}, + }, + Operator: 0, + Value: &MatchValue{ + Raw: "hello", + }, + }, + }, + }, + "all missing identifier": { + input: `all group.tasks as { t.name == "hello" }`, + expected: &CollectionExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"group", "tasks"}, + }, + }, + err: "1:20 (19): no match found, expected: \"_\", [ \\t\\r\\n] or [a-zA-Z]", + }, + "all missing selector": { + input: `all as t { t.name == "hello" }`, + expected: &CollectionExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"group", "tasks"}, + }, + }, + err: "1:8 (7): no match found, expected: \"as\" or [ \\t\\r\\n]", + }, + "nested all": { + input: `all group.tasks as t { all t.test as i { i == "test" }}`, + expected: &CollectionExpression{ + Key: "t", + Value: "", + Type: AllExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"group", "tasks"}, + }, + Inner: &CollectionExpression{ + Key: "i", + Value: "", + Type: AllExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"t", "test"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"i"}, + }, + Operator: MatchEqual, + Value: &MatchValue{ + Raw: "test", + }, + }, + }, + }, + }, + "all with key value": { + input: `all group.tasks as k, v { k == v }`, + expected: &CollectionExpression{ + Type: AllExpression, + Key: "k", + Value: "v", + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"group", "tasks"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"k"}, + }, + Operator: MatchEqual, + Value: &MatchValue{ + Raw: "v", + Converted: nil, + }, + }, + }, + }, + "any": { + input: `any group.tasks as t { t.name == "vmware" }`, + expected: &CollectionExpression{ + Key: "t", + Value: "", + Type: AnyExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"group", "tasks"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"t", "name"}, + }, + Operator: MatchEqual, + Value: &MatchValue{ + Raw: "vmware", + }, + }, + }, + }, + "nested any": { + input: `any group.tasks as t { any t.test as t { t == "test" }}`, + expected: &CollectionExpression{ + Key: "t", + Value: "", + Type: AnyExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"group", "tasks"}, + }, + Inner: &CollectionExpression{ + Key: "t", + Value: "", + Type: AnyExpression, + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"t", "test"}, + }, + Inner: &MatchExpression{ + Selector: Selector{ + Type: SelectorTypeBexpr, + Path: []string{"t"}, + }, + Operator: MatchEqual, + Value: &MatchValue{ + Raw: "test", + }, + }, + }, + }, + }, "Complex": { input: "(((foo == 3) and (not ((bar in baz) and (not (one != two))))) or (((next is empty) and (not (foo is not empty))) and (bar not in foo)))", expected: &BinaryExpression{ From f7727d1d43c4585eb0ec592634927f26998c5fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Thu, 7 Sep 2023 01:56:46 +0200 Subject: [PATCH 2/9] Replace the prefixes in go-bexpr --- evaluate.go | 99 ++++++++++++++++++++++++++++++++------------- evaluate_test.go | 13 +++--- go.mod | 2 - go.sum | 4 +- grammar/ast.go | 8 ++-- grammar/ast_test.go | 6 +-- options.go | 22 ++++++++++ 7 files changed, 109 insertions(+), 45 deletions(-) diff --git a/evaluate.go b/evaluate.go index 7abd748..eaaa42c 100644 --- a/evaluate.go +++ b/evaluate.go @@ -239,29 +239,63 @@ func evaluateNotPresent(ptr pointerstructure.Pointer, datum interface{}) bool { func getValue(datum interface{}, path []string, opt ...Option) (interface{}, bool, error) { opts := getOpts(opt...) - ptr := pointerstructure.Pointer{ - Parts: path, - Config: pointerstructure.Config{ - TagName: opts.withTagName, - ValueTransformationHook: opts.withHookFn, - }, - } - val, err := ptr.Get(datum) - if err != nil { - if errors.Is(err, pointerstructure.ErrNotFound) { - // Prefer the withUnknown option if set, otherwise defer to NotPresent - // disposition - switch { - case opts.withUnknown != nil: - err = nil - val = *opts.withUnknown - case evaluateNotPresent(ptr, datum): - return nil, false, nil + var val interface{} + var found bool + if len(path) != 0 { + for i := len(opts.withLocalVariables) - 1; i >= 0; i-- { + name := path[0] + lv := opts.withLocalVariables[i] + if name == lv.name { + if len(lv.path) == 0 { + // This local variable is a key or an index and we know its + // value without having to call pointerstructure, we stop + // here. + val = lv.value + if len(path) > 1 { + first := pointerstructure.Pointer{Parts: []string{name}} + full := pointerstructure.Pointer{Parts: path} + return nil, false, fmt.Errorf("%s references a %T so %s is invalid", first.String(), val, full.String()) + } + found = true + // panic(fmt.Sprintf("%v %#v", name, val)) + break + } else { + // This local variable references another value, we prepend the + // path of the selector it replaces and continue searching + prefix := append([]string(nil), lv.path...) + path = append(prefix, path[1:]...) + } } } - + } + if !found { + // This is not a local variable, we use pointerstructure to look for it + // in the global datum + ptr := pointerstructure.Pointer{ + Parts: path, + Config: pointerstructure.Config{ + TagName: opts.withTagName, + ValueTransformationHook: opts.withHookFn, + }, + } + var err error + val, err = ptr.Get(datum) if err != nil { - return false, false, fmt.Errorf("error finding value in datum: %w", err) + if errors.Is(err, pointerstructure.ErrNotFound) { + // Prefer the withUnknown option if set, otherwise defer to NotPresent + // disposition + switch { + case opts.withUnknown != nil: + err = nil + val = *opts.withUnknown + case evaluateNotPresent(ptr, datum): + return nil, false, nil + } + } + + if err != nil { + return false, false, fmt.Errorf("error finding value in datum: %w", err) + } } } @@ -347,25 +381,28 @@ func evaluateCollectionExpression(expression *grammar.CollectionExpression, datu var keys []reflect.Value if v.Kind() == reflect.Map { + if v.Type().Key() != reflect.TypeOf("") { + return false, fmt.Errorf("%s can only iterate over maps indexed with strings", expression.Type) + } keys = v.MapKeys() } switch v.Kind() { case reflect.Slice, reflect.Array, reflect.Map: for i := 0; i < v.Len(); i++ { - - vars := map[string]interface{}{} + innerOpt := append([]Option(nil), opt...) if v.Kind() == reflect.Map { key := keys[i] if expression.Key != "_" { - vars[expression.Key] = key.Interface() + innerOpt = append(innerOpt, WithLocalVariable(expression.Key, nil, key.Interface())) } if expression.Value != "" && expression.Value != "_" { - vars[expression.Value] = v.MapIndex(key).Interface() + path := append([]string(nil), expression.Selector.Path...) + path = append(path, key.Interface().(string)) + innerOpt = append(innerOpt, WithLocalVariable(expression.Value, path, nil)) } } else { - value := v.Index(i).Interface() if expression.Value == "" { // This means we are using the version with one placeholder // like "all things as t { ... }". For lists t will iterate @@ -373,19 +410,23 @@ func evaluateCollectionExpression(expression *grammar.CollectionExpression, datu // of the Sentinel for loop (or the "for t in things" in // Python). This should match what users expect. if expression.Key != "_" { - vars[expression.Key] = value + path := append([]string(nil), expression.Selector.Path...) + path = append(path, strconv.Itoa(i)) + innerOpt = append(innerOpt, WithLocalVariable(expression.Key, path, nil)) } } else { if expression.Key != "_" { - vars[expression.Key] = i + innerOpt = append(innerOpt, WithLocalVariable(expression.Key, nil, i)) } if expression.Value != "_" { - vars[expression.Value] = value + path := append([]string(nil), expression.Selector.Path...) + path = append(path, strconv.Itoa(i)) + innerOpt = append(innerOpt, WithLocalVariable(expression.Value, path, nil)) } } } - result, err := evaluate(expression.Inner, pointerstructure.Defaults{vars, datum}, opt...) + result, err := evaluate(expression.Inner, datum, innerOpt...) if err != nil { return false, err } diff --git a/evaluate_test.go b/evaluate_test.go index 2e53802..49c93d5 100644 --- a/evaluate_test.go +++ b/evaluate_test.go @@ -238,7 +238,7 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{ {expression: "foo.bar != false", result: true}, {expression: "foo.baz != false", result: false}, {expression: "foo.baz != true", result: true}, - {expression: "foo.bar.baz == 3", result: false, err: `error finding value in datum: /foo/bar/baz at part 2: invalid value kind (bool)`}, + {expression: "foo.bar.baz == 3", result: false, err: `error finding value in datum: /foo/bar/baz: at part 2, invalid value kind: bool`}, }, }, "Nested Structs and Maps": { @@ -325,10 +325,13 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{ // any {expression: `any Nested.SliceOfInts as i { i == 1 }`, result: true}, {expression: `any Nested.SliceOfInts as i { i == 42 }`, result: false}, - {expression: `any Nested.Map as v { v != "bar" }`, result: true}, - {expression: `any Nested.Map as v { v == "bar" }`, result: true}, - {expression: `any Nested.Map as v { v == "hello" }`, result: false}, + {expression: `any Nested.SliceOfStructs as i { "/i/X" == 1 }`, result: true}, + {expression: `any Nested.Map as k { k != "bar" }`, result: true}, + {expression: `any Nested.Map as k { k == "bar" }`, result: true}, + {expression: `any Nested.Map as k { k == "hello" }`, result: false}, {expression: `any Nested.Map as k, v { k == "foo" and v == "bar" }`, result: true}, + {expression: `any Nested.Map as k { k.Color == "red" }`, err: "/k references a string so /k/Color is invalid"}, + {expression: `any Nested.SliceOfInts as i, _ { i.Color == "red" }`, err: "/i references a int so /i/Color is invalid"}, // Missing key in map tests {expression: "Nested.Map.notfound == 4", result: false}, {expression: "Nested.Map.notfound != 4", result: true}, @@ -417,7 +420,7 @@ func TestWithHookFn(t *testing.T) { {expression: `"/I/I"=="bar"`, result: true}, { expression: `"/S/I"=="foo"`, result: false, - err: "error finding value in datum: /S/I at part 1: invalid value kind (string)", + err: "error finding value in datum: /S/I: at part 1, invalid value kind: string", }, }, }, diff --git a/go.mod b/go.mod index 5e3f71a..fed408d 100644 --- a/go.mod +++ b/go.mod @@ -13,5 +13,3 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/mitchellh/pointerstructure v1.2.1 => github.com/remilapeyre/pointerstructure v0.0.0-20230906004826-80d813010704 diff --git a/go.sum b/go.sum index 999d82e..c6ceb45 100644 --- a/go.sum +++ b/go.sum @@ -3,10 +3,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw= +github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/remilapeyre/pointerstructure v0.0.0-20230906004826-80d813010704 h1:KnesY9UJKkVhupIN3bac36cb6Kc0mTTG7BkHNrdQgSo= -github.com/remilapeyre/pointerstructure v0.0.0-20230906004826-80d813010704/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/grammar/ast.go b/grammar/ast.go index 23d7eef..770201f 100644 --- a/grammar/ast.go +++ b/grammar/ast.go @@ -196,8 +196,8 @@ func (expr *MatchExpression) ExpressionDump(w io.Writer, indent string, level in type CollectionExpressionType string const ( - AllExpression CollectionExpressionType = "All" - AnyExpression CollectionExpressionType = "Any" + AllExpression CollectionExpressionType = "all" + AnyExpression CollectionExpressionType = "any" ) type CollectionExpression struct { @@ -210,9 +210,9 @@ type CollectionExpression struct { func (expr *CollectionExpression) ExpressionDump(w io.Writer, indent string, level int) { localIndent := strings.Repeat(indent, level) if expr.Value == "" { - fmt.Fprintf(w, "%s%s %s on %v {\n", localIndent, expr.Type, expr.Key, expr.Selector) + fmt.Fprintf(w, "%s%s %s on %v {\n", localIndent, strings.ToUpper(string(expr.Type)), expr.Key, expr.Selector) } else { - fmt.Fprintf(w, "%s%s (%s, %s) on %v {\n", localIndent, expr.Type, expr.Key, expr.Value, expr.Selector) + fmt.Fprintf(w, "%s%s (%s, %s) on %v {\n", localIndent, strings.ToUpper(string(expr.Type)), expr.Key, expr.Value, expr.Selector) } expr.Inner.ExpressionDump(w, indent, level+1) fmt.Fprintf(w, "%s}\n", localIndent) diff --git a/grammar/ast_test.go b/grammar/ast_test.go index 1a5fda1..96a86bd 100644 --- a/grammar/ast_test.go +++ b/grammar/ast_test.go @@ -98,7 +98,7 @@ func TestAST_Dump(t *testing.T) { }, }, }, - expected: "All k on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + expected: "ALL k on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", }, "All": { expr: &CollectionExpression{ @@ -120,7 +120,7 @@ func TestAST_Dump(t *testing.T) { }, }, }, - expected: "All (k, v) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + expected: "ALL (k, v) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", }, "Any": { expr: &CollectionExpression{ @@ -142,7 +142,7 @@ func TestAST_Dump(t *testing.T) { }, }, }, - expected: "Any (k, _) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + expected: "ANY (k, _) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", }, } diff --git a/options.go b/options.go index a5eb4cf..e39c135 100644 --- a/options.go +++ b/options.go @@ -14,6 +14,14 @@ func getOpts(opt ...Option) options { return opts } +// a localVariable can either point to a known value or replace another JSON +// Pointer path +type localVariable struct { + name string + path []string + value any +} + // Option - how Options are passed as arguments type Option func(*options) @@ -23,6 +31,7 @@ type options struct { withTagName string withHookFn ValueTransformationHookFn withUnknown *interface{} + withLocalVariables []localVariable } func WithMaxExpressions(maxExprCnt uint64) Option { @@ -58,6 +67,19 @@ func WithUnknownValue(val interface{}) Option { } } +// WithLocalVariable add a local variable that can either point to another path +// that will be resolved when the local variable is referenced or to a known +// value that will be used directly. +func WithLocalVariable(name string, path []string, value any) Option { + return func(o *options) { + o.withLocalVariables = append(o.withLocalVariables, localVariable{ + name: name, + path: path, + value: value, + }) + } +} + func getDefaultOptions() options { return options{ withMaxExpressions: 0, From 971044de35e4a0c72222d6752e2a9c736616ca5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Thu, 7 Sep 2023 01:58:15 +0200 Subject: [PATCH 3/9] Remove panic --- evaluate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/evaluate.go b/evaluate.go index eaaa42c..63232ae 100644 --- a/evaluate.go +++ b/evaluate.go @@ -257,7 +257,6 @@ func getValue(datum interface{}, path []string, opt ...Option) (interface{}, boo return nil, false, fmt.Errorf("%s references a %T so %s is invalid", first.String(), val, full.String()) } found = true - // panic(fmt.Sprintf("%v %#v", name, val)) break } else { // This local variable references another value, we prepend the From 338859abf2bc8501766af6ad29c351f083ce663a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Thu, 7 Sep 2023 10:04:19 +0200 Subject: [PATCH 4/9] Fix benchmark --- README.md | 2 +- evaluate_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e9d34f..72395de 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,6 @@ The [Makefile](Makefile) contains 3 main targets to aid with testing: `1s` seemed like too little to get results consistent enough for comparison between two runs. For the highest degree of confidence that performance has remained steady increase this value even further. The time it takes to run the bench testing suite grows linearly with this value. - * `BENCHTESTS=BenchmarkEvalute` - This is used to run a particular benchmark including all of its + * `BENCHTESTS=BenchmarkEvaluate` - This is used to run a particular benchmark including all of its sub-benchmarks. This is just an example and "BenchmarkEvaluate" can be replaced with any benchmark functions name. diff --git a/evaluate_test.go b/evaluate_test.go index 49c93d5..1335347 100644 --- a/evaluate_test.go +++ b/evaluate_test.go @@ -637,7 +637,7 @@ func BenchmarkEvaluate(b *testing.B) { b.Skip("Skipping benchmark - rerun with -bench-full to enable") } - expr, err := CreateEvaluator(expTest.expression, nil) + expr, err := CreateEvaluator(expTest.expression, WithHookFn(expTest.hook)) require.NoError(b, err) b.ResetTimer() From 2f46e1ae76ead846e88fd881e26b4cac775e9e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Thu, 7 Sep 2023 10:43:50 +0200 Subject: [PATCH 5/9] Simplify grammar and use options --- evaluate.go | 56 +- evaluate_test.go | 3 +- grammar/ast.go | 51 +- grammar/ast_test.go | 31 +- grammar/grammar.go | 1172 ++++++++++++++++++++------------------- grammar/grammar.peg | 63 ++- grammar/grammar_test.go | 57 +- 7 files changed, 764 insertions(+), 669 deletions(-) diff --git a/evaluate.go b/evaluate.go index 63232ae..0047d3c 100644 --- a/evaluate.go +++ b/evaluate.go @@ -373,7 +373,7 @@ func evaluateCollectionExpression(expression *grammar.CollectionExpression, datu return false, err } if !present { - return expression.Type == grammar.AllExpression, nil + return expression.Op == grammar.CollectionOpAll, nil } v := reflect.ValueOf(val) @@ -381,7 +381,7 @@ func evaluateCollectionExpression(expression *grammar.CollectionExpression, datu var keys []reflect.Value if v.Kind() == reflect.Map { if v.Type().Key() != reflect.TypeOf("") { - return false, fmt.Errorf("%s can only iterate over maps indexed with strings", expression.Type) + return false, fmt.Errorf("%s can only iterate over maps indexed with strings", expression.Op) } keys = v.MapKeys() } @@ -391,37 +391,37 @@ func evaluateCollectionExpression(expression *grammar.CollectionExpression, datu for i := 0; i < v.Len(); i++ { innerOpt := append([]Option(nil), opt...) + if expression.NameBinding.Mode == grammar.CollectionBindIndexAndValue && + expression.NameBinding.Index == expression.NameBinding.Value { + return false, fmt.Errorf("%q cannot be used as a placeholder for both the index and the value", expression.NameBinding.Index) + } + if v.Kind() == reflect.Map { key := keys[i] - if expression.Key != "_" { - innerOpt = append(innerOpt, WithLocalVariable(expression.Key, nil, key.Interface())) + if expression.NameBinding.Default != "" { + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Default, nil, key.Interface())) + } + if expression.NameBinding.Index != "" { + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Index, nil, key.Interface())) } - if expression.Value != "" && expression.Value != "_" { + if expression.NameBinding.Value != "" { path := append([]string(nil), expression.Selector.Path...) path = append(path, key.Interface().(string)) - innerOpt = append(innerOpt, WithLocalVariable(expression.Value, path, nil)) + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Value, path, nil)) } } else { - if expression.Value == "" { - // This means we are using the version with one placeholder - // like "all things as t { ... }". For lists t will iterate - // over the elements, not the indexes to match the behavior - // of the Sentinel for loop (or the "for t in things" in - // Python). This should match what users expect. - if expression.Key != "_" { - path := append([]string(nil), expression.Selector.Path...) - path = append(path, strconv.Itoa(i)) - innerOpt = append(innerOpt, WithLocalVariable(expression.Key, path, nil)) - } - } else { - if expression.Key != "_" { - innerOpt = append(innerOpt, WithLocalVariable(expression.Key, nil, i)) - } - if expression.Value != "_" { - path := append([]string(nil), expression.Selector.Path...) - path = append(path, strconv.Itoa(i)) - innerOpt = append(innerOpt, WithLocalVariable(expression.Value, path, nil)) - } + if expression.NameBinding.Default != "" { + path := append([]string(nil), expression.Selector.Path...) + path = append(path, fmt.Sprintf("%d", i)) + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Default, path, nil)) + } + if expression.NameBinding.Index != "" { + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Index, nil, i)) + } + if expression.NameBinding.Value != "" { + path := append([]string(nil), expression.Selector.Path...) + path = append(path, fmt.Sprintf("%d", i)) + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Value, path, nil)) } } @@ -429,12 +429,12 @@ func evaluateCollectionExpression(expression *grammar.CollectionExpression, datu if err != nil { return false, err } - if (result && expression.Type == grammar.AnyExpression) || (!result && expression.Type == grammar.AllExpression) { + if (result && expression.Op == grammar.CollectionOpAny) || (!result && expression.Op == grammar.CollectionOpAll) { return result, nil } } - return expression.Type == grammar.AllExpression, nil + return expression.Op == grammar.CollectionOpAll, nil default: return false, fmt.Errorf(`%s is not a list or a map`, expression.Selector.String()) diff --git a/evaluate_test.go b/evaluate_test.go index 1335347..0a40384 100644 --- a/evaluate_test.go +++ b/evaluate_test.go @@ -312,12 +312,11 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{ {expression: `"true" in "/Nested/SliceOfInfs"`, result: true}, {expression: `"/Nested/Map/email" matches "(foz|foo)@example.com"`, result: true}, // all - {expression: `all Nested.SliceOfInts as _ { TopInt == 5 }`, result: true}, {expression: `all Nested.SliceOfInts as i { i != 42 }`, result: true}, {expression: `all Nested.SliceOfInts as i { i == 1 }`, result: false}, {expression: `all Nested.Map as v { v == "bar" }`, result: false}, {expression: `all Nested.Map as v { v != "hello" }`, result: true}, - {expression: `all Nested.Map as _, _ { TopInt == 5 }`, result: true}, + {expression: `all Nested.Map as k, k { TopInt == 5 }`, err: `"k" cannot be used as a placeholder for both the index and the value`}, {expression: `all Nested.Map as k, _ { k != "foo" }`, result: false}, {expression: `all Nested.Map as k, _ { k != "hello" }`, result: true}, {expression: `all Nested.Map as k, v { k != "foo" or v != "baz" }`, result: true}, diff --git a/grammar/ast.go b/grammar/ast.go index 770201f..d6faab0 100644 --- a/grammar/ast.go +++ b/grammar/ast.go @@ -193,27 +193,54 @@ func (expr *MatchExpression) ExpressionDump(w io.Writer, indent string, level in } } -type CollectionExpressionType string +type CollectionBindMode string const ( - AllExpression CollectionExpressionType = "all" - AnyExpression CollectionExpressionType = "any" + CollectionBindDefault CollectionBindMode = "Default" + CollectionBindIndex CollectionBindMode = "Index" + CollectionBindValue CollectionBindMode = "Value" + CollectionBindIndexAndValue CollectionBindMode = "Index & Value" +) + +type CollectionNameBinding struct { + Mode CollectionBindMode + Default string + Index string + Value string +} + +func (b *CollectionNameBinding) String() string { + switch b.Mode { + case CollectionBindDefault: + return fmt.Sprintf("%v (%s)", b.Mode, b.Default) + case CollectionBindIndex: + return fmt.Sprintf("%v (%s)", b.Mode, b.Index) + case CollectionBindValue: + return fmt.Sprintf("%v (%s)", b.Mode, b.Value) + case CollectionBindIndexAndValue: + return fmt.Sprintf("%v (%s, %s)", b.Mode, b.Index, b.Value) + default: + return fmt.Sprintf("UNKNOWN (%s, %s, %s)", b.Default, b.Index, b.Value) + } +} + +type CollectionOperator string + +const ( + CollectionOpAll CollectionOperator = "ALL" + CollectionOpAny CollectionOperator = "ANY" ) type CollectionExpression struct { - Type CollectionExpressionType - Selector Selector - Inner Expression - Key, Value string + Op CollectionOperator + Selector Selector + Inner Expression + NameBinding CollectionNameBinding } func (expr *CollectionExpression) ExpressionDump(w io.Writer, indent string, level int) { localIndent := strings.Repeat(indent, level) - if expr.Value == "" { - fmt.Fprintf(w, "%s%s %s on %v {\n", localIndent, strings.ToUpper(string(expr.Type)), expr.Key, expr.Selector) - } else { - fmt.Fprintf(w, "%s%s (%s, %s) on %v {\n", localIndent, strings.ToUpper(string(expr.Type)), expr.Key, expr.Value, expr.Selector) - } + fmt.Fprintf(w, "%s%s %s on %v {\n", localIndent, expr.Op, expr.NameBinding.String(), expr.Selector) expr.Inner.ExpressionDump(w, indent, level+1) fmt.Fprintf(w, "%s}\n", localIndent) } diff --git a/grammar/ast_test.go b/grammar/ast_test.go index 96a86bd..21b25d4 100644 --- a/grammar/ast_test.go +++ b/grammar/ast_test.go @@ -80,9 +80,11 @@ func TestAST_Dump(t *testing.T) { }, "All single variation": { expr: &CollectionExpression{ - Key: "k", - Value: "", - Type: AllExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: "k", + }, + Op: CollectionOpAll, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"obj"}, @@ -98,13 +100,16 @@ func TestAST_Dump(t *testing.T) { }, }, }, - expected: "ALL k on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + expected: "ALL Default (k) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", }, "All": { expr: &CollectionExpression{ - Key: "k", - Value: "v", - Type: AllExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindIndexAndValue, + Index: "k", + Value: "v", + }, + Op: CollectionOpAll, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"obj"}, @@ -120,13 +125,15 @@ func TestAST_Dump(t *testing.T) { }, }, }, - expected: "ALL (k, v) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + expected: "ALL Index & Value (k, v) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", }, "Any": { expr: &CollectionExpression{ - Key: "k", - Value: "_", - Type: AnyExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindIndex, + Index: "k", + }, + Op: CollectionOpAny, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"obj"}, @@ -142,7 +149,7 @@ func TestAST_Dump(t *testing.T) { }, }, }, - expected: "ANY (k, _) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", + expected: "ANY Index (k) on obj {\n Equal {\n Selector: v\n Value: \"hello\"\n }\n}\n", }, } diff --git a/grammar/grammar.go b/grammar/grammar.go index fd8a81a..ad675ed 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -194,60 +194,48 @@ var g = &grammar{ }, }, }, - &actionExpr{ - pos: position{line: 28, col: 5, offset: 530}, - run: (*parser).callonOrExpression17, - expr: &labeledExpr{ - pos: position{line: 28, col: 5, offset: 530}, - label: "expr", - expr: &ruleRefExpr{ - pos: position{line: 28, col: 10, offset: 535}, - name: "CollectionExpressionWithKey", - }, - }, - }, }, }, }, { name: "AndExpression", - pos: position{line: 32, col: 1, offset: 588}, + pos: position{line: 30, col: 1, offset: 529}, expr: &choiceExpr{ - pos: position{line: 32, col: 18, offset: 605}, + pos: position{line: 30, col: 18, offset: 546}, alternatives: []any{ &actionExpr{ - pos: position{line: 32, col: 18, offset: 605}, + pos: position{line: 30, col: 18, offset: 546}, run: (*parser).callonAndExpression2, expr: &seqExpr{ - pos: position{line: 32, col: 18, offset: 605}, + pos: position{line: 30, col: 18, offset: 546}, exprs: []any{ &labeledExpr{ - pos: position{line: 32, col: 18, offset: 605}, + pos: position{line: 30, col: 18, offset: 546}, label: "left", expr: &ruleRefExpr{ - pos: position{line: 32, col: 23, offset: 610}, + pos: position{line: 30, col: 23, offset: 551}, name: "NotExpression", }, }, &ruleRefExpr{ - pos: position{line: 32, col: 37, offset: 624}, + pos: position{line: 30, col: 37, offset: 565}, name: "_", }, &litMatcher{ - pos: position{line: 32, col: 39, offset: 626}, + pos: position{line: 30, col: 39, offset: 567}, val: "and", ignoreCase: false, want: "\"and\"", }, &ruleRefExpr{ - pos: position{line: 32, col: 45, offset: 632}, + pos: position{line: 30, col: 45, offset: 573}, name: "_", }, &labeledExpr{ - pos: position{line: 32, col: 47, offset: 634}, + pos: position{line: 30, col: 47, offset: 575}, label: "right", expr: &ruleRefExpr{ - pos: position{line: 32, col: 53, offset: 640}, + pos: position{line: 30, col: 53, offset: 581}, name: "AndExpression", }, }, @@ -255,13 +243,13 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 38, col: 5, offset: 792}, + pos: position{line: 36, col: 5, offset: 733}, run: (*parser).callonAndExpression11, expr: &labeledExpr{ - pos: position{line: 38, col: 5, offset: 792}, + pos: position{line: 36, col: 5, offset: 733}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 38, col: 10, offset: 797}, + pos: position{line: 36, col: 10, offset: 738}, name: "NotExpression", }, }, @@ -271,31 +259,31 @@ var g = &grammar{ }, { name: "NotExpression", - pos: position{line: 42, col: 1, offset: 836}, + pos: position{line: 40, col: 1, offset: 777}, expr: &choiceExpr{ - pos: position{line: 42, col: 18, offset: 853}, + pos: position{line: 40, col: 18, offset: 794}, alternatives: []any{ &actionExpr{ - pos: position{line: 42, col: 18, offset: 853}, + pos: position{line: 40, col: 18, offset: 794}, run: (*parser).callonNotExpression2, expr: &seqExpr{ - pos: position{line: 42, col: 18, offset: 853}, + pos: position{line: 40, col: 18, offset: 794}, exprs: []any{ &litMatcher{ - pos: position{line: 42, col: 18, offset: 853}, + pos: position{line: 40, col: 18, offset: 794}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 42, col: 24, offset: 859}, + pos: position{line: 40, col: 24, offset: 800}, name: "_", }, &labeledExpr{ - pos: position{line: 42, col: 26, offset: 861}, + pos: position{line: 40, col: 26, offset: 802}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 42, col: 31, offset: 866}, + pos: position{line: 40, col: 31, offset: 807}, name: "NotExpression", }, }, @@ -303,13 +291,13 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 53, col: 5, offset: 1253}, + pos: position{line: 51, col: 5, offset: 1194}, run: (*parser).callonNotExpression8, expr: &labeledExpr{ - pos: position{line: 53, col: 5, offset: 1253}, + pos: position{line: 51, col: 5, offset: 1194}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 53, col: 10, offset: 1258}, + pos: position{line: 51, col: 10, offset: 1199}, name: "ParenthesizedExpression", }, }, @@ -319,116 +307,97 @@ var g = &grammar{ }, { name: "CollectionExpression", - pos: position{line: 57, col: 1, offset: 1307}, + pos: position{line: 55, col: 1, offset: 1248}, expr: &actionExpr{ - pos: position{line: 57, col: 25, offset: 1331}, + pos: position{line: 55, col: 25, offset: 1272}, run: (*parser).callonCollectionExpression1, expr: &seqExpr{ - pos: position{line: 57, col: 25, offset: 1331}, + pos: position{line: 55, col: 25, offset: 1272}, exprs: []any{ &labeledExpr{ - pos: position{line: 57, col: 25, offset: 1331}, - label: "operator", + pos: position{line: 55, col: 25, offset: 1272}, + label: "op", expr: &choiceExpr{ - pos: position{line: 57, col: 35, offset: 1341}, + pos: position{line: 55, col: 29, offset: 1276}, alternatives: []any{ - &litMatcher{ - pos: position{line: 57, col: 35, offset: 1341}, - val: "all", - ignoreCase: false, - want: "\"all\"", + &ruleRefExpr{ + pos: position{line: 55, col: 29, offset: 1276}, + name: "CollectionOpAny", }, - &litMatcher{ - pos: position{line: 57, col: 41, offset: 1347}, - val: "any", - ignoreCase: false, - want: "\"any\"", + &ruleRefExpr{ + pos: position{line: 55, col: 47, offset: 1294}, + name: "CollectionOpAll", }, }, }, }, - &ruleRefExpr{ - pos: position{line: 57, col: 48, offset: 1354}, - name: "_", - }, &labeledExpr{ - pos: position{line: 57, col: 50, offset: 1356}, + pos: position{line: 55, col: 64, offset: 1311}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 57, col: 59, offset: 1365}, + pos: position{line: 55, col: 73, offset: 1320}, name: "Selector", }, }, &ruleRefExpr{ - pos: position{line: 57, col: 68, offset: 1374}, + pos: position{line: 55, col: 82, offset: 1329}, name: "_", }, &litMatcher{ - pos: position{line: 57, col: 70, offset: 1376}, + pos: position{line: 55, col: 84, offset: 1331}, val: "as", ignoreCase: false, want: "\"as\"", }, &ruleRefExpr{ - pos: position{line: 57, col: 75, offset: 1381}, + pos: position{line: 55, col: 89, offset: 1336}, name: "_", }, &labeledExpr{ - pos: position{line: 57, col: 77, offset: 1383}, - label: "ident", - expr: &choiceExpr{ - pos: position{line: 57, col: 84, offset: 1390}, - alternatives: []any{ - &ruleRefExpr{ - pos: position{line: 57, col: 84, offset: 1390}, - name: "Identifier", - }, - &litMatcher{ - pos: position{line: 57, col: 97, offset: 1403}, - val: "_", - ignoreCase: false, - want: "\"_\"", - }, - }, + pos: position{line: 55, col: 91, offset: 1338}, + label: "binding", + expr: &ruleRefExpr{ + pos: position{line: 55, col: 99, offset: 1346}, + name: "CollectionIdentifiers", }, }, &zeroOrOneExpr{ - pos: position{line: 57, col: 102, offset: 1408}, + pos: position{line: 55, col: 121, offset: 1368}, expr: &ruleRefExpr{ - pos: position{line: 57, col: 102, offset: 1408}, + pos: position{line: 55, col: 121, offset: 1368}, name: "_", }, }, &litMatcher{ - pos: position{line: 57, col: 105, offset: 1411}, + pos: position{line: 55, col: 124, offset: 1371}, val: "{", ignoreCase: false, want: "\"{\"", }, &zeroOrOneExpr{ - pos: position{line: 57, col: 109, offset: 1415}, + pos: position{line: 55, col: 128, offset: 1375}, expr: &ruleRefExpr{ - pos: position{line: 57, col: 109, offset: 1415}, + pos: position{line: 55, col: 128, offset: 1375}, name: "_", }, }, &labeledExpr{ - pos: position{line: 57, col: 112, offset: 1418}, + pos: position{line: 55, col: 131, offset: 1378}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 57, col: 117, offset: 1423}, + pos: position{line: 55, col: 136, offset: 1383}, name: "OrExpression", }, }, &zeroOrOneExpr{ - pos: position{line: 57, col: 130, offset: 1436}, + pos: position{line: 55, col: 149, offset: 1396}, expr: &ruleRefExpr{ - pos: position{line: 57, col: 130, offset: 1436}, + pos: position{line: 55, col: 149, offset: 1396}, name: "_", }, }, &litMatcher{ - pos: position{line: 57, col: 133, offset: 1439}, + pos: position{line: 55, col: 152, offset: 1399}, val: "}", ignoreCase: false, want: "\"}\"", @@ -438,159 +407,199 @@ var g = &grammar{ }, }, { - name: "CollectionExpressionWithKey", - pos: position{line: 61, col: 1, offset: 1528}, - expr: &actionExpr{ - pos: position{line: 61, col: 32, offset: 1559}, - run: (*parser).callonCollectionExpressionWithKey1, - expr: &seqExpr{ - pos: position{line: 61, col: 32, offset: 1559}, - exprs: []any{ - &labeledExpr{ - pos: position{line: 61, col: 32, offset: 1559}, - label: "operator", - expr: &choiceExpr{ - pos: position{line: 61, col: 42, offset: 1569}, - alternatives: []any{ - &litMatcher{ - pos: position{line: 61, col: 42, offset: 1569}, - val: "all", - ignoreCase: false, - want: "\"all\"", + name: "CollectionIdentifiers", + displayName: "\"collection-identifiers\"", + pos: position{line: 64, col: 1, offset: 1625}, + expr: &choiceExpr{ + pos: position{line: 64, col: 51, offset: 1675}, + alternatives: []any{ + &actionExpr{ + pos: position{line: 64, col: 51, offset: 1675}, + run: (*parser).callonCollectionIdentifiers2, + expr: &seqExpr{ + pos: position{line: 64, col: 51, offset: 1675}, + exprs: []any{ + &labeledExpr{ + pos: position{line: 64, col: 51, offset: 1675}, + label: "id1", + expr: &ruleRefExpr{ + pos: position{line: 64, col: 55, offset: 1679}, + name: "Identifier", }, - &litMatcher{ - pos: position{line: 61, col: 48, offset: 1575}, - val: "any", - ignoreCase: false, - want: "\"any\"", + }, + &zeroOrOneExpr{ + pos: position{line: 64, col: 66, offset: 1690}, + expr: &ruleRefExpr{ + pos: position{line: 64, col: 66, offset: 1690}, + name: "_", + }, + }, + &litMatcher{ + pos: position{line: 64, col: 69, offset: 1693}, + val: ",", + ignoreCase: false, + want: "\",\"", + }, + &zeroOrOneExpr{ + pos: position{line: 64, col: 73, offset: 1697}, + expr: &ruleRefExpr{ + pos: position{line: 64, col: 73, offset: 1697}, + name: "_", + }, + }, + &labeledExpr{ + pos: position{line: 64, col: 76, offset: 1700}, + label: "id2", + expr: &ruleRefExpr{ + pos: position{line: 64, col: 80, offset: 1704}, + name: "Identifier", }, }, }, }, - &ruleRefExpr{ - pos: position{line: 61, col: 55, offset: 1582}, - name: "_", - }, - &labeledExpr{ - pos: position{line: 61, col: 57, offset: 1584}, - label: "selector", - expr: &ruleRefExpr{ - pos: position{line: 61, col: 66, offset: 1593}, - name: "Selector", - }, - }, - &ruleRefExpr{ - pos: position{line: 61, col: 75, offset: 1602}, - name: "_", - }, - &litMatcher{ - pos: position{line: 61, col: 77, offset: 1604}, - val: "as", - ignoreCase: false, - want: "\"as\"", - }, - &ruleRefExpr{ - pos: position{line: 61, col: 82, offset: 1609}, - name: "_", - }, - &labeledExpr{ - pos: position{line: 61, col: 84, offset: 1611}, - label: "key", - expr: &choiceExpr{ - pos: position{line: 61, col: 89, offset: 1616}, - alternatives: []any{ - &ruleRefExpr{ - pos: position{line: 61, col: 89, offset: 1616}, + }, + &actionExpr{ + pos: position{line: 70, col: 5, offset: 1859}, + run: (*parser).callonCollectionIdentifiers13, + expr: &seqExpr{ + pos: position{line: 70, col: 5, offset: 1859}, + exprs: []any{ + &labeledExpr{ + pos: position{line: 70, col: 5, offset: 1859}, + label: "id1", + expr: &ruleRefExpr{ + pos: position{line: 70, col: 9, offset: 1863}, name: "Identifier", }, - &litMatcher{ - pos: position{line: 61, col: 102, offset: 1629}, - val: "_", - ignoreCase: false, - want: "\"_\"", + }, + &zeroOrOneExpr{ + pos: position{line: 70, col: 20, offset: 1874}, + expr: &ruleRefExpr{ + pos: position{line: 70, col: 20, offset: 1874}, + name: "_", }, }, + &litMatcher{ + pos: position{line: 70, col: 23, offset: 1877}, + val: ",", + ignoreCase: false, + want: "\",\"", + }, + &zeroOrOneExpr{ + pos: position{line: 70, col: 27, offset: 1881}, + expr: &ruleRefExpr{ + pos: position{line: 70, col: 27, offset: 1881}, + name: "_", + }, + }, + &litMatcher{ + pos: position{line: 70, col: 30, offset: 1884}, + val: "_", + ignoreCase: false, + want: "\"_\"", + }, }, }, - &zeroOrOneExpr{ - pos: position{line: 61, col: 107, offset: 1634}, - expr: &ruleRefExpr{ - pos: position{line: 61, col: 107, offset: 1634}, - name: "_", - }, - }, - &litMatcher{ - pos: position{line: 61, col: 110, offset: 1637}, - val: ",", - ignoreCase: false, - want: "\",\"", - }, - &zeroOrOneExpr{ - pos: position{line: 61, col: 114, offset: 1641}, - expr: &ruleRefExpr{ - pos: position{line: 61, col: 114, offset: 1641}, - name: "_", - }, - }, - &labeledExpr{ - pos: position{line: 61, col: 117, offset: 1644}, - label: "value", - expr: &choiceExpr{ - pos: position{line: 61, col: 124, offset: 1651}, - alternatives: []any{ - &ruleRefExpr{ - pos: position{line: 61, col: 124, offset: 1651}, - name: "Identifier", + }, + &actionExpr{ + pos: position{line: 75, col: 5, offset: 1997}, + run: (*parser).callonCollectionIdentifiers23, + expr: &seqExpr{ + pos: position{line: 75, col: 5, offset: 1997}, + exprs: []any{ + &litMatcher{ + pos: position{line: 75, col: 5, offset: 1997}, + val: "_", + ignoreCase: false, + want: "\"_\"", + }, + &zeroOrOneExpr{ + pos: position{line: 75, col: 9, offset: 2001}, + expr: &ruleRefExpr{ + pos: position{line: 75, col: 9, offset: 2001}, + name: "_", }, - &litMatcher{ - pos: position{line: 61, col: 137, offset: 1664}, - val: "_", - ignoreCase: false, - want: "\"_\"", + }, + &litMatcher{ + pos: position{line: 75, col: 12, offset: 2004}, + val: ",", + ignoreCase: false, + want: "\",\"", + }, + &zeroOrOneExpr{ + pos: position{line: 75, col: 16, offset: 2008}, + expr: &ruleRefExpr{ + pos: position{line: 75, col: 16, offset: 2008}, + name: "_", + }, + }, + &labeledExpr{ + pos: position{line: 75, col: 19, offset: 2011}, + label: "id2", + expr: &ruleRefExpr{ + pos: position{line: 75, col: 23, offset: 2015}, + name: "Identifier", }, }, }, }, - &zeroOrOneExpr{ - pos: position{line: 61, col: 142, offset: 1669}, + }, + &actionExpr{ + pos: position{line: 80, col: 5, offset: 2135}, + run: (*parser).callonCollectionIdentifiers33, + expr: &labeledExpr{ + pos: position{line: 80, col: 5, offset: 2135}, + label: "id", expr: &ruleRefExpr{ - pos: position{line: 61, col: 142, offset: 1669}, - name: "_", + pos: position{line: 80, col: 8, offset: 2138}, + name: "Identifier", }, }, + }, + }, + }, + }, + { + name: "CollectionOpAny", + pos: position{line: 87, col: 1, offset: 2260}, + expr: &actionExpr{ + pos: position{line: 87, col: 20, offset: 2279}, + run: (*parser).callonCollectionOpAny1, + expr: &seqExpr{ + pos: position{line: 87, col: 20, offset: 2279}, + exprs: []any{ &litMatcher{ - pos: position{line: 61, col: 145, offset: 1672}, - val: "{", + pos: position{line: 87, col: 20, offset: 2279}, + val: "any", ignoreCase: false, - want: "\"{\"", + want: "\"any\"", }, - &zeroOrOneExpr{ - pos: position{line: 61, col: 149, offset: 1676}, - expr: &ruleRefExpr{ - pos: position{line: 61, col: 149, offset: 1676}, - name: "_", - }, - }, - &labeledExpr{ - pos: position{line: 61, col: 152, offset: 1679}, - label: "expr", - expr: &ruleRefExpr{ - pos: position{line: 61, col: 157, offset: 1684}, - name: "OrExpression", - }, - }, - &zeroOrOneExpr{ - pos: position{line: 61, col: 170, offset: 1697}, - expr: &ruleRefExpr{ - pos: position{line: 61, col: 170, offset: 1697}, - name: "_", - }, + &ruleRefExpr{ + pos: position{line: 87, col: 26, offset: 2285}, + name: "_", }, + }, + }, + }, + }, + { + name: "CollectionOpAll", + pos: position{line: 91, col: 1, offset: 2323}, + expr: &actionExpr{ + pos: position{line: 91, col: 20, offset: 2342}, + run: (*parser).callonCollectionOpAll1, + expr: &seqExpr{ + pos: position{line: 91, col: 20, offset: 2342}, + exprs: []any{ &litMatcher{ - pos: position{line: 61, col: 173, offset: 1700}, - val: "}", + pos: position{line: 91, col: 20, offset: 2342}, + val: "all", ignoreCase: false, - want: "\"}\"", + want: "\"all\"", + }, + &ruleRefExpr{ + pos: position{line: 91, col: 26, offset: 2348}, + name: "_", }, }, }, @@ -599,46 +608,46 @@ var g = &grammar{ { name: "ParenthesizedExpression", displayName: "\"grouping\"", - pos: position{line: 90, col: 1, offset: 2160}, + pos: position{line: 95, col: 1, offset: 2386}, expr: &choiceExpr{ - pos: position{line: 90, col: 39, offset: 2198}, + pos: position{line: 95, col: 39, offset: 2424}, alternatives: []any{ &actionExpr{ - pos: position{line: 90, col: 39, offset: 2198}, + pos: position{line: 95, col: 39, offset: 2424}, run: (*parser).callonParenthesizedExpression2, expr: &seqExpr{ - pos: position{line: 90, col: 39, offset: 2198}, + pos: position{line: 95, col: 39, offset: 2424}, exprs: []any{ &litMatcher{ - pos: position{line: 90, col: 39, offset: 2198}, + pos: position{line: 95, col: 39, offset: 2424}, val: "(", ignoreCase: false, want: "\"(\"", }, &zeroOrOneExpr{ - pos: position{line: 90, col: 43, offset: 2202}, + pos: position{line: 95, col: 43, offset: 2428}, expr: &ruleRefExpr{ - pos: position{line: 90, col: 43, offset: 2202}, + pos: position{line: 95, col: 43, offset: 2428}, name: "_", }, }, &labeledExpr{ - pos: position{line: 90, col: 46, offset: 2205}, + pos: position{line: 95, col: 46, offset: 2431}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 90, col: 51, offset: 2210}, + pos: position{line: 95, col: 51, offset: 2436}, name: "OrExpression", }, }, &zeroOrOneExpr{ - pos: position{line: 90, col: 64, offset: 2223}, + pos: position{line: 95, col: 64, offset: 2449}, expr: &ruleRefExpr{ - pos: position{line: 90, col: 64, offset: 2223}, + pos: position{line: 95, col: 64, offset: 2449}, name: "_", }, }, &litMatcher{ - pos: position{line: 90, col: 67, offset: 2226}, + pos: position{line: 95, col: 67, offset: 2452}, val: ")", ignoreCase: false, want: "\")\"", @@ -647,55 +656,55 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 92, col: 5, offset: 2256}, + pos: position{line: 97, col: 5, offset: 2482}, run: (*parser).callonParenthesizedExpression12, expr: &labeledExpr{ - pos: position{line: 92, col: 5, offset: 2256}, + pos: position{line: 97, col: 5, offset: 2482}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 92, col: 10, offset: 2261}, + pos: position{line: 97, col: 10, offset: 2487}, name: "MatchExpression", }, }, }, &seqExpr{ - pos: position{line: 94, col: 5, offset: 2303}, + pos: position{line: 99, col: 5, offset: 2529}, exprs: []any{ &litMatcher{ - pos: position{line: 94, col: 5, offset: 2303}, + pos: position{line: 99, col: 5, offset: 2529}, val: "(", ignoreCase: false, want: "\"(\"", }, &zeroOrOneExpr{ - pos: position{line: 94, col: 9, offset: 2307}, + pos: position{line: 99, col: 9, offset: 2533}, expr: &ruleRefExpr{ - pos: position{line: 94, col: 9, offset: 2307}, + pos: position{line: 99, col: 9, offset: 2533}, name: "_", }, }, &ruleRefExpr{ - pos: position{line: 94, col: 12, offset: 2310}, + pos: position{line: 99, col: 12, offset: 2536}, name: "OrExpression", }, &zeroOrOneExpr{ - pos: position{line: 94, col: 25, offset: 2323}, + pos: position{line: 99, col: 25, offset: 2549}, expr: &ruleRefExpr{ - pos: position{line: 94, col: 25, offset: 2323}, + pos: position{line: 99, col: 25, offset: 2549}, name: "_", }, }, ¬Expr{ - pos: position{line: 94, col: 28, offset: 2326}, + pos: position{line: 99, col: 28, offset: 2552}, expr: &litMatcher{ - pos: position{line: 94, col: 29, offset: 2327}, + pos: position{line: 99, col: 29, offset: 2553}, val: ")", ignoreCase: false, want: "\")\"", }, }, &andCodeExpr{ - pos: position{line: 94, col: 33, offset: 2331}, + pos: position{line: 99, col: 33, offset: 2557}, run: (*parser).callonParenthesizedExpression24, }, }, @@ -706,20 +715,20 @@ var g = &grammar{ { name: "MatchExpression", displayName: "\"match\"", - pos: position{line: 98, col: 1, offset: 2390}, + pos: position{line: 103, col: 1, offset: 2616}, expr: &choiceExpr{ - pos: position{line: 98, col: 28, offset: 2417}, + pos: position{line: 103, col: 28, offset: 2643}, alternatives: []any{ &ruleRefExpr{ - pos: position{line: 98, col: 28, offset: 2417}, + pos: position{line: 103, col: 28, offset: 2643}, name: "MatchSelectorOpValue", }, &ruleRefExpr{ - pos: position{line: 98, col: 51, offset: 2440}, + pos: position{line: 103, col: 51, offset: 2666}, name: "MatchSelectorOp", }, &ruleRefExpr{ - pos: position{line: 98, col: 69, offset: 2458}, + pos: position{line: 103, col: 69, offset: 2684}, name: "MatchValueOpSelector", }, }, @@ -728,59 +737,59 @@ var g = &grammar{ { name: "MatchSelectorOpValue", displayName: "\"match\"", - pos: position{line: 100, col: 1, offset: 2480}, + pos: position{line: 105, col: 1, offset: 2706}, expr: &actionExpr{ - pos: position{line: 100, col: 33, offset: 2512}, + pos: position{line: 105, col: 33, offset: 2738}, run: (*parser).callonMatchSelectorOpValue1, expr: &seqExpr{ - pos: position{line: 100, col: 33, offset: 2512}, + pos: position{line: 105, col: 33, offset: 2738}, exprs: []any{ &labeledExpr{ - pos: position{line: 100, col: 33, offset: 2512}, + pos: position{line: 105, col: 33, offset: 2738}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 100, col: 42, offset: 2521}, + pos: position{line: 105, col: 42, offset: 2747}, name: "Selector", }, }, &labeledExpr{ - pos: position{line: 100, col: 51, offset: 2530}, + pos: position{line: 105, col: 51, offset: 2756}, label: "operator", expr: &choiceExpr{ - pos: position{line: 100, col: 61, offset: 2540}, + pos: position{line: 105, col: 61, offset: 2766}, alternatives: []any{ &ruleRefExpr{ - pos: position{line: 100, col: 61, offset: 2540}, + pos: position{line: 105, col: 61, offset: 2766}, name: "MatchEqual", }, &ruleRefExpr{ - pos: position{line: 100, col: 74, offset: 2553}, + pos: position{line: 105, col: 74, offset: 2779}, name: "MatchNotEqual", }, &ruleRefExpr{ - pos: position{line: 100, col: 90, offset: 2569}, + pos: position{line: 105, col: 90, offset: 2795}, name: "MatchContains", }, &ruleRefExpr{ - pos: position{line: 100, col: 106, offset: 2585}, + pos: position{line: 105, col: 106, offset: 2811}, name: "MatchNotContains", }, &ruleRefExpr{ - pos: position{line: 100, col: 125, offset: 2604}, + pos: position{line: 105, col: 125, offset: 2830}, name: "MatchMatches", }, &ruleRefExpr{ - pos: position{line: 100, col: 140, offset: 2619}, + pos: position{line: 105, col: 140, offset: 2845}, name: "MatchNotMatches", }, }, }, }, &labeledExpr{ - pos: position{line: 100, col: 157, offset: 2636}, + pos: position{line: 105, col: 157, offset: 2862}, label: "value", expr: &ruleRefExpr{ - pos: position{line: 100, col: 163, offset: 2642}, + pos: position{line: 105, col: 163, offset: 2868}, name: "Value", }, }, @@ -791,33 +800,33 @@ var g = &grammar{ { name: "MatchSelectorOp", displayName: "\"match\"", - pos: position{line: 104, col: 1, offset: 2780}, + pos: position{line: 109, col: 1, offset: 3006}, expr: &actionExpr{ - pos: position{line: 104, col: 28, offset: 2807}, + pos: position{line: 109, col: 28, offset: 3033}, run: (*parser).callonMatchSelectorOp1, expr: &seqExpr{ - pos: position{line: 104, col: 28, offset: 2807}, + pos: position{line: 109, col: 28, offset: 3033}, exprs: []any{ &labeledExpr{ - pos: position{line: 104, col: 28, offset: 2807}, + pos: position{line: 109, col: 28, offset: 3033}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 104, col: 37, offset: 2816}, + pos: position{line: 109, col: 37, offset: 3042}, name: "Selector", }, }, &labeledExpr{ - pos: position{line: 104, col: 46, offset: 2825}, + pos: position{line: 109, col: 46, offset: 3051}, label: "operator", expr: &choiceExpr{ - pos: position{line: 104, col: 56, offset: 2835}, + pos: position{line: 109, col: 56, offset: 3061}, alternatives: []any{ &ruleRefExpr{ - pos: position{line: 104, col: 56, offset: 2835}, + pos: position{line: 109, col: 56, offset: 3061}, name: "MatchIsEmpty", }, &ruleRefExpr{ - pos: position{line: 104, col: 71, offset: 2850}, + pos: position{line: 109, col: 71, offset: 3076}, name: "MatchIsNotEmpty", }, }, @@ -830,46 +839,46 @@ var g = &grammar{ { name: "MatchValueOpSelector", displayName: "\"match\"", - pos: position{line: 108, col: 1, offset: 2983}, + pos: position{line: 113, col: 1, offset: 3209}, expr: &choiceExpr{ - pos: position{line: 108, col: 33, offset: 3015}, + pos: position{line: 113, col: 33, offset: 3241}, alternatives: []any{ &actionExpr{ - pos: position{line: 108, col: 33, offset: 3015}, + pos: position{line: 113, col: 33, offset: 3241}, run: (*parser).callonMatchValueOpSelector2, expr: &seqExpr{ - pos: position{line: 108, col: 33, offset: 3015}, + pos: position{line: 113, col: 33, offset: 3241}, exprs: []any{ &labeledExpr{ - pos: position{line: 108, col: 33, offset: 3015}, + pos: position{line: 113, col: 33, offset: 3241}, label: "value", expr: &ruleRefExpr{ - pos: position{line: 108, col: 39, offset: 3021}, + pos: position{line: 113, col: 39, offset: 3247}, name: "Value", }, }, &labeledExpr{ - pos: position{line: 108, col: 45, offset: 3027}, + pos: position{line: 113, col: 45, offset: 3253}, label: "operator", expr: &choiceExpr{ - pos: position{line: 108, col: 55, offset: 3037}, + pos: position{line: 113, col: 55, offset: 3263}, alternatives: []any{ &ruleRefExpr{ - pos: position{line: 108, col: 55, offset: 3037}, + pos: position{line: 113, col: 55, offset: 3263}, name: "MatchIn", }, &ruleRefExpr{ - pos: position{line: 108, col: 65, offset: 3047}, + pos: position{line: 113, col: 65, offset: 3273}, name: "MatchNotIn", }, }, }, }, &labeledExpr{ - pos: position{line: 108, col: 77, offset: 3059}, + pos: position{line: 113, col: 77, offset: 3285}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 108, col: 86, offset: 3068}, + pos: position{line: 113, col: 86, offset: 3294}, name: "Selector", }, }, @@ -877,38 +886,38 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 110, col: 5, offset: 3210}, + pos: position{line: 115, col: 5, offset: 3436}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 110, col: 5, offset: 3210}, + pos: position{line: 115, col: 5, offset: 3436}, name: "Value", }, &labeledExpr{ - pos: position{line: 110, col: 11, offset: 3216}, + pos: position{line: 115, col: 11, offset: 3442}, label: "operator", expr: &choiceExpr{ - pos: position{line: 110, col: 21, offset: 3226}, + pos: position{line: 115, col: 21, offset: 3452}, alternatives: []any{ &ruleRefExpr{ - pos: position{line: 110, col: 21, offset: 3226}, + pos: position{line: 115, col: 21, offset: 3452}, name: "MatchIn", }, &ruleRefExpr{ - pos: position{line: 110, col: 31, offset: 3236}, + pos: position{line: 115, col: 31, offset: 3462}, name: "MatchNotIn", }, }, }, }, ¬Expr{ - pos: position{line: 110, col: 43, offset: 3248}, + pos: position{line: 115, col: 43, offset: 3474}, expr: &ruleRefExpr{ - pos: position{line: 110, col: 44, offset: 3249}, + pos: position{line: 115, col: 44, offset: 3475}, name: "Selector", }, }, &andCodeExpr{ - pos: position{line: 110, col: 53, offset: 3258}, + pos: position{line: 115, col: 53, offset: 3484}, run: (*parser).callonMatchValueOpSelector20, }, }, @@ -918,30 +927,30 @@ var g = &grammar{ }, { name: "MatchEqual", - pos: position{line: 114, col: 1, offset: 3312}, + pos: position{line: 119, col: 1, offset: 3538}, expr: &actionExpr{ - pos: position{line: 114, col: 15, offset: 3326}, + pos: position{line: 119, col: 15, offset: 3552}, run: (*parser).callonMatchEqual1, expr: &seqExpr{ - pos: position{line: 114, col: 15, offset: 3326}, + pos: position{line: 119, col: 15, offset: 3552}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 114, col: 15, offset: 3326}, + pos: position{line: 119, col: 15, offset: 3552}, expr: &ruleRefExpr{ - pos: position{line: 114, col: 15, offset: 3326}, + pos: position{line: 119, col: 15, offset: 3552}, name: "_", }, }, &litMatcher{ - pos: position{line: 114, col: 18, offset: 3329}, + pos: position{line: 119, col: 18, offset: 3555}, val: "==", ignoreCase: false, want: "\"==\"", }, &zeroOrOneExpr{ - pos: position{line: 114, col: 23, offset: 3334}, + pos: position{line: 119, col: 23, offset: 3560}, expr: &ruleRefExpr{ - pos: position{line: 114, col: 23, offset: 3334}, + pos: position{line: 119, col: 23, offset: 3560}, name: "_", }, }, @@ -951,30 +960,30 @@ var g = &grammar{ }, { name: "MatchNotEqual", - pos: position{line: 117, col: 1, offset: 3367}, + pos: position{line: 122, col: 1, offset: 3593}, expr: &actionExpr{ - pos: position{line: 117, col: 18, offset: 3384}, + pos: position{line: 122, col: 18, offset: 3610}, run: (*parser).callonMatchNotEqual1, expr: &seqExpr{ - pos: position{line: 117, col: 18, offset: 3384}, + pos: position{line: 122, col: 18, offset: 3610}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 117, col: 18, offset: 3384}, + pos: position{line: 122, col: 18, offset: 3610}, expr: &ruleRefExpr{ - pos: position{line: 117, col: 18, offset: 3384}, + pos: position{line: 122, col: 18, offset: 3610}, name: "_", }, }, &litMatcher{ - pos: position{line: 117, col: 21, offset: 3387}, + pos: position{line: 122, col: 21, offset: 3613}, val: "!=", ignoreCase: false, want: "\"!=\"", }, &zeroOrOneExpr{ - pos: position{line: 117, col: 26, offset: 3392}, + pos: position{line: 122, col: 26, offset: 3618}, expr: &ruleRefExpr{ - pos: position{line: 117, col: 26, offset: 3392}, + pos: position{line: 122, col: 26, offset: 3618}, name: "_", }, }, @@ -984,29 +993,29 @@ var g = &grammar{ }, { name: "MatchIsEmpty", - pos: position{line: 120, col: 1, offset: 3428}, + pos: position{line: 125, col: 1, offset: 3654}, expr: &actionExpr{ - pos: position{line: 120, col: 17, offset: 3444}, + pos: position{line: 125, col: 17, offset: 3670}, run: (*parser).callonMatchIsEmpty1, expr: &seqExpr{ - pos: position{line: 120, col: 17, offset: 3444}, + pos: position{line: 125, col: 17, offset: 3670}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 120, col: 17, offset: 3444}, + pos: position{line: 125, col: 17, offset: 3670}, name: "_", }, &litMatcher{ - pos: position{line: 120, col: 19, offset: 3446}, + pos: position{line: 125, col: 19, offset: 3672}, val: "is", ignoreCase: false, want: "\"is\"", }, &ruleRefExpr{ - pos: position{line: 120, col: 24, offset: 3451}, + pos: position{line: 125, col: 24, offset: 3677}, name: "_", }, &litMatcher{ - pos: position{line: 120, col: 26, offset: 3453}, + pos: position{line: 125, col: 26, offset: 3679}, val: "empty", ignoreCase: false, want: "\"empty\"", @@ -1017,39 +1026,39 @@ var g = &grammar{ }, { name: "MatchIsNotEmpty", - pos: position{line: 123, col: 1, offset: 3493}, + pos: position{line: 128, col: 1, offset: 3719}, expr: &actionExpr{ - pos: position{line: 123, col: 20, offset: 3512}, + pos: position{line: 128, col: 20, offset: 3738}, run: (*parser).callonMatchIsNotEmpty1, expr: &seqExpr{ - pos: position{line: 123, col: 20, offset: 3512}, + pos: position{line: 128, col: 20, offset: 3738}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 123, col: 20, offset: 3512}, + pos: position{line: 128, col: 20, offset: 3738}, name: "_", }, &litMatcher{ - pos: position{line: 123, col: 21, offset: 3513}, + pos: position{line: 128, col: 21, offset: 3739}, val: "is", ignoreCase: false, want: "\"is\"", }, &ruleRefExpr{ - pos: position{line: 123, col: 26, offset: 3518}, + pos: position{line: 128, col: 26, offset: 3744}, name: "_", }, &litMatcher{ - pos: position{line: 123, col: 28, offset: 3520}, + pos: position{line: 128, col: 28, offset: 3746}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 123, col: 34, offset: 3526}, + pos: position{line: 128, col: 34, offset: 3752}, name: "_", }, &litMatcher{ - pos: position{line: 123, col: 36, offset: 3528}, + pos: position{line: 128, col: 36, offset: 3754}, val: "empty", ignoreCase: false, want: "\"empty\"", @@ -1060,25 +1069,25 @@ var g = &grammar{ }, { name: "MatchIn", - pos: position{line: 126, col: 1, offset: 3571}, + pos: position{line: 131, col: 1, offset: 3797}, expr: &actionExpr{ - pos: position{line: 126, col: 12, offset: 3582}, + pos: position{line: 131, col: 12, offset: 3808}, run: (*parser).callonMatchIn1, expr: &seqExpr{ - pos: position{line: 126, col: 12, offset: 3582}, + pos: position{line: 131, col: 12, offset: 3808}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 126, col: 12, offset: 3582}, + pos: position{line: 131, col: 12, offset: 3808}, name: "_", }, &litMatcher{ - pos: position{line: 126, col: 14, offset: 3584}, + pos: position{line: 131, col: 14, offset: 3810}, val: "in", ignoreCase: false, want: "\"in\"", }, &ruleRefExpr{ - pos: position{line: 126, col: 19, offset: 3589}, + pos: position{line: 131, col: 19, offset: 3815}, name: "_", }, }, @@ -1087,35 +1096,35 @@ var g = &grammar{ }, { name: "MatchNotIn", - pos: position{line: 129, col: 1, offset: 3618}, + pos: position{line: 134, col: 1, offset: 3844}, expr: &actionExpr{ - pos: position{line: 129, col: 15, offset: 3632}, + pos: position{line: 134, col: 15, offset: 3858}, run: (*parser).callonMatchNotIn1, expr: &seqExpr{ - pos: position{line: 129, col: 15, offset: 3632}, + pos: position{line: 134, col: 15, offset: 3858}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 129, col: 15, offset: 3632}, + pos: position{line: 134, col: 15, offset: 3858}, name: "_", }, &litMatcher{ - pos: position{line: 129, col: 17, offset: 3634}, + pos: position{line: 134, col: 17, offset: 3860}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 129, col: 23, offset: 3640}, + pos: position{line: 134, col: 23, offset: 3866}, name: "_", }, &litMatcher{ - pos: position{line: 129, col: 25, offset: 3642}, + pos: position{line: 134, col: 25, offset: 3868}, val: "in", ignoreCase: false, want: "\"in\"", }, &ruleRefExpr{ - pos: position{line: 129, col: 30, offset: 3647}, + pos: position{line: 134, col: 30, offset: 3873}, name: "_", }, }, @@ -1124,25 +1133,25 @@ var g = &grammar{ }, { name: "MatchContains", - pos: position{line: 132, col: 1, offset: 3679}, + pos: position{line: 137, col: 1, offset: 3905}, expr: &actionExpr{ - pos: position{line: 132, col: 18, offset: 3696}, + pos: position{line: 137, col: 18, offset: 3922}, run: (*parser).callonMatchContains1, expr: &seqExpr{ - pos: position{line: 132, col: 18, offset: 3696}, + pos: position{line: 137, col: 18, offset: 3922}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 132, col: 18, offset: 3696}, + pos: position{line: 137, col: 18, offset: 3922}, name: "_", }, &litMatcher{ - pos: position{line: 132, col: 20, offset: 3698}, + pos: position{line: 137, col: 20, offset: 3924}, val: "contains", ignoreCase: false, want: "\"contains\"", }, &ruleRefExpr{ - pos: position{line: 132, col: 31, offset: 3709}, + pos: position{line: 137, col: 31, offset: 3935}, name: "_", }, }, @@ -1151,35 +1160,35 @@ var g = &grammar{ }, { name: "MatchNotContains", - pos: position{line: 135, col: 1, offset: 3738}, + pos: position{line: 140, col: 1, offset: 3964}, expr: &actionExpr{ - pos: position{line: 135, col: 21, offset: 3758}, + pos: position{line: 140, col: 21, offset: 3984}, run: (*parser).callonMatchNotContains1, expr: &seqExpr{ - pos: position{line: 135, col: 21, offset: 3758}, + pos: position{line: 140, col: 21, offset: 3984}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 135, col: 21, offset: 3758}, + pos: position{line: 140, col: 21, offset: 3984}, name: "_", }, &litMatcher{ - pos: position{line: 135, col: 23, offset: 3760}, + pos: position{line: 140, col: 23, offset: 3986}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 135, col: 29, offset: 3766}, + pos: position{line: 140, col: 29, offset: 3992}, name: "_", }, &litMatcher{ - pos: position{line: 135, col: 31, offset: 3768}, + pos: position{line: 140, col: 31, offset: 3994}, val: "contains", ignoreCase: false, want: "\"contains\"", }, &ruleRefExpr{ - pos: position{line: 135, col: 42, offset: 3779}, + pos: position{line: 140, col: 42, offset: 4005}, name: "_", }, }, @@ -1188,25 +1197,25 @@ var g = &grammar{ }, { name: "MatchMatches", - pos: position{line: 138, col: 1, offset: 3811}, + pos: position{line: 143, col: 1, offset: 4037}, expr: &actionExpr{ - pos: position{line: 138, col: 17, offset: 3827}, + pos: position{line: 143, col: 17, offset: 4053}, run: (*parser).callonMatchMatches1, expr: &seqExpr{ - pos: position{line: 138, col: 17, offset: 3827}, + pos: position{line: 143, col: 17, offset: 4053}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 138, col: 17, offset: 3827}, + pos: position{line: 143, col: 17, offset: 4053}, name: "_", }, &litMatcher{ - pos: position{line: 138, col: 19, offset: 3829}, + pos: position{line: 143, col: 19, offset: 4055}, val: "matches", ignoreCase: false, want: "\"matches\"", }, &ruleRefExpr{ - pos: position{line: 138, col: 29, offset: 3839}, + pos: position{line: 143, col: 29, offset: 4065}, name: "_", }, }, @@ -1215,35 +1224,35 @@ var g = &grammar{ }, { name: "MatchNotMatches", - pos: position{line: 141, col: 1, offset: 3873}, + pos: position{line: 146, col: 1, offset: 4099}, expr: &actionExpr{ - pos: position{line: 141, col: 20, offset: 3892}, + pos: position{line: 146, col: 20, offset: 4118}, run: (*parser).callonMatchNotMatches1, expr: &seqExpr{ - pos: position{line: 141, col: 20, offset: 3892}, + pos: position{line: 146, col: 20, offset: 4118}, exprs: []any{ &ruleRefExpr{ - pos: position{line: 141, col: 20, offset: 3892}, + pos: position{line: 146, col: 20, offset: 4118}, name: "_", }, &litMatcher{ - pos: position{line: 141, col: 22, offset: 3894}, + pos: position{line: 146, col: 22, offset: 4120}, val: "not", ignoreCase: false, want: "\"not\"", }, &ruleRefExpr{ - pos: position{line: 141, col: 28, offset: 3900}, + pos: position{line: 146, col: 28, offset: 4126}, name: "_", }, &litMatcher{ - pos: position{line: 141, col: 30, offset: 3902}, + pos: position{line: 146, col: 30, offset: 4128}, val: "matches", ignoreCase: false, want: "\"matches\"", }, &ruleRefExpr{ - pos: position{line: 141, col: 40, offset: 3912}, + pos: position{line: 146, col: 40, offset: 4138}, name: "_", }, }, @@ -1253,31 +1262,31 @@ var g = &grammar{ { name: "Selector", displayName: "\"selector\"", - pos: position{line: 145, col: 1, offset: 3950}, + pos: position{line: 150, col: 1, offset: 4176}, expr: &choiceExpr{ - pos: position{line: 145, col: 24, offset: 3973}, + pos: position{line: 150, col: 24, offset: 4199}, alternatives: []any{ &actionExpr{ - pos: position{line: 145, col: 24, offset: 3973}, + pos: position{line: 150, col: 24, offset: 4199}, run: (*parser).callonSelector2, expr: &seqExpr{ - pos: position{line: 145, col: 24, offset: 3973}, + pos: position{line: 150, col: 24, offset: 4199}, exprs: []any{ &labeledExpr{ - pos: position{line: 145, col: 24, offset: 3973}, + pos: position{line: 150, col: 24, offset: 4199}, label: "first", expr: &ruleRefExpr{ - pos: position{line: 145, col: 30, offset: 3979}, + pos: position{line: 150, col: 30, offset: 4205}, name: "Identifier", }, }, &labeledExpr{ - pos: position{line: 145, col: 41, offset: 3990}, + pos: position{line: 150, col: 41, offset: 4216}, label: "rest", expr: &zeroOrMoreExpr{ - pos: position{line: 145, col: 46, offset: 3995}, + pos: position{line: 150, col: 46, offset: 4221}, expr: &ruleRefExpr{ - pos: position{line: 145, col: 46, offset: 3995}, + pos: position{line: 150, col: 46, offset: 4221}, name: "SelectorOrIndex", }, }, @@ -1286,30 +1295,30 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 156, col: 5, offset: 4259}, + pos: position{line: 161, col: 5, offset: 4485}, run: (*parser).callonSelector9, expr: &seqExpr{ - pos: position{line: 156, col: 5, offset: 4259}, + pos: position{line: 161, col: 5, offset: 4485}, exprs: []any{ &litMatcher{ - pos: position{line: 156, col: 5, offset: 4259}, + pos: position{line: 161, col: 5, offset: 4485}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &labeledExpr{ - pos: position{line: 156, col: 9, offset: 4263}, + pos: position{line: 161, col: 9, offset: 4489}, label: "ptrsegs", expr: &zeroOrMoreExpr{ - pos: position{line: 156, col: 17, offset: 4271}, + pos: position{line: 161, col: 17, offset: 4497}, expr: &ruleRefExpr{ - pos: position{line: 156, col: 17, offset: 4271}, + pos: position{line: 161, col: 17, offset: 4497}, name: "JsonPointerSegment", }, }, }, &litMatcher{ - pos: position{line: 156, col: 37, offset: 4291}, + pos: position{line: 161, col: 37, offset: 4517}, val: "\"", ignoreCase: false, want: "\"\\\"\"", @@ -1322,26 +1331,26 @@ var g = &grammar{ }, { name: "JsonPointerSegment", - pos: position{line: 177, col: 1, offset: 4769}, + pos: position{line: 182, col: 1, offset: 4995}, expr: &actionExpr{ - pos: position{line: 177, col: 23, offset: 4791}, + pos: position{line: 182, col: 23, offset: 5017}, run: (*parser).callonJsonPointerSegment1, expr: &seqExpr{ - pos: position{line: 177, col: 23, offset: 4791}, + pos: position{line: 182, col: 23, offset: 5017}, exprs: []any{ &litMatcher{ - pos: position{line: 177, col: 23, offset: 4791}, + pos: position{line: 182, col: 23, offset: 5017}, val: "/", ignoreCase: false, want: "\"/\"", }, &labeledExpr{ - pos: position{line: 177, col: 27, offset: 4795}, + pos: position{line: 182, col: 27, offset: 5021}, label: "ident", expr: &oneOrMoreExpr{ - pos: position{line: 177, col: 33, offset: 4801}, + pos: position{line: 182, col: 33, offset: 5027}, expr: &charClassMatcher{ - pos: position{line: 177, col: 33, offset: 4801}, + pos: position{line: 182, col: 33, offset: 5027}, val: "[\\pL\\pN-_.~:|]", chars: []rune{'-', '_', '.', '~', ':', '|'}, classes: []*unicode.RangeTable{rangeTable("L"), rangeTable("N")}, @@ -1356,24 +1365,24 @@ var g = &grammar{ }, { name: "Identifier", - pos: position{line: 181, col: 1, offset: 4856}, + pos: position{line: 186, col: 1, offset: 5082}, expr: &actionExpr{ - pos: position{line: 181, col: 15, offset: 4870}, + pos: position{line: 186, col: 15, offset: 5096}, run: (*parser).callonIdentifier1, expr: &seqExpr{ - pos: position{line: 181, col: 15, offset: 4870}, + pos: position{line: 186, col: 15, offset: 5096}, exprs: []any{ &charClassMatcher{ - pos: position{line: 181, col: 15, offset: 4870}, + pos: position{line: 186, col: 15, offset: 5096}, val: "[a-zA-Z]", ranges: []rune{'a', 'z', 'A', 'Z'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 181, col: 24, offset: 4879}, + pos: position{line: 186, col: 24, offset: 5105}, expr: &charClassMatcher{ - pos: position{line: 181, col: 24, offset: 4879}, + pos: position{line: 186, col: 24, offset: 5105}, val: "[a-zA-Z0-9_/]", chars: []rune{'_', '/'}, ranges: []rune{'a', 'z', 'A', 'Z', '0', '9'}, @@ -1387,27 +1396,27 @@ var g = &grammar{ }, { name: "SelectorOrIndex", - pos: position{line: 185, col: 1, offset: 4929}, + pos: position{line: 190, col: 1, offset: 5155}, expr: &choiceExpr{ - pos: position{line: 185, col: 20, offset: 4948}, + pos: position{line: 190, col: 20, offset: 5174}, alternatives: []any{ &actionExpr{ - pos: position{line: 185, col: 20, offset: 4948}, + pos: position{line: 190, col: 20, offset: 5174}, run: (*parser).callonSelectorOrIndex2, expr: &seqExpr{ - pos: position{line: 185, col: 20, offset: 4948}, + pos: position{line: 190, col: 20, offset: 5174}, exprs: []any{ &litMatcher{ - pos: position{line: 185, col: 20, offset: 4948}, + pos: position{line: 190, col: 20, offset: 5174}, val: ".", ignoreCase: false, want: "\".\"", }, &labeledExpr{ - pos: position{line: 185, col: 24, offset: 4952}, + pos: position{line: 190, col: 24, offset: 5178}, label: "ident", expr: &ruleRefExpr{ - pos: position{line: 185, col: 30, offset: 4958}, + pos: position{line: 190, col: 30, offset: 5184}, name: "Identifier", }, }, @@ -1415,36 +1424,36 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 187, col: 5, offset: 4996}, + pos: position{line: 192, col: 5, offset: 5222}, run: (*parser).callonSelectorOrIndex7, expr: &labeledExpr{ - pos: position{line: 187, col: 5, offset: 4996}, + pos: position{line: 192, col: 5, offset: 5222}, label: "expr", expr: &ruleRefExpr{ - pos: position{line: 187, col: 10, offset: 5001}, + pos: position{line: 192, col: 10, offset: 5227}, name: "IndexExpression", }, }, }, &actionExpr{ - pos: position{line: 189, col: 5, offset: 5043}, + pos: position{line: 194, col: 5, offset: 5269}, run: (*parser).callonSelectorOrIndex10, expr: &seqExpr{ - pos: position{line: 189, col: 5, offset: 5043}, + pos: position{line: 194, col: 5, offset: 5269}, exprs: []any{ &litMatcher{ - pos: position{line: 189, col: 5, offset: 5043}, + pos: position{line: 194, col: 5, offset: 5269}, val: ".", ignoreCase: false, want: "\".\"", }, &labeledExpr{ - pos: position{line: 189, col: 9, offset: 5047}, + pos: position{line: 194, col: 9, offset: 5273}, label: "idx", expr: &oneOrMoreExpr{ - pos: position{line: 189, col: 13, offset: 5051}, + pos: position{line: 194, col: 13, offset: 5277}, expr: &charClassMatcher{ - pos: position{line: 189, col: 13, offset: 5051}, + pos: position{line: 194, col: 13, offset: 5277}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1461,46 +1470,46 @@ var g = &grammar{ { name: "IndexExpression", displayName: "\"index\"", - pos: position{line: 193, col: 1, offset: 5097}, + pos: position{line: 198, col: 1, offset: 5323}, expr: &choiceExpr{ - pos: position{line: 193, col: 28, offset: 5124}, + pos: position{line: 198, col: 28, offset: 5350}, alternatives: []any{ &actionExpr{ - pos: position{line: 193, col: 28, offset: 5124}, + pos: position{line: 198, col: 28, offset: 5350}, run: (*parser).callonIndexExpression2, expr: &seqExpr{ - pos: position{line: 193, col: 28, offset: 5124}, + pos: position{line: 198, col: 28, offset: 5350}, exprs: []any{ &litMatcher{ - pos: position{line: 193, col: 28, offset: 5124}, + pos: position{line: 198, col: 28, offset: 5350}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 193, col: 32, offset: 5128}, + pos: position{line: 198, col: 32, offset: 5354}, expr: &ruleRefExpr{ - pos: position{line: 193, col: 32, offset: 5128}, + pos: position{line: 198, col: 32, offset: 5354}, name: "_", }, }, &labeledExpr{ - pos: position{line: 193, col: 35, offset: 5131}, + pos: position{line: 198, col: 35, offset: 5357}, label: "lit", expr: &ruleRefExpr{ - pos: position{line: 193, col: 39, offset: 5135}, + pos: position{line: 198, col: 39, offset: 5361}, name: "StringLiteral", }, }, &zeroOrOneExpr{ - pos: position{line: 193, col: 53, offset: 5149}, + pos: position{line: 198, col: 53, offset: 5375}, expr: &ruleRefExpr{ - pos: position{line: 193, col: 53, offset: 5149}, + pos: position{line: 198, col: 53, offset: 5375}, name: "_", }, }, &litMatcher{ - pos: position{line: 193, col: 56, offset: 5152}, + pos: position{line: 198, col: 56, offset: 5378}, val: "]", ignoreCase: false, want: "\"]\"", @@ -1509,72 +1518,72 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 195, col: 5, offset: 5181}, + pos: position{line: 200, col: 5, offset: 5407}, exprs: []any{ &litMatcher{ - pos: position{line: 195, col: 5, offset: 5181}, + pos: position{line: 200, col: 5, offset: 5407}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 195, col: 9, offset: 5185}, + pos: position{line: 200, col: 9, offset: 5411}, expr: &ruleRefExpr{ - pos: position{line: 195, col: 9, offset: 5185}, + pos: position{line: 200, col: 9, offset: 5411}, name: "_", }, }, ¬Expr{ - pos: position{line: 195, col: 12, offset: 5188}, + pos: position{line: 200, col: 12, offset: 5414}, expr: &ruleRefExpr{ - pos: position{line: 195, col: 13, offset: 5189}, + pos: position{line: 200, col: 13, offset: 5415}, name: "StringLiteral", }, }, &andCodeExpr{ - pos: position{line: 195, col: 27, offset: 5203}, + pos: position{line: 200, col: 27, offset: 5429}, run: (*parser).callonIndexExpression18, }, }, }, &seqExpr{ - pos: position{line: 197, col: 5, offset: 5255}, + pos: position{line: 202, col: 5, offset: 5481}, exprs: []any{ &litMatcher{ - pos: position{line: 197, col: 5, offset: 5255}, + pos: position{line: 202, col: 5, offset: 5481}, val: "[", ignoreCase: false, want: "\"[\"", }, &zeroOrOneExpr{ - pos: position{line: 197, col: 9, offset: 5259}, + pos: position{line: 202, col: 9, offset: 5485}, expr: &ruleRefExpr{ - pos: position{line: 197, col: 9, offset: 5259}, + pos: position{line: 202, col: 9, offset: 5485}, name: "_", }, }, &ruleRefExpr{ - pos: position{line: 197, col: 12, offset: 5262}, + pos: position{line: 202, col: 12, offset: 5488}, name: "StringLiteral", }, &zeroOrOneExpr{ - pos: position{line: 197, col: 26, offset: 5276}, + pos: position{line: 202, col: 26, offset: 5502}, expr: &ruleRefExpr{ - pos: position{line: 197, col: 26, offset: 5276}, + pos: position{line: 202, col: 26, offset: 5502}, name: "_", }, }, ¬Expr{ - pos: position{line: 197, col: 29, offset: 5279}, + pos: position{line: 202, col: 29, offset: 5505}, expr: &litMatcher{ - pos: position{line: 197, col: 30, offset: 5280}, + pos: position{line: 202, col: 30, offset: 5506}, val: "]", ignoreCase: false, want: "\"]\"", }, }, &andCodeExpr{ - pos: position{line: 197, col: 34, offset: 5284}, + pos: position{line: 202, col: 34, offset: 5510}, run: (*parser).callonIndexExpression28, }, }, @@ -1585,42 +1594,42 @@ var g = &grammar{ { name: "Value", displayName: "\"value\"", - pos: position{line: 201, col: 1, offset: 5347}, + pos: position{line: 206, col: 1, offset: 5573}, expr: &choiceExpr{ - pos: position{line: 201, col: 18, offset: 5364}, + pos: position{line: 206, col: 18, offset: 5590}, alternatives: []any{ &actionExpr{ - pos: position{line: 201, col: 18, offset: 5364}, + pos: position{line: 206, col: 18, offset: 5590}, run: (*parser).callonValue2, expr: &labeledExpr{ - pos: position{line: 201, col: 18, offset: 5364}, + pos: position{line: 206, col: 18, offset: 5590}, label: "selector", expr: &ruleRefExpr{ - pos: position{line: 201, col: 27, offset: 5373}, + pos: position{line: 206, col: 27, offset: 5599}, name: "Selector", }, }, }, &actionExpr{ - pos: position{line: 203, col: 5, offset: 5449}, + pos: position{line: 208, col: 5, offset: 5675}, run: (*parser).callonValue5, expr: &labeledExpr{ - pos: position{line: 203, col: 5, offset: 5449}, + pos: position{line: 208, col: 5, offset: 5675}, label: "n", expr: &ruleRefExpr{ - pos: position{line: 203, col: 7, offset: 5451}, + pos: position{line: 208, col: 7, offset: 5677}, name: "NumberLiteral", }, }, }, &actionExpr{ - pos: position{line: 205, col: 5, offset: 5515}, + pos: position{line: 210, col: 5, offset: 5741}, run: (*parser).callonValue8, expr: &labeledExpr{ - pos: position{line: 205, col: 5, offset: 5515}, + pos: position{line: 210, col: 5, offset: 5741}, label: "s", expr: &ruleRefExpr{ - pos: position{line: 205, col: 7, offset: 5517}, + pos: position{line: 210, col: 7, offset: 5743}, name: "StringLiteral", }, }, @@ -1631,33 +1640,33 @@ var g = &grammar{ { name: "NumberLiteral", displayName: "\"number\"", - pos: position{line: 209, col: 1, offset: 5580}, + pos: position{line: 214, col: 1, offset: 5806}, expr: &choiceExpr{ - pos: position{line: 209, col: 27, offset: 5606}, + pos: position{line: 214, col: 27, offset: 5832}, alternatives: []any{ &actionExpr{ - pos: position{line: 209, col: 27, offset: 5606}, + pos: position{line: 214, col: 27, offset: 5832}, run: (*parser).callonNumberLiteral2, expr: &seqExpr{ - pos: position{line: 209, col: 27, offset: 5606}, + pos: position{line: 214, col: 27, offset: 5832}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 209, col: 27, offset: 5606}, + pos: position{line: 214, col: 27, offset: 5832}, expr: &litMatcher{ - pos: position{line: 209, col: 27, offset: 5606}, + pos: position{line: 214, col: 27, offset: 5832}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &ruleRefExpr{ - pos: position{line: 209, col: 32, offset: 5611}, + pos: position{line: 214, col: 32, offset: 5837}, name: "IntegerOrFloat", }, &andExpr{ - pos: position{line: 209, col: 47, offset: 5626}, + pos: position{line: 214, col: 47, offset: 5852}, expr: &ruleRefExpr{ - pos: position{line: 209, col: 48, offset: 5627}, + pos: position{line: 214, col: 48, offset: 5853}, name: "AfterNumbers", }, }, @@ -1665,30 +1674,30 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 211, col: 5, offset: 5676}, + pos: position{line: 216, col: 5, offset: 5902}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 211, col: 5, offset: 5676}, + pos: position{line: 216, col: 5, offset: 5902}, expr: &litMatcher{ - pos: position{line: 211, col: 5, offset: 5676}, + pos: position{line: 216, col: 5, offset: 5902}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &ruleRefExpr{ - pos: position{line: 211, col: 10, offset: 5681}, + pos: position{line: 216, col: 10, offset: 5907}, name: "IntegerOrFloat", }, ¬Expr{ - pos: position{line: 211, col: 25, offset: 5696}, + pos: position{line: 216, col: 25, offset: 5922}, expr: &ruleRefExpr{ - pos: position{line: 211, col: 26, offset: 5697}, + pos: position{line: 216, col: 26, offset: 5923}, name: "AfterNumbers", }, }, &andCodeExpr{ - pos: position{line: 211, col: 39, offset: 5710}, + pos: position{line: 216, col: 39, offset: 5936}, run: (*parser).callonNumberLiteral15, }, }, @@ -1698,22 +1707,22 @@ var g = &grammar{ }, { name: "AfterNumbers", - pos: position{line: 215, col: 1, offset: 5770}, + pos: position{line: 220, col: 1, offset: 5996}, expr: &andExpr{ - pos: position{line: 215, col: 17, offset: 5786}, + pos: position{line: 220, col: 17, offset: 6012}, expr: &choiceExpr{ - pos: position{line: 215, col: 19, offset: 5788}, + pos: position{line: 220, col: 19, offset: 6014}, alternatives: []any{ &ruleRefExpr{ - pos: position{line: 215, col: 19, offset: 5788}, + pos: position{line: 220, col: 19, offset: 6014}, name: "_", }, &ruleRefExpr{ - pos: position{line: 215, col: 23, offset: 5792}, + pos: position{line: 220, col: 23, offset: 6018}, name: "EOF", }, &litMatcher{ - pos: position{line: 215, col: 29, offset: 5798}, + pos: position{line: 220, col: 29, offset: 6024}, val: ")", ignoreCase: false, want: "\")\"", @@ -1724,33 +1733,33 @@ var g = &grammar{ }, { name: "IntegerOrFloat", - pos: position{line: 217, col: 1, offset: 5804}, + pos: position{line: 222, col: 1, offset: 6030}, expr: &seqExpr{ - pos: position{line: 217, col: 19, offset: 5822}, + pos: position{line: 222, col: 19, offset: 6048}, exprs: []any{ &choiceExpr{ - pos: position{line: 217, col: 20, offset: 5823}, + pos: position{line: 222, col: 20, offset: 6049}, alternatives: []any{ &litMatcher{ - pos: position{line: 217, col: 20, offset: 5823}, + pos: position{line: 222, col: 20, offset: 6049}, val: "0", ignoreCase: false, want: "\"0\"", }, &seqExpr{ - pos: position{line: 217, col: 26, offset: 5829}, + pos: position{line: 222, col: 26, offset: 6055}, exprs: []any{ &charClassMatcher{ - pos: position{line: 217, col: 26, offset: 5829}, + pos: position{line: 222, col: 26, offset: 6055}, val: "[1-9]", ranges: []rune{'1', '9'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 217, col: 31, offset: 5834}, + pos: position{line: 222, col: 31, offset: 6060}, expr: &charClassMatcher{ - pos: position{line: 217, col: 31, offset: 5834}, + pos: position{line: 222, col: 31, offset: 6060}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1762,20 +1771,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 217, col: 39, offset: 5842}, + pos: position{line: 222, col: 39, offset: 6068}, expr: &seqExpr{ - pos: position{line: 217, col: 40, offset: 5843}, + pos: position{line: 222, col: 40, offset: 6069}, exprs: []any{ &litMatcher{ - pos: position{line: 217, col: 40, offset: 5843}, + pos: position{line: 222, col: 40, offset: 6069}, val: ".", ignoreCase: false, want: "\".\"", }, &oneOrMoreExpr{ - pos: position{line: 217, col: 44, offset: 5847}, + pos: position{line: 222, col: 44, offset: 6073}, expr: &charClassMatcher{ - pos: position{line: 217, col: 44, offset: 5847}, + pos: position{line: 222, col: 44, offset: 6073}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1791,34 +1800,34 @@ var g = &grammar{ { name: "StringLiteral", displayName: "\"string\"", - pos: position{line: 219, col: 1, offset: 5857}, + pos: position{line: 224, col: 1, offset: 6083}, expr: &choiceExpr{ - pos: position{line: 219, col: 27, offset: 5883}, + pos: position{line: 224, col: 27, offset: 6109}, alternatives: []any{ &actionExpr{ - pos: position{line: 219, col: 27, offset: 5883}, + pos: position{line: 224, col: 27, offset: 6109}, run: (*parser).callonStringLiteral2, expr: &choiceExpr{ - pos: position{line: 219, col: 28, offset: 5884}, + pos: position{line: 224, col: 28, offset: 6110}, alternatives: []any{ &seqExpr{ - pos: position{line: 219, col: 28, offset: 5884}, + pos: position{line: 224, col: 28, offset: 6110}, exprs: []any{ &litMatcher{ - pos: position{line: 219, col: 28, offset: 5884}, + pos: position{line: 224, col: 28, offset: 6110}, val: "`", ignoreCase: false, want: "\"`\"", }, &zeroOrMoreExpr{ - pos: position{line: 219, col: 32, offset: 5888}, + pos: position{line: 224, col: 32, offset: 6114}, expr: &ruleRefExpr{ - pos: position{line: 219, col: 32, offset: 5888}, + pos: position{line: 224, col: 32, offset: 6114}, name: "RawStringChar", }, }, &litMatcher{ - pos: position{line: 219, col: 47, offset: 5903}, + pos: position{line: 224, col: 47, offset: 6129}, val: "`", ignoreCase: false, want: "\"`\"", @@ -1826,23 +1835,23 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 219, col: 53, offset: 5909}, + pos: position{line: 224, col: 53, offset: 6135}, exprs: []any{ &litMatcher{ - pos: position{line: 219, col: 53, offset: 5909}, + pos: position{line: 224, col: 53, offset: 6135}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &zeroOrMoreExpr{ - pos: position{line: 219, col: 57, offset: 5913}, + pos: position{line: 224, col: 57, offset: 6139}, expr: &ruleRefExpr{ - pos: position{line: 219, col: 57, offset: 5913}, + pos: position{line: 224, col: 57, offset: 6139}, name: "DoubleStringChar", }, }, &litMatcher{ - pos: position{line: 219, col: 75, offset: 5931}, + pos: position{line: 224, col: 75, offset: 6157}, val: "\"", ignoreCase: false, want: "\"\\\"\"", @@ -1853,42 +1862,42 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 221, col: 5, offset: 5983}, + pos: position{line: 226, col: 5, offset: 6209}, exprs: []any{ &choiceExpr{ - pos: position{line: 221, col: 6, offset: 5984}, + pos: position{line: 226, col: 6, offset: 6210}, alternatives: []any{ &seqExpr{ - pos: position{line: 221, col: 6, offset: 5984}, + pos: position{line: 226, col: 6, offset: 6210}, exprs: []any{ &litMatcher{ - pos: position{line: 221, col: 6, offset: 5984}, + pos: position{line: 226, col: 6, offset: 6210}, val: "`", ignoreCase: false, want: "\"`\"", }, &zeroOrMoreExpr{ - pos: position{line: 221, col: 10, offset: 5988}, + pos: position{line: 226, col: 10, offset: 6214}, expr: &ruleRefExpr{ - pos: position{line: 221, col: 10, offset: 5988}, + pos: position{line: 226, col: 10, offset: 6214}, name: "RawStringChar", }, }, }, }, &seqExpr{ - pos: position{line: 221, col: 27, offset: 6005}, + pos: position{line: 226, col: 27, offset: 6231}, exprs: []any{ &litMatcher{ - pos: position{line: 221, col: 27, offset: 6005}, + pos: position{line: 226, col: 27, offset: 6231}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &zeroOrMoreExpr{ - pos: position{line: 221, col: 31, offset: 6009}, + pos: position{line: 226, col: 31, offset: 6235}, expr: &ruleRefExpr{ - pos: position{line: 221, col: 31, offset: 6009}, + pos: position{line: 226, col: 31, offset: 6235}, name: "DoubleStringChar", }, }, @@ -1897,11 +1906,11 @@ var g = &grammar{ }, }, &ruleRefExpr{ - pos: position{line: 221, col: 50, offset: 6028}, + pos: position{line: 226, col: 50, offset: 6254}, name: "EOF", }, &andCodeExpr{ - pos: position{line: 221, col: 54, offset: 6032}, + pos: position{line: 226, col: 54, offset: 6258}, run: (*parser).callonStringLiteral25, }, }, @@ -1911,42 +1920,42 @@ var g = &grammar{ }, { name: "RawStringChar", - pos: position{line: 225, col: 1, offset: 6096}, + pos: position{line: 230, col: 1, offset: 6322}, expr: &seqExpr{ - pos: position{line: 225, col: 18, offset: 6113}, + pos: position{line: 230, col: 18, offset: 6339}, exprs: []any{ ¬Expr{ - pos: position{line: 225, col: 18, offset: 6113}, + pos: position{line: 230, col: 18, offset: 6339}, expr: &litMatcher{ - pos: position{line: 225, col: 19, offset: 6114}, + pos: position{line: 230, col: 19, offset: 6340}, val: "`", ignoreCase: false, want: "\"`\"", }, }, &anyMatcher{ - line: 225, col: 23, offset: 6118, + line: 230, col: 23, offset: 6344, }, }, }, }, { name: "DoubleStringChar", - pos: position{line: 226, col: 1, offset: 6120}, + pos: position{line: 231, col: 1, offset: 6346}, expr: &seqExpr{ - pos: position{line: 226, col: 21, offset: 6140}, + pos: position{line: 231, col: 21, offset: 6366}, exprs: []any{ ¬Expr{ - pos: position{line: 226, col: 21, offset: 6140}, + pos: position{line: 231, col: 21, offset: 6366}, expr: &litMatcher{ - pos: position{line: 226, col: 22, offset: 6141}, + pos: position{line: 231, col: 22, offset: 6367}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, }, &anyMatcher{ - line: 226, col: 26, offset: 6145, + line: 231, col: 26, offset: 6371, }, }, }, @@ -1954,11 +1963,11 @@ var g = &grammar{ { name: "_", displayName: "\"whitespace\"", - pos: position{line: 228, col: 1, offset: 6148}, + pos: position{line: 233, col: 1, offset: 6374}, expr: &oneOrMoreExpr{ - pos: position{line: 228, col: 19, offset: 6166}, + pos: position{line: 233, col: 19, offset: 6392}, expr: &charClassMatcher{ - pos: position{line: 228, col: 19, offset: 6166}, + pos: position{line: 233, col: 19, offset: 6392}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, @@ -1968,11 +1977,11 @@ var g = &grammar{ }, { name: "EOF", - pos: position{line: 230, col: 1, offset: 6178}, + pos: position{line: 235, col: 1, offset: 6404}, expr: ¬Expr{ - pos: position{line: 230, col: 8, offset: 6185}, + pos: position{line: 235, col: 8, offset: 6411}, expr: &anyMatcher{ - line: 230, col: 9, offset: 6186, + line: 235, col: 9, offset: 6412, }, }, }, @@ -2033,16 +2042,6 @@ func (p *parser) callonOrExpression14() (any, error) { return p.cur.onOrExpression14(stack["expr"]) } -func (c *current) onOrExpression17(expr any) (any, error) { - return expr, nil -} - -func (p *parser) callonOrExpression17() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onOrExpression17(stack["expr"]) -} - func (c *current) onAndExpression2(left, right any) (any, error) { return &BinaryExpression{ Operator: BinaryOpAnd, @@ -2096,49 +2095,92 @@ func (p *parser) callonNotExpression8() (any, error) { return p.cur.onNotExpression8(stack["expr"]) } -func (c *current) onCollectionExpression1(operator, selector, ident, expr any) (any, error) { - return c.onCollectionExpressionWithKey1(operator, selector, ident, "", expr) +func (c *current) onCollectionExpression1(op, selector, binding, expr any) (any, error) { + return &CollectionExpression{ + Op: op.(CollectionOperator), + Selector: selector.(Selector), + NameBinding: binding.(CollectionNameBinding), + Inner: expr.(Expression), + }, nil } func (p *parser) callonCollectionExpression1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onCollectionExpression1(stack["operator"], stack["selector"], stack["ident"], stack["expr"]) + return p.cur.onCollectionExpression1(stack["op"], stack["selector"], stack["binding"], stack["expr"]) } -func (c *current) onCollectionExpressionWithKey1(operator, selector, key, value, expr any) (any, error) { - ce := &CollectionExpression{ - Selector: selector.(Selector), - Inner: expr.(Expression), - } +func (c *current) onCollectionIdentifiers2(id1, id2 any) (any, error) { + return CollectionNameBinding{ + Mode: CollectionBindIndexAndValue, + Index: id1.(string), + Value: id2.(string), + }, nil +} - if string(operator.([]byte)) == "all" { - ce.Type = AllExpression - } else { - ce.Type = AnyExpression - } +func (p *parser) callonCollectionIdentifiers2() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCollectionIdentifiers2(stack["id1"], stack["id2"]) +} - switch k := key.(type) { - case string: - ce.Key = k - default: - ce.Key = "_" - } +func (c *current) onCollectionIdentifiers13(id1 any) (any, error) { + return CollectionNameBinding{ + Mode: CollectionBindIndex, + Index: id1.(string), + }, nil +} - switch v := value.(type) { - case string: - ce.Value = v - default: - ce.Value = "_" - } +func (p *parser) callonCollectionIdentifiers13() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCollectionIdentifiers13(stack["id1"]) +} + +func (c *current) onCollectionIdentifiers23(id2 any) (any, error) { + return CollectionNameBinding{ + Mode: CollectionBindValue, + Value: id2.(string), + }, nil +} + +func (p *parser) callonCollectionIdentifiers23() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCollectionIdentifiers23(stack["id2"]) +} + +func (c *current) onCollectionIdentifiers33(id any) (any, error) { + return CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: id.(string), + }, nil +} + +func (p *parser) callonCollectionIdentifiers33() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCollectionIdentifiers33(stack["id"]) +} + +func (c *current) onCollectionOpAny1() (any, error) { + return CollectionOpAny, nil +} + +func (p *parser) callonCollectionOpAny1() (any, error) { + stack := p.vstack[len(p.vstack)-1] + _ = stack + return p.cur.onCollectionOpAny1() +} - return ce, nil +func (c *current) onCollectionOpAll1() (any, error) { + return CollectionOpAll, nil } -func (p *parser) callonCollectionExpressionWithKey1() (any, error) { +func (p *parser) callonCollectionOpAll1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onCollectionExpressionWithKey1(stack["operator"], stack["selector"], stack["key"], stack["value"], stack["expr"]) + return p.cur.onCollectionOpAll1() } func (c *current) onParenthesizedExpression2(expr any) (any, error) { diff --git a/grammar/grammar.peg b/grammar/grammar.peg index 920b2b4..d2ff1e2 100644 --- a/grammar/grammar.peg +++ b/grammar/grammar.peg @@ -25,8 +25,6 @@ OrExpression <- left:AndExpression _ "or" _ right:OrExpression { return expr, nil } / expr:CollectionExpression { return expr, nil -} / expr:CollectionExpressionWithKey { - return expr, nil } AndExpression <- left:NotExpression _ "and" _ right:AndExpression { @@ -54,37 +52,44 @@ NotExpression <- "not" _ expr:NotExpression { return expr, nil } -CollectionExpression <- operator:("all"/"any") _ selector:Selector _ "as" _ ident:(Identifier / "_") _? "{" _? expr:OrExpression _? "}" { - return c.onCollectionExpressionWithKey1(operator, selector, ident, "", expr) +CollectionExpression <- op:(CollectionOpAny / CollectionOpAll) selector:Selector _ "as" _ binding:CollectionIdentifiers _? "{" _? expr:OrExpression _? "}" { + return &CollectionExpression{ + Op: op.(CollectionOperator), + Selector: selector.(Selector), + NameBinding: binding.(CollectionNameBinding), + Inner: expr.(Expression), + }, nil } -CollectionExpressionWithKey <- operator:("all"/"any") _ selector:Selector _ "as" _ key:(Identifier / "_") _? "," _? value:(Identifier / "_") _? "{" _? expr:OrExpression _? "}" { - ce := &CollectionExpression{ - Selector: selector.(Selector), - Inner: expr.(Expression), - } - - if string(operator.([]byte)) == "all" { - ce.Type = AllExpression - } else { - ce.Type = AnyExpression - } - - switch k := key.(type) { - case string: - ce.Key = k - default: - ce.Key = "_" - } +CollectionIdentifiers "collection-identifiers" <- id1:Identifier _? "," _? id2:Identifier { + return CollectionNameBinding{ + Mode: CollectionBindIndexAndValue, + Index: id1.(string), + Value: id2.(string), + }, nil +} / id1:Identifier _? "," _? "_" { + return CollectionNameBinding{ + Mode: CollectionBindIndex, + Index: id1.(string), + }, nil +} / "_" _? "," _? id2:Identifier { + return CollectionNameBinding{ + Mode: CollectionBindValue, + Value: id2.(string), + }, nil +} / id:Identifier { + return CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: id.(string), + }, nil +} - switch v := value.(type) { - case string: - ce.Value = v - default: - ce.Value = "_" - } +CollectionOpAny <- "any" _ { + return CollectionOpAny, nil +} - return ce, nil +CollectionOpAll <- "all" _ { + return CollectionOpAll, nil } ParenthesizedExpression "grouping" <- "(" _? expr:OrExpression _? ")" { diff --git a/grammar/grammar_test.go b/grammar/grammar_test.go index 7534c39..d723281 100644 --- a/grammar/grammar_test.go +++ b/grammar/grammar_test.go @@ -377,9 +377,11 @@ func TestExpressionParsing(t *testing.T) { "all": { input: `all group.tasks as t { t.name == "hello" }`, expected: &CollectionExpression{ - Key: "t", - Value: "", - Type: AllExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: "t", + }, + Op: CollectionOpAll, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"group", "tasks"}, @@ -419,17 +421,21 @@ func TestExpressionParsing(t *testing.T) { "nested all": { input: `all group.tasks as t { all t.test as i { i == "test" }}`, expected: &CollectionExpression{ - Key: "t", - Value: "", - Type: AllExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: "t", + }, + Op: CollectionOpAll, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"group", "tasks"}, }, Inner: &CollectionExpression{ - Key: "i", - Value: "", - Type: AllExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: "i", + }, + Op: CollectionOpAll, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"t", "test"}, @@ -450,9 +456,12 @@ func TestExpressionParsing(t *testing.T) { "all with key value": { input: `all group.tasks as k, v { k == v }`, expected: &CollectionExpression{ - Type: AllExpression, - Key: "k", - Value: "v", + Op: CollectionOpAll, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindIndexAndValue, + Index: "k", + Value: "v", + }, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"group", "tasks"}, @@ -473,9 +482,11 @@ func TestExpressionParsing(t *testing.T) { "any": { input: `any group.tasks as t { t.name == "vmware" }`, expected: &CollectionExpression{ - Key: "t", - Value: "", - Type: AnyExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: "t", + }, + Op: CollectionOpAny, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"group", "tasks"}, @@ -495,17 +506,21 @@ func TestExpressionParsing(t *testing.T) { "nested any": { input: `any group.tasks as t { any t.test as t { t == "test" }}`, expected: &CollectionExpression{ - Key: "t", - Value: "", - Type: AnyExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: "t", + }, + Op: CollectionOpAny, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"group", "tasks"}, }, Inner: &CollectionExpression{ - Key: "t", - Value: "", - Type: AnyExpression, + NameBinding: CollectionNameBinding{ + Mode: CollectionBindDefault, + Default: "t", + }, + Op: CollectionOpAny, Selector: Selector{ Type: SelectorTypeBexpr, Path: []string{"t", "test"}, From d7afa0c5ac8c9f1f47029a001167e1fea04fa260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Thu, 7 Sep 2023 22:31:52 +0200 Subject: [PATCH 6/9] Move the tests down --- evaluate_test.go | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/evaluate_test.go b/evaluate_test.go index 0a40384..89d312b 100644 --- a/evaluate_test.go +++ b/evaluate_test.go @@ -311,6 +311,24 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{ {expression: `"2" in "/Nested/SliceOfInfs"`, result: false}, {expression: `"true" in "/Nested/SliceOfInfs"`, result: true}, {expression: `"/Nested/Map/email" matches "(foz|foo)@example.com"`, result: true}, + // Missing key in map tests + {expression: "Nested.Map.notfound == 4", result: false}, + {expression: "Nested.Map.notfound != 4", result: true}, + {expression: "4 in Nested.Map.notfound", result: false}, + {expression: "4 not in Nested.Map.notfound", result: true}, + {expression: "Nested.Map.notfound is empty", result: true}, + {expression: "Nested.Map.notfound is not empty", result: false}, + {expression: `Nested.Map.notfound matches ".*"`, result: false}, + {expression: `Nested.Map.notfound not matches ".*"`, result: true}, + // Missing field in struct tests + {expression: "Nested.Notfound == 4", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, + {expression: "Nested.Notfound != 4", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, + {expression: "4 in Nested.Notfound", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, + {expression: "4 not in Nested.Notfound", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, + {expression: "Nested.Notfound is empty", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, + {expression: "Nested.Notfound is not empty", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, + {expression: `Nested.Notfound matches ".*"`, result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, + {expression: `Nested.Notfound not matches ".*"`, result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, // all {expression: `all Nested.SliceOfInts as i { i != 42 }`, result: true}, {expression: `all Nested.SliceOfInts as i { i == 1 }`, result: false}, @@ -331,24 +349,6 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{ {expression: `any Nested.Map as k, v { k == "foo" and v == "bar" }`, result: true}, {expression: `any Nested.Map as k { k.Color == "red" }`, err: "/k references a string so /k/Color is invalid"}, {expression: `any Nested.SliceOfInts as i, _ { i.Color == "red" }`, err: "/i references a int so /i/Color is invalid"}, - // Missing key in map tests - {expression: "Nested.Map.notfound == 4", result: false}, - {expression: "Nested.Map.notfound != 4", result: true}, - {expression: "4 in Nested.Map.notfound", result: false}, - {expression: "4 not in Nested.Map.notfound", result: true}, - {expression: "Nested.Map.notfound is empty", result: true}, - {expression: "Nested.Map.notfound is not empty", result: false}, - {expression: `Nested.Map.notfound matches ".*"`, result: false}, - {expression: `Nested.Map.notfound not matches ".*"`, result: true}, - // Missing field in struct tests - {expression: "Nested.Notfound == 4", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, - {expression: "Nested.Notfound != 4", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, - {expression: "4 in Nested.Notfound", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, - {expression: "4 not in Nested.Notfound", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, - {expression: "Nested.Notfound is empty", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, - {expression: "Nested.Notfound is not empty", result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, - {expression: `Nested.Notfound matches ".*"`, result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, - {expression: `Nested.Notfound not matches ".*"`, result: false, err: `error finding value in datum: /Nested/Notfound at part 1: couldn't find key: struct field with name "Notfound"`}, }, }, } From c0178fa9cbd59ef9cd690f83f5824ac8a584ffc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Thu, 7 Sep 2023 22:35:30 +0200 Subject: [PATCH 7/9] Exit early --- evaluate.go | 58 ++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/evaluate.go b/evaluate.go index 0047d3c..9ebb7cb 100644 --- a/evaluate.go +++ b/evaluate.go @@ -239,8 +239,6 @@ func evaluateNotPresent(ptr pointerstructure.Pointer, datum interface{}) bool { func getValue(datum interface{}, path []string, opt ...Option) (interface{}, bool, error) { opts := getOpts(opt...) - var val interface{} - var found bool if len(path) != 0 { for i := len(opts.withLocalVariables) - 1; i >= 0; i-- { name := path[0] @@ -250,14 +248,12 @@ func getValue(datum interface{}, path []string, opt ...Option) (interface{}, boo // This local variable is a key or an index and we know its // value without having to call pointerstructure, we stop // here. - val = lv.value if len(path) > 1 { first := pointerstructure.Pointer{Parts: []string{name}} full := pointerstructure.Pointer{Parts: path} - return nil, false, fmt.Errorf("%s references a %T so %s is invalid", first.String(), val, full.String()) + return nil, false, fmt.Errorf("%s references a %T so %s is invalid", first.String(), lv.value, full.String()) } - found = true - break + return lv.value, true, nil } else { // This local variable references another value, we prepend the // path of the selector it replaces and continue searching @@ -267,35 +263,33 @@ func getValue(datum interface{}, path []string, opt ...Option) (interface{}, boo } } } - if !found { - // This is not a local variable, we use pointerstructure to look for it - // in the global datum - ptr := pointerstructure.Pointer{ - Parts: path, - Config: pointerstructure.Config{ - TagName: opts.withTagName, - ValueTransformationHook: opts.withHookFn, - }, - } - var err error - val, err = ptr.Get(datum) - if err != nil { - if errors.Is(err, pointerstructure.ErrNotFound) { - // Prefer the withUnknown option if set, otherwise defer to NotPresent - // disposition - switch { - case opts.withUnknown != nil: - err = nil - val = *opts.withUnknown - case evaluateNotPresent(ptr, datum): - return nil, false, nil - } - } - if err != nil { - return false, false, fmt.Errorf("error finding value in datum: %w", err) + // This is not a local variable, we use pointerstructure to look for it + // in the global datum + ptr := pointerstructure.Pointer{ + Parts: path, + Config: pointerstructure.Config{ + TagName: opts.withTagName, + ValueTransformationHook: opts.withHookFn, + }, + } + val, err := ptr.Get(datum) + if err != nil { + if errors.Is(err, pointerstructure.ErrNotFound) { + // Prefer the withUnknown option if set, otherwise defer to NotPresent + // disposition + switch { + case opts.withUnknown != nil: + err = nil + val = *opts.withUnknown + case evaluateNotPresent(ptr, datum): + return nil, false, nil } } + + if err != nil { + return false, false, fmt.Errorf("error finding value in datum: %w", err) + } } return val, true, nil From 58da06a12e214576ec2c7b8971183ae030e7b7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 8 Sep 2023 11:10:29 +0200 Subject: [PATCH 8/9] Address code review comments --- evaluate.go | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/evaluate.go b/evaluate.go index 9ebb7cb..4b06481 100644 --- a/evaluate.go +++ b/evaluate.go @@ -237,9 +237,26 @@ func evaluateNotPresent(ptr pointerstructure.Pointer, datum interface{}) bool { return reflect.ValueOf(val).Kind() == reflect.Map } +// getValues resolves path to the value it references by first looking into the +// the local variables, then into the global datum state if it does not. +// +// When the path points to a local variable we have multiple cases we have to +// take care of, in some constructions like +// +// all Slice as item { item != "forbidden" } +// +// `item` is actually an alias to "/Slice/0", "/Slice/1", etc. In that case we +// compute the full path because we tracked what each of them points to. +// +// In some other cases like +// +// all Map as key { key != "forbidden" } +// +// `key` has no equivalent JSON Pointer. In that case we kept track of the the +// concrete value instead of the path and we return it directly. func getValue(datum interface{}, path []string, opt ...Option) (interface{}, bool, error) { opts := getOpts(opt...) - if len(path) != 0 { + if len(path) != 0 && len(opts.withLocalVariables) > 0 { for i := len(opts.withLocalVariables) - 1; i >= 0; i-- { name := path[0] lv := opts.withLocalVariables[i] @@ -399,23 +416,24 @@ func evaluateCollectionExpression(expression *grammar.CollectionExpression, datu innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Index, nil, key.Interface())) } if expression.NameBinding.Value != "" { - path := append([]string(nil), expression.Selector.Path...) + path := make([]string, 0, len(expression.Selector.Path)+1) + path = append(path, expression.Selector.Path...) path = append(path, key.Interface().(string)) innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Value, path, nil)) } } else { - if expression.NameBinding.Default != "" { - path := append([]string(nil), expression.Selector.Path...) - path = append(path, fmt.Sprintf("%d", i)) - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Default, path, nil)) - } if expression.NameBinding.Index != "" { innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Index, nil, i)) } + + pathValue := make([]string, 0, len(expression.Selector.Path)+1) + pathValue = append(pathValue, expression.Selector.Path...) + pathValue = append(pathValue, fmt.Sprintf("%d", i)) + if expression.NameBinding.Default != "" { + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Default, pathValue, nil)) + } if expression.NameBinding.Value != "" { - path := append([]string(nil), expression.Selector.Path...) - path = append(path, fmt.Sprintf("%d", i)) - innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Value, path, nil)) + innerOpt = append(innerOpt, WithLocalVariable(expression.NameBinding.Value, pathValue, nil)) } } From fa1ad08dc715441a8354f9b2f9724e017bfae783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 8 Sep 2023 11:12:04 +0200 Subject: [PATCH 9/9] getValues -> getValue --- evaluate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evaluate.go b/evaluate.go index 4b06481..47165a6 100644 --- a/evaluate.go +++ b/evaluate.go @@ -237,7 +237,7 @@ func evaluateNotPresent(ptr pointerstructure.Pointer, datum interface{}) bool { return reflect.ValueOf(val).Kind() == reflect.Map } -// getValues resolves path to the value it references by first looking into the +// getValue resolves path to the value it references by first looking into the // the local variables, then into the global datum state if it does not. // // When the path points to a local variable we have multiple cases we have to