diff --git a/pkg/policy/doc.go b/pkg/policy/doc.go index 10394fa..4e10a1b 100644 --- a/pkg/policy/doc.go +++ b/pkg/policy/doc.go @@ -2,10 +2,7 @@ // ANTLRv4 grammar is provided in `parser/Query.g4` and `parser/QueryLexer.g4`. // // Current limitations: -// 1. Grouping filter expressions in parenthesis is not supported right now. -// Requiring this will make query too verbose, making it optional makes -// our grammar not LL(1). This can be supported in future. -// 2. Filters must be defined before they are used. +// 1. Filters must be defined before they are used. // This requirement may be relaxed in future. // // Example query: diff --git a/pkg/policy/parser/Query.g4 b/pkg/policy/parser/Query.g4 index 0cad576..fc74c6f 100644 --- a/pkg/policy/parser/Query.g4 +++ b/pkg/policy/parser/Query.g4 @@ -24,6 +24,7 @@ clause: CLAUSE_SAME | CLAUSE_DISTINCT; // nodes from distinct buckets filterExpr: F1 = filterExpr Op = AND_OP F2 = filterExpr | F1 = filterExpr Op = OR_OP F2 = filterExpr + | '(' Inner = filterExpr ')' | expr ; diff --git a/pkg/policy/parser/Query.interp b/pkg/policy/parser/Query.interp index 63f74d9..9512ecb 100644 Binary files a/pkg/policy/parser/Query.interp and b/pkg/policy/parser/Query.interp differ diff --git a/pkg/policy/parser/query_parser.go b/pkg/policy/parser/query_parser.go index fb94f3a..c78c0f4 100644 Binary files a/pkg/policy/parser/query_parser.go and b/pkg/policy/parser/query_parser.go differ diff --git a/pkg/policy/query.go b/pkg/policy/query.go index 7fbdae5..9bf08ac 100644 --- a/pkg/policy/query.go +++ b/pkg/policy/query.go @@ -186,6 +186,10 @@ func (p *policyVisitor) VisitFilterExpr(ctx *parser.FilterExprContext) interface return eCtx.Accept(p) } + if inner := ctx.GetInner(); inner != nil { + return inner.Accept(p) + } + f := new(netmap.Filter) op := operationFromString(ctx.GetOp().GetText()) f.SetOperation(op) diff --git a/pkg/policy/query_test.go b/pkg/policy/query_test.go index 2493edc..b7278d4 100644 --- a/pkg/policy/query_test.go +++ b/pkg/policy/query_test.go @@ -215,6 +215,30 @@ FILTER City EQ "SPB" AND SSD EQ true OR City EQ "SPB" AND Rating GE 5 AS SPBSSD` require.EqualValues(t, expected, r) } +func TestBrackets(t *testing.T) { + q := `REP 7 IN SPB +SELECT 1 IN City FROM SPBSSD AS SPB +FILTER ( City EQ "SPB" OR SSD EQ true ) AND (City EQ "SPB" OR Rating GE 5) AS SPBSSD` + + expected := new(netmap.PlacementPolicy) + expected.SetReplicas([]*netmap.Replica{newReplica("SPB", 7)}) + expected.SetSelectors([]*netmap.Selector{ + newSelector(1, netmap.UnspecifiedClause, "City", "SPBSSD", "SPB"), + }) + expected.SetFilters([]*netmap.Filter{ + newFilter("SPBSSD", "", "", netmap.AND, + newFilter("", "", "", netmap.OR, + newFilter("", "City", "SPB", netmap.EQ), + newFilter("", "SSD", "true", netmap.EQ)), + newFilter("", "", "", netmap.OR, + newFilter("", "City", "SPB", netmap.EQ), + newFilter("", "Rating", "5", netmap.GE)))}) + + r, err := Parse(q) + require.NoError(t, err) + require.EqualValues(t, expected, r) +} + func TestValidation(t *testing.T) { t.Run("MissingSelector", func(t *testing.T) { q := `REP 3 IN RU`