forked from TrueCloudLab/frostfs-sdk-go
Merge pull request #3 from fyrchik/policy-parser
Use ANTLR for policy parsing
This commit is contained in:
commit
56ef32f21e
22 changed files with 3692 additions and 263 deletions
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/pkg/policy/parser/*.go -diff
|
||||||
|
/pkg/policy/parser/generate.go diff
|
||||||
|
**/*.interp -diff
|
||||||
|
**/*.tokens -diff
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module github.com/nspcc-dev/neofs-sdk-go
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/participle v0.7.1
|
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1
|
||||||
github.com/nspcc-dev/neofs-api-go v1.27.0
|
github.com/nspcc-dev/neofs-api-go v1.27.0
|
||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
go.uber.org/zap v1.10.0
|
go.uber.org/zap v1.10.0
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -10,15 +10,14 @@ github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3
|
||||||
github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
|
github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
|
||||||
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
|
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
|
||||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||||
github.com/alecthomas/participle v0.7.1 h1:2bN7reTw//5f0cugJcTOnY/NYZcWQOaajW+BwZB5xWs=
|
|
||||||
github.com/alecthomas/participle v0.7.1/go.mod h1:HfdmEuwvr12HXQN44HPWXR0lHmVolVYe4dyL6lQ3duY=
|
|
||||||
github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||||
|
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1 h1:zFRi26YWd7NIorBXe8UkevRl0dIvk/AnXHWaAiZG+Yk=
|
||||||
|
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
// Package policy provides facilities for creating policy from SQL-like language.
|
// Package policy provides facilities for creating policy from SQL-like language.
|
||||||
// eBNF grammar is provided in `grammar.ebnf` for illustration.
|
// ANTLRv4 grammar is provided in `parser/Query.g4` and `parser/QueryLexer.g4`.
|
||||||
//
|
//
|
||||||
// Current limitations:
|
// Current limitations:
|
||||||
// 1. Grouping filter expressions in parenthesis is not supported right now.
|
// 1. Filters must be defined before they are used.
|
||||||
// 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.
|
|
||||||
// This requirement may be relaxed in future.
|
// This requirement may be relaxed in future.
|
||||||
|
// 2. Keywords are key-sensitive. This can be changed if necessary
|
||||||
|
// https://github.com/antlr/antlr4/blob/master/doc/case-insensitive-lexing.md .
|
||||||
//
|
//
|
||||||
// Example query:
|
// Example query:
|
||||||
// REP 1 in SPB
|
// REP 1 IN SPB
|
||||||
// REP 2 in Americas
|
// REP 2 IN Americas
|
||||||
// CBF 4
|
// CBF 4
|
||||||
// SELECT 1 Node IN City FROM SPBSSD AS SPB
|
// SELECT 1 IN City FROM SPBSSD AS SPB
|
||||||
// SELECT 2 Node IN SAME City FROM Americas AS Americas
|
// SELECT 2 IN SAME City FROM Americas AS Americas
|
||||||
// FILTER SSD EQ true AS IsSSD
|
// FILTER SSD EQ true AS IsSSD
|
||||||
// FILTER @IsSSD AND Country eq "RU" AND City eq "St.Petersburg" AS SPBSSD
|
// FILTER @IsSSD AND Country EQ "RU" AND City EQ "St.Petersburg" AS SPBSSD
|
||||||
// FILTER 'Continent' == 'North America' OR Continent == 'South America' AS Americas
|
// FILTER 'Continent' EQ 'North America' OR Continent EQ 'South America' AS Americas
|
||||||
package policy
|
package policy
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package policy_test
|
package policy_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -30,7 +29,6 @@ FILTER City EQ SPB AND SSD EQ true OR City EQ SPB AND Rating GE 5 AS SPBSSD`,
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
got := policy.Encode(q)
|
got := policy.Encode(q)
|
||||||
fmt.Println(strings.Join(got, "\n"))
|
|
||||||
require.Equal(t, testCase, strings.Join(got, "\n"))
|
require.Equal(t, testCase, strings.Join(got, "\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
Policy ::=
|
|
||||||
RepStmt, [RepStmt],
|
|
||||||
CbtStmt?,
|
|
||||||
[SelectStmt],
|
|
||||||
[FilterStmt],
|
|
||||||
;
|
|
||||||
|
|
||||||
RepStmt ::=
|
|
||||||
'REP', Number1, (* number of object replicas *)
|
|
||||||
('AS', Ident)? (* optional selector name *)
|
|
||||||
;
|
|
||||||
|
|
||||||
CbtStmt ::= 'CBF', Number1 (* container backup factor *)
|
|
||||||
;
|
|
||||||
|
|
||||||
SelectStmt ::=
|
|
||||||
'SELECT', Number1, (* number of nodes to select without container backup factor *)
|
|
||||||
('IN', Clause?, Ident)?, (* bucket name *)
|
|
||||||
FROM, (Ident | '*'), (* filter reference or whole netmap *)
|
|
||||||
('AS', Ident)? (* optional selector name *)
|
|
||||||
;
|
|
||||||
|
|
||||||
Clause ::=
|
|
||||||
'SAME' (* nodes from the same bucket *)
|
|
||||||
| 'DISTINCT' (* nodes from distinct buckets *)
|
|
||||||
;
|
|
||||||
|
|
||||||
FilterStmt ::=
|
|
||||||
'FILTER', AndChain, ['OR', AndChain],
|
|
||||||
'AS', Ident (* obligatory filter name *)
|
|
||||||
;
|
|
||||||
|
|
||||||
AndChain ::=
|
|
||||||
Expr, ['AND', Expr]
|
|
||||||
;
|
|
||||||
|
|
||||||
Expr ::=
|
|
||||||
'@' Ident (* filter reference *)
|
|
||||||
| Key, Op, Value (* attribute filter *)
|
|
||||||
;
|
|
||||||
|
|
||||||
Op ::= 'EQ' | 'NE' | 'GE' | 'GT' | 'LT' | 'LE'
|
|
||||||
;
|
|
||||||
|
|
||||||
Key ::= Ident | String
|
|
||||||
;
|
|
||||||
|
|
||||||
Value ::= Ident | Number | String
|
|
||||||
;
|
|
||||||
|
|
||||||
Number1 ::= Digit1 [Digit];
|
|
||||||
Number ::= Digit [Digit];
|
|
||||||
|
|
||||||
Digit1 ::= '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;
|
|
||||||
Digit ::= '0' | Digit1;
|
|
|
@ -1,60 +0,0 @@
|
||||||
//nolint:govet,golint // fails on struct tags here, but participle needs this syntax
|
|
||||||
package policy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/alecthomas/participle"
|
|
||||||
)
|
|
||||||
|
|
||||||
var parser *participle.Parser
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
p, err := participle.Build(&query{})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
parser = p
|
|
||||||
}
|
|
||||||
|
|
||||||
type query struct {
|
|
||||||
Replicas []*replicaStmt `@@+`
|
|
||||||
CBF uint32 `("CBF" @Int)?`
|
|
||||||
Selectors []*selectorStmt `@@*`
|
|
||||||
Filters []*filterStmt `@@*`
|
|
||||||
}
|
|
||||||
|
|
||||||
type replicaStmt struct {
|
|
||||||
Count int `"REP" @Int`
|
|
||||||
Selector string `("IN" @Ident)?`
|
|
||||||
}
|
|
||||||
|
|
||||||
type selectorStmt struct {
|
|
||||||
Count uint32 `"SELECT" @Int`
|
|
||||||
Bucket []string `("IN" @(("SAME" | "DISTINCT")? Ident))?`
|
|
||||||
Filter string `"FROM" @(Ident | "*")`
|
|
||||||
Name string `("AS" @Ident)?`
|
|
||||||
}
|
|
||||||
|
|
||||||
type filterStmt struct {
|
|
||||||
Value *orChain `"FILTER" @@`
|
|
||||||
Name string `"AS" @Ident`
|
|
||||||
}
|
|
||||||
|
|
||||||
type filterOrExpr struct {
|
|
||||||
Reference string `"@"@Ident`
|
|
||||||
Expr *simpleExpr `| @@`
|
|
||||||
}
|
|
||||||
|
|
||||||
type orChain struct {
|
|
||||||
Clauses []*andChain `@@ ("OR" @@)*`
|
|
||||||
}
|
|
||||||
|
|
||||||
type andChain struct {
|
|
||||||
Clauses []*filterOrExpr `@@ ("AND" @@)*`
|
|
||||||
}
|
|
||||||
|
|
||||||
type simpleExpr struct {
|
|
||||||
Key string `@(Ident | String)`
|
|
||||||
// We don't use literals here to improve error messages.
|
|
||||||
Op string `@Ident`
|
|
||||||
Value string `@(Ident | String | Int)`
|
|
||||||
}
|
|
46
pkg/policy/parser/Query.g4
Normal file
46
pkg/policy/parser/Query.g4
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
parser grammar Query;
|
||||||
|
|
||||||
|
options {
|
||||||
|
tokenVocab = QueryLexer;
|
||||||
|
}
|
||||||
|
|
||||||
|
policy: repStmt+ cbfStmt? selectStmt* filterStmt*;
|
||||||
|
|
||||||
|
repStmt:
|
||||||
|
REP Count = NUMBER1 // number of object replicas
|
||||||
|
(IN Selector = ident)?; // optional selector name
|
||||||
|
|
||||||
|
cbfStmt: CBF BackupFactor = NUMBER1; // container backup factor
|
||||||
|
|
||||||
|
selectStmt:
|
||||||
|
SELECT Count = NUMBER1 // number of nodes to select without container backup factor *)
|
||||||
|
(IN clause? Bucket = ident)? // bucket name
|
||||||
|
FROM Filter = identWC // filter reference or whole netmap
|
||||||
|
(AS Name = ident)? // optional selector name
|
||||||
|
;
|
||||||
|
|
||||||
|
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
|
||||||
|
;
|
||||||
|
|
||||||
|
filterStmt:
|
||||||
|
FILTER Expr = filterExpr
|
||||||
|
AS Name = ident // obligatory filter name
|
||||||
|
;
|
||||||
|
|
||||||
|
expr:
|
||||||
|
AT Filter = ident // reference to named filter
|
||||||
|
| Key = filterKey SIMPLE_OP Value = filterValue // attribute comparison
|
||||||
|
;
|
||||||
|
|
||||||
|
filterKey : ident | STRING;
|
||||||
|
filterValue : ident | number | STRING;
|
||||||
|
number : ZERO | NUMBER1;
|
||||||
|
keyword : REP | IN | AS | SELECT | FROM | FILTER;
|
||||||
|
ident : keyword | IDENT;
|
||||||
|
identWC : ident | WILDCARD;
|
67
pkg/policy/parser/Query.interp
Normal file
67
pkg/policy/parser/Query.interp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
token literal names:
|
||||||
|
null
|
||||||
|
'AND'
|
||||||
|
'OR'
|
||||||
|
null
|
||||||
|
'REP'
|
||||||
|
'IN'
|
||||||
|
'AS'
|
||||||
|
'CBF'
|
||||||
|
'SELECT'
|
||||||
|
'FROM'
|
||||||
|
'FILTER'
|
||||||
|
'*'
|
||||||
|
'SAME'
|
||||||
|
'DISTINCT'
|
||||||
|
'('
|
||||||
|
')'
|
||||||
|
'@'
|
||||||
|
null
|
||||||
|
null
|
||||||
|
'0'
|
||||||
|
null
|
||||||
|
null
|
||||||
|
|
||||||
|
token symbolic names:
|
||||||
|
null
|
||||||
|
AND_OP
|
||||||
|
OR_OP
|
||||||
|
SIMPLE_OP
|
||||||
|
REP
|
||||||
|
IN
|
||||||
|
AS
|
||||||
|
CBF
|
||||||
|
SELECT
|
||||||
|
FROM
|
||||||
|
FILTER
|
||||||
|
WILDCARD
|
||||||
|
CLAUSE_SAME
|
||||||
|
CLAUSE_DISTINCT
|
||||||
|
L_PAREN
|
||||||
|
R_PAREN
|
||||||
|
AT
|
||||||
|
IDENT
|
||||||
|
NUMBER1
|
||||||
|
ZERO
|
||||||
|
STRING
|
||||||
|
WS
|
||||||
|
|
||||||
|
rule names:
|
||||||
|
policy
|
||||||
|
repStmt
|
||||||
|
cbfStmt
|
||||||
|
selectStmt
|
||||||
|
clause
|
||||||
|
filterExpr
|
||||||
|
filterStmt
|
||||||
|
expr
|
||||||
|
filterKey
|
||||||
|
filterValue
|
||||||
|
number
|
||||||
|
keyword
|
||||||
|
ident
|
||||||
|
identWC
|
||||||
|
|
||||||
|
|
||||||
|
atn:
|
||||||
|
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 23, 130, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 3, 2, 6, 2, 32, 10, 2, 13, 2, 14, 2, 33, 3, 2, 5, 2, 37, 10, 2, 3, 2, 7, 2, 40, 10, 2, 12, 2, 14, 2, 43, 11, 2, 3, 2, 7, 2, 46, 10, 2, 12, 2, 14, 2, 49, 11, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 55, 10, 3, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 64, 10, 5, 3, 5, 5, 5, 67, 10, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 73, 10, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 83, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 91, 10, 7, 12, 7, 14, 7, 94, 11, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 5, 9, 107, 10, 9, 3, 10, 3, 10, 5, 10, 111, 10, 10, 3, 11, 3, 11, 3, 11, 5, 11, 116, 10, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 5, 14, 124, 10, 14, 3, 15, 3, 15, 5, 15, 128, 10, 15, 3, 15, 2, 3, 12, 16, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 2, 5, 3, 2, 14, 15, 3, 2, 20, 21, 4, 2, 6, 8, 10, 12, 2, 132, 2, 31, 3, 2, 2, 2, 4, 50, 3, 2, 2, 2, 6, 56, 3, 2, 2, 2, 8, 59, 3, 2, 2, 2, 10, 74, 3, 2, 2, 2, 12, 82, 3, 2, 2, 2, 14, 95, 3, 2, 2, 2, 16, 106, 3, 2, 2, 2, 18, 110, 3, 2, 2, 2, 20, 115, 3, 2, 2, 2, 22, 117, 3, 2, 2, 2, 24, 119, 3, 2, 2, 2, 26, 123, 3, 2, 2, 2, 28, 127, 3, 2, 2, 2, 30, 32, 5, 4, 3, 2, 31, 30, 3, 2, 2, 2, 32, 33, 3, 2, 2, 2, 33, 31, 3, 2, 2, 2, 33, 34, 3, 2, 2, 2, 34, 36, 3, 2, 2, 2, 35, 37, 5, 6, 4, 2, 36, 35, 3, 2, 2, 2, 36, 37, 3, 2, 2, 2, 37, 41, 3, 2, 2, 2, 38, 40, 5, 8, 5, 2, 39, 38, 3, 2, 2, 2, 40, 43, 3, 2, 2, 2, 41, 39, 3, 2, 2, 2, 41, 42, 3, 2, 2, 2, 42, 47, 3, 2, 2, 2, 43, 41, 3, 2, 2, 2, 44, 46, 5, 14, 8, 2, 45, 44, 3, 2, 2, 2, 46, 49, 3, 2, 2, 2, 47, 45, 3, 2, 2, 2, 47, 48, 3, 2, 2, 2, 48, 3, 3, 2, 2, 2, 49, 47, 3, 2, 2, 2, 50, 51, 7, 6, 2, 2, 51, 54, 7, 20, 2, 2, 52, 53, 7, 7, 2, 2, 53, 55, 5, 26, 14, 2, 54, 52, 3, 2, 2, 2, 54, 55, 3, 2, 2, 2, 55, 5, 3, 2, 2, 2, 56, 57, 7, 9, 2, 2, 57, 58, 7, 20, 2, 2, 58, 7, 3, 2, 2, 2, 59, 60, 7, 10, 2, 2, 60, 66, 7, 20, 2, 2, 61, 63, 7, 7, 2, 2, 62, 64, 5, 10, 6, 2, 63, 62, 3, 2, 2, 2, 63, 64, 3, 2, 2, 2, 64, 65, 3, 2, 2, 2, 65, 67, 5, 26, 14, 2, 66, 61, 3, 2, 2, 2, 66, 67, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 69, 7, 11, 2, 2, 69, 72, 5, 28, 15, 2, 70, 71, 7, 8, 2, 2, 71, 73, 5, 26, 14, 2, 72, 70, 3, 2, 2, 2, 72, 73, 3, 2, 2, 2, 73, 9, 3, 2, 2, 2, 74, 75, 9, 2, 2, 2, 75, 11, 3, 2, 2, 2, 76, 77, 8, 7, 1, 2, 77, 78, 7, 16, 2, 2, 78, 79, 5, 12, 7, 2, 79, 80, 7, 17, 2, 2, 80, 83, 3, 2, 2, 2, 81, 83, 5, 16, 9, 2, 82, 76, 3, 2, 2, 2, 82, 81, 3, 2, 2, 2, 83, 92, 3, 2, 2, 2, 84, 85, 12, 6, 2, 2, 85, 86, 7, 3, 2, 2, 86, 91, 5, 12, 7, 7, 87, 88, 12, 5, 2, 2, 88, 89, 7, 4, 2, 2, 89, 91, 5, 12, 7, 6, 90, 84, 3, 2, 2, 2, 90, 87, 3, 2, 2, 2, 91, 94, 3, 2, 2, 2, 92, 90, 3, 2, 2, 2, 92, 93, 3, 2, 2, 2, 93, 13, 3, 2, 2, 2, 94, 92, 3, 2, 2, 2, 95, 96, 7, 12, 2, 2, 96, 97, 5, 12, 7, 2, 97, 98, 7, 8, 2, 2, 98, 99, 5, 26, 14, 2, 99, 15, 3, 2, 2, 2, 100, 101, 7, 18, 2, 2, 101, 107, 5, 26, 14, 2, 102, 103, 5, 18, 10, 2, 103, 104, 7, 5, 2, 2, 104, 105, 5, 20, 11, 2, 105, 107, 3, 2, 2, 2, 106, 100, 3, 2, 2, 2, 106, 102, 3, 2, 2, 2, 107, 17, 3, 2, 2, 2, 108, 111, 5, 26, 14, 2, 109, 111, 7, 22, 2, 2, 110, 108, 3, 2, 2, 2, 110, 109, 3, 2, 2, 2, 111, 19, 3, 2, 2, 2, 112, 116, 5, 26, 14, 2, 113, 116, 5, 22, 12, 2, 114, 116, 7, 22, 2, 2, 115, 112, 3, 2, 2, 2, 115, 113, 3, 2, 2, 2, 115, 114, 3, 2, 2, 2, 116, 21, 3, 2, 2, 2, 117, 118, 9, 3, 2, 2, 118, 23, 3, 2, 2, 2, 119, 120, 9, 4, 2, 2, 120, 25, 3, 2, 2, 2, 121, 124, 5, 24, 13, 2, 122, 124, 7, 19, 2, 2, 123, 121, 3, 2, 2, 2, 123, 122, 3, 2, 2, 2, 124, 27, 3, 2, 2, 2, 125, 128, 5, 26, 14, 2, 126, 128, 7, 13, 2, 2, 127, 125, 3, 2, 2, 2, 127, 126, 3, 2, 2, 2, 128, 29, 3, 2, 2, 2, 18, 33, 36, 41, 47, 54, 63, 66, 72, 82, 90, 92, 106, 110, 115, 123, 127]
|
37
pkg/policy/parser/Query.tokens
Normal file
37
pkg/policy/parser/Query.tokens
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
AND_OP=1
|
||||||
|
OR_OP=2
|
||||||
|
SIMPLE_OP=3
|
||||||
|
REP=4
|
||||||
|
IN=5
|
||||||
|
AS=6
|
||||||
|
CBF=7
|
||||||
|
SELECT=8
|
||||||
|
FROM=9
|
||||||
|
FILTER=10
|
||||||
|
WILDCARD=11
|
||||||
|
CLAUSE_SAME=12
|
||||||
|
CLAUSE_DISTINCT=13
|
||||||
|
L_PAREN=14
|
||||||
|
R_PAREN=15
|
||||||
|
AT=16
|
||||||
|
IDENT=17
|
||||||
|
NUMBER1=18
|
||||||
|
ZERO=19
|
||||||
|
STRING=20
|
||||||
|
WS=21
|
||||||
|
'AND'=1
|
||||||
|
'OR'=2
|
||||||
|
'REP'=4
|
||||||
|
'IN'=5
|
||||||
|
'AS'=6
|
||||||
|
'CBF'=7
|
||||||
|
'SELECT'=8
|
||||||
|
'FROM'=9
|
||||||
|
'FILTER'=10
|
||||||
|
'*'=11
|
||||||
|
'SAME'=12
|
||||||
|
'DISTINCT'=13
|
||||||
|
'('=14
|
||||||
|
')'=15
|
||||||
|
'@'=16
|
||||||
|
'0'=19
|
41
pkg/policy/parser/QueryLexer.g4
Normal file
41
pkg/policy/parser/QueryLexer.g4
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
lexer grammar QueryLexer;
|
||||||
|
|
||||||
|
AND_OP : 'AND';
|
||||||
|
OR_OP : 'OR';
|
||||||
|
SIMPLE_OP : 'EQ' | 'NE' | 'GE' | 'GT' | 'LT' | 'LE';
|
||||||
|
|
||||||
|
REP : 'REP';
|
||||||
|
IN : 'IN';
|
||||||
|
AS : 'AS';
|
||||||
|
CBF : 'CBF';
|
||||||
|
SELECT : 'SELECT';
|
||||||
|
FROM : 'FROM';
|
||||||
|
FILTER : 'FILTER';
|
||||||
|
WILDCARD : '*';
|
||||||
|
|
||||||
|
CLAUSE_SAME : 'SAME';
|
||||||
|
CLAUSE_DISTINCT : 'DISTINCT';
|
||||||
|
|
||||||
|
L_PAREN : '(';
|
||||||
|
R_PAREN : ')';
|
||||||
|
AT : '@';
|
||||||
|
|
||||||
|
IDENT : Nondigit (Digit | Nondigit)* ;
|
||||||
|
fragment Digit : [0-9] ;
|
||||||
|
fragment Nondigit : [a-zA-Z_] ;
|
||||||
|
|
||||||
|
NUMBER1 : [1-9] Digit* ;
|
||||||
|
ZERO : '0' ;
|
||||||
|
|
||||||
|
// Taken from antlr4 json grammar with minor corrections.
|
||||||
|
// https://github.com/antlr/grammars-v4/blob/master/json/JSON.g4
|
||||||
|
STRING : '"' (ESC | SAFECODEPOINTDOUBLE)* '"'
|
||||||
|
| '\'' (ESC | SAFECODEPOINTSINGLE)* '\'' ;
|
||||||
|
|
||||||
|
fragment ESC : '\\' (['"\\/bfnrt] | UNICODE) ;
|
||||||
|
fragment UNICODE : 'u' HEX HEX HEX HEX ;
|
||||||
|
fragment HEX : [0-9a-fA-F] ;
|
||||||
|
fragment SAFECODEPOINTSINGLE : ~ ['\\\u0000-\u001F] ;
|
||||||
|
fragment SAFECODEPOINTDOUBLE : ~ ["\\\u0000-\u001F] ;
|
||||||
|
|
||||||
|
WS : [ \t\n\r] + -> skip ;
|
87
pkg/policy/parser/QueryLexer.interp
Normal file
87
pkg/policy/parser/QueryLexer.interp
Normal file
File diff suppressed because one or more lines are too long
37
pkg/policy/parser/QueryLexer.tokens
Normal file
37
pkg/policy/parser/QueryLexer.tokens
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
AND_OP=1
|
||||||
|
OR_OP=2
|
||||||
|
SIMPLE_OP=3
|
||||||
|
REP=4
|
||||||
|
IN=5
|
||||||
|
AS=6
|
||||||
|
CBF=7
|
||||||
|
SELECT=8
|
||||||
|
FROM=9
|
||||||
|
FILTER=10
|
||||||
|
WILDCARD=11
|
||||||
|
CLAUSE_SAME=12
|
||||||
|
CLAUSE_DISTINCT=13
|
||||||
|
L_PAREN=14
|
||||||
|
R_PAREN=15
|
||||||
|
AT=16
|
||||||
|
IDENT=17
|
||||||
|
NUMBER1=18
|
||||||
|
ZERO=19
|
||||||
|
STRING=20
|
||||||
|
WS=21
|
||||||
|
'AND'=1
|
||||||
|
'OR'=2
|
||||||
|
'REP'=4
|
||||||
|
'IN'=5
|
||||||
|
'AS'=6
|
||||||
|
'CBF'=7
|
||||||
|
'SELECT'=8
|
||||||
|
'FROM'=9
|
||||||
|
'FILTER'=10
|
||||||
|
'*'=11
|
||||||
|
'SAME'=12
|
||||||
|
'DISTINCT'=13
|
||||||
|
'('=14
|
||||||
|
')'=15
|
||||||
|
'@'=16
|
||||||
|
'0'=19
|
3
pkg/policy/parser/generate.go
Normal file
3
pkg/policy/parser/generate.go
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
package parser
|
||||||
|
|
||||||
|
//go:generate antlr4 -Dlanguage=Go -visitor QueryLexer.g4 Query.g4
|
106
pkg/policy/parser/query_base_listener.go
Normal file
106
pkg/policy/parser/query_base_listener.go
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// Code generated from Query.g4 by ANTLR 4.9.2. DO NOT EDIT.
|
||||||
|
|
||||||
|
package parser // Query
|
||||||
|
|
||||||
|
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||||
|
|
||||||
|
// BaseQueryListener is a complete listener for a parse tree produced by Query.
|
||||||
|
type BaseQueryListener struct{}
|
||||||
|
|
||||||
|
var _ QueryListener = &BaseQueryListener{}
|
||||||
|
|
||||||
|
// VisitTerminal is called when a terminal node is visited.
|
||||||
|
func (s *BaseQueryListener) VisitTerminal(node antlr.TerminalNode) {}
|
||||||
|
|
||||||
|
// VisitErrorNode is called when an error node is visited.
|
||||||
|
func (s *BaseQueryListener) VisitErrorNode(node antlr.ErrorNode) {}
|
||||||
|
|
||||||
|
// EnterEveryRule is called when any rule is entered.
|
||||||
|
func (s *BaseQueryListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}
|
||||||
|
|
||||||
|
// ExitEveryRule is called when any rule is exited.
|
||||||
|
func (s *BaseQueryListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}
|
||||||
|
|
||||||
|
// EnterPolicy is called when production policy is entered.
|
||||||
|
func (s *BaseQueryListener) EnterPolicy(ctx *PolicyContext) {}
|
||||||
|
|
||||||
|
// ExitPolicy is called when production policy is exited.
|
||||||
|
func (s *BaseQueryListener) ExitPolicy(ctx *PolicyContext) {}
|
||||||
|
|
||||||
|
// EnterRepStmt is called when production repStmt is entered.
|
||||||
|
func (s *BaseQueryListener) EnterRepStmt(ctx *RepStmtContext) {}
|
||||||
|
|
||||||
|
// ExitRepStmt is called when production repStmt is exited.
|
||||||
|
func (s *BaseQueryListener) ExitRepStmt(ctx *RepStmtContext) {}
|
||||||
|
|
||||||
|
// EnterCbfStmt is called when production cbfStmt is entered.
|
||||||
|
func (s *BaseQueryListener) EnterCbfStmt(ctx *CbfStmtContext) {}
|
||||||
|
|
||||||
|
// ExitCbfStmt is called when production cbfStmt is exited.
|
||||||
|
func (s *BaseQueryListener) ExitCbfStmt(ctx *CbfStmtContext) {}
|
||||||
|
|
||||||
|
// EnterSelectStmt is called when production selectStmt is entered.
|
||||||
|
func (s *BaseQueryListener) EnterSelectStmt(ctx *SelectStmtContext) {}
|
||||||
|
|
||||||
|
// ExitSelectStmt is called when production selectStmt is exited.
|
||||||
|
func (s *BaseQueryListener) ExitSelectStmt(ctx *SelectStmtContext) {}
|
||||||
|
|
||||||
|
// EnterClause is called when production clause is entered.
|
||||||
|
func (s *BaseQueryListener) EnterClause(ctx *ClauseContext) {}
|
||||||
|
|
||||||
|
// ExitClause is called when production clause is exited.
|
||||||
|
func (s *BaseQueryListener) ExitClause(ctx *ClauseContext) {}
|
||||||
|
|
||||||
|
// EnterFilterExpr is called when production filterExpr is entered.
|
||||||
|
func (s *BaseQueryListener) EnterFilterExpr(ctx *FilterExprContext) {}
|
||||||
|
|
||||||
|
// ExitFilterExpr is called when production filterExpr is exited.
|
||||||
|
func (s *BaseQueryListener) ExitFilterExpr(ctx *FilterExprContext) {}
|
||||||
|
|
||||||
|
// EnterFilterStmt is called when production filterStmt is entered.
|
||||||
|
func (s *BaseQueryListener) EnterFilterStmt(ctx *FilterStmtContext) {}
|
||||||
|
|
||||||
|
// ExitFilterStmt is called when production filterStmt is exited.
|
||||||
|
func (s *BaseQueryListener) ExitFilterStmt(ctx *FilterStmtContext) {}
|
||||||
|
|
||||||
|
// EnterExpr is called when production expr is entered.
|
||||||
|
func (s *BaseQueryListener) EnterExpr(ctx *ExprContext) {}
|
||||||
|
|
||||||
|
// ExitExpr is called when production expr is exited.
|
||||||
|
func (s *BaseQueryListener) ExitExpr(ctx *ExprContext) {}
|
||||||
|
|
||||||
|
// EnterFilterKey is called when production filterKey is entered.
|
||||||
|
func (s *BaseQueryListener) EnterFilterKey(ctx *FilterKeyContext) {}
|
||||||
|
|
||||||
|
// ExitFilterKey is called when production filterKey is exited.
|
||||||
|
func (s *BaseQueryListener) ExitFilterKey(ctx *FilterKeyContext) {}
|
||||||
|
|
||||||
|
// EnterFilterValue is called when production filterValue is entered.
|
||||||
|
func (s *BaseQueryListener) EnterFilterValue(ctx *FilterValueContext) {}
|
||||||
|
|
||||||
|
// ExitFilterValue is called when production filterValue is exited.
|
||||||
|
func (s *BaseQueryListener) ExitFilterValue(ctx *FilterValueContext) {}
|
||||||
|
|
||||||
|
// EnterNumber is called when production number is entered.
|
||||||
|
func (s *BaseQueryListener) EnterNumber(ctx *NumberContext) {}
|
||||||
|
|
||||||
|
// ExitNumber is called when production number is exited.
|
||||||
|
func (s *BaseQueryListener) ExitNumber(ctx *NumberContext) {}
|
||||||
|
|
||||||
|
// EnterKeyword is called when production keyword is entered.
|
||||||
|
func (s *BaseQueryListener) EnterKeyword(ctx *KeywordContext) {}
|
||||||
|
|
||||||
|
// ExitKeyword is called when production keyword is exited.
|
||||||
|
func (s *BaseQueryListener) ExitKeyword(ctx *KeywordContext) {}
|
||||||
|
|
||||||
|
// EnterIdent is called when production ident is entered.
|
||||||
|
func (s *BaseQueryListener) EnterIdent(ctx *IdentContext) {}
|
||||||
|
|
||||||
|
// ExitIdent is called when production ident is exited.
|
||||||
|
func (s *BaseQueryListener) ExitIdent(ctx *IdentContext) {}
|
||||||
|
|
||||||
|
// EnterIdentWC is called when production identWC is entered.
|
||||||
|
func (s *BaseQueryListener) EnterIdentWC(ctx *IdentWCContext) {}
|
||||||
|
|
||||||
|
// ExitIdentWC is called when production identWC is exited.
|
||||||
|
func (s *BaseQueryListener) ExitIdentWC(ctx *IdentWCContext) {}
|
65
pkg/policy/parser/query_base_visitor.go
Normal file
65
pkg/policy/parser/query_base_visitor.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// Code generated from Query.g4 by ANTLR 4.9.2. DO NOT EDIT.
|
||||||
|
|
||||||
|
package parser // Query
|
||||||
|
|
||||||
|
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||||
|
|
||||||
|
type BaseQueryVisitor struct {
|
||||||
|
*antlr.BaseParseTreeVisitor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitPolicy(ctx *PolicyContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitRepStmt(ctx *RepStmtContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitCbfStmt(ctx *CbfStmtContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitSelectStmt(ctx *SelectStmtContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitClause(ctx *ClauseContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitFilterExpr(ctx *FilterExprContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitFilterStmt(ctx *FilterStmtContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitExpr(ctx *ExprContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitFilterKey(ctx *FilterKeyContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitFilterValue(ctx *FilterValueContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitNumber(ctx *NumberContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitKeyword(ctx *KeywordContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitIdent(ctx *IdentContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BaseQueryVisitor) VisitIdentWC(ctx *IdentWCContext) interface{} {
|
||||||
|
return v.VisitChildren(ctx)
|
||||||
|
}
|
193
pkg/policy/parser/query_lexer.go
Normal file
193
pkg/policy/parser/query_lexer.go
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
// Code generated from QueryLexer.g4 by ANTLR 4.9.2. DO NOT EDIT.
|
||||||
|
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/antlr/antlr4/runtime/Go/antlr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Suppress unused import error
|
||||||
|
var _ = fmt.Printf
|
||||||
|
var _ = unicode.IsLetter
|
||||||
|
|
||||||
|
var serializedLexerAtn = []uint16{
|
||||||
|
3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 23, 200,
|
||||||
|
8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7,
|
||||||
|
9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12,
|
||||||
|
4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4,
|
||||||
|
18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23,
|
||||||
|
9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9,
|
||||||
|
28, 4, 29, 9, 29, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4,
|
||||||
|
3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 79, 10,
|
||||||
|
4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 8, 3,
|
||||||
|
8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10,
|
||||||
|
3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3,
|
||||||
|
12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14,
|
||||||
|
3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3,
|
||||||
|
17, 3, 18, 3, 18, 3, 18, 7, 18, 139, 10, 18, 12, 18, 14, 18, 142, 11, 18,
|
||||||
|
3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 7, 21, 150, 10, 21, 12, 21, 14,
|
||||||
|
21, 153, 11, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 7, 23, 160, 10, 23,
|
||||||
|
12, 23, 14, 23, 163, 11, 23, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 169, 10,
|
||||||
|
23, 12, 23, 14, 23, 172, 11, 23, 3, 23, 5, 23, 175, 10, 23, 3, 24, 3, 24,
|
||||||
|
3, 24, 5, 24, 180, 10, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3,
|
||||||
|
26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 6, 29, 195, 10, 29, 13, 29,
|
||||||
|
14, 29, 196, 3, 29, 3, 29, 2, 2, 30, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13,
|
||||||
|
8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17,
|
||||||
|
33, 18, 35, 19, 37, 2, 39, 2, 41, 20, 43, 21, 45, 22, 47, 2, 49, 2, 51,
|
||||||
|
2, 53, 2, 55, 2, 57, 23, 3, 2, 10, 3, 2, 50, 59, 5, 2, 67, 92, 97, 97,
|
||||||
|
99, 124, 3, 2, 51, 59, 11, 2, 36, 36, 41, 41, 49, 49, 94, 94, 100, 100,
|
||||||
|
104, 104, 112, 112, 116, 116, 118, 118, 5, 2, 50, 59, 67, 72, 99, 104,
|
||||||
|
5, 2, 2, 33, 41, 41, 94, 94, 5, 2, 2, 33, 36, 36, 94, 94, 5, 2, 11, 12,
|
||||||
|
15, 15, 34, 34, 2, 207, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2,
|
||||||
|
2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3,
|
||||||
|
2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23,
|
||||||
|
3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2,
|
||||||
|
31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2,
|
||||||
|
2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 3, 59, 3, 2, 2,
|
||||||
|
2, 5, 63, 3, 2, 2, 2, 7, 78, 3, 2, 2, 2, 9, 80, 3, 2, 2, 2, 11, 84, 3,
|
||||||
|
2, 2, 2, 13, 87, 3, 2, 2, 2, 15, 90, 3, 2, 2, 2, 17, 94, 3, 2, 2, 2, 19,
|
||||||
|
101, 3, 2, 2, 2, 21, 106, 3, 2, 2, 2, 23, 113, 3, 2, 2, 2, 25, 115, 3,
|
||||||
|
2, 2, 2, 27, 120, 3, 2, 2, 2, 29, 129, 3, 2, 2, 2, 31, 131, 3, 2, 2, 2,
|
||||||
|
33, 133, 3, 2, 2, 2, 35, 135, 3, 2, 2, 2, 37, 143, 3, 2, 2, 2, 39, 145,
|
||||||
|
3, 2, 2, 2, 41, 147, 3, 2, 2, 2, 43, 154, 3, 2, 2, 2, 45, 174, 3, 2, 2,
|
||||||
|
2, 47, 176, 3, 2, 2, 2, 49, 181, 3, 2, 2, 2, 51, 187, 3, 2, 2, 2, 53, 189,
|
||||||
|
3, 2, 2, 2, 55, 191, 3, 2, 2, 2, 57, 194, 3, 2, 2, 2, 59, 60, 7, 67, 2,
|
||||||
|
2, 60, 61, 7, 80, 2, 2, 61, 62, 7, 70, 2, 2, 62, 4, 3, 2, 2, 2, 63, 64,
|
||||||
|
7, 81, 2, 2, 64, 65, 7, 84, 2, 2, 65, 6, 3, 2, 2, 2, 66, 67, 7, 71, 2,
|
||||||
|
2, 67, 79, 7, 83, 2, 2, 68, 69, 7, 80, 2, 2, 69, 79, 7, 71, 2, 2, 70, 71,
|
||||||
|
7, 73, 2, 2, 71, 79, 7, 71, 2, 2, 72, 73, 7, 73, 2, 2, 73, 79, 7, 86, 2,
|
||||||
|
2, 74, 75, 7, 78, 2, 2, 75, 79, 7, 86, 2, 2, 76, 77, 7, 78, 2, 2, 77, 79,
|
||||||
|
7, 71, 2, 2, 78, 66, 3, 2, 2, 2, 78, 68, 3, 2, 2, 2, 78, 70, 3, 2, 2, 2,
|
||||||
|
78, 72, 3, 2, 2, 2, 78, 74, 3, 2, 2, 2, 78, 76, 3, 2, 2, 2, 79, 8, 3, 2,
|
||||||
|
2, 2, 80, 81, 7, 84, 2, 2, 81, 82, 7, 71, 2, 2, 82, 83, 7, 82, 2, 2, 83,
|
||||||
|
10, 3, 2, 2, 2, 84, 85, 7, 75, 2, 2, 85, 86, 7, 80, 2, 2, 86, 12, 3, 2,
|
||||||
|
2, 2, 87, 88, 7, 67, 2, 2, 88, 89, 7, 85, 2, 2, 89, 14, 3, 2, 2, 2, 90,
|
||||||
|
91, 7, 69, 2, 2, 91, 92, 7, 68, 2, 2, 92, 93, 7, 72, 2, 2, 93, 16, 3, 2,
|
||||||
|
2, 2, 94, 95, 7, 85, 2, 2, 95, 96, 7, 71, 2, 2, 96, 97, 7, 78, 2, 2, 97,
|
||||||
|
98, 7, 71, 2, 2, 98, 99, 7, 69, 2, 2, 99, 100, 7, 86, 2, 2, 100, 18, 3,
|
||||||
|
2, 2, 2, 101, 102, 7, 72, 2, 2, 102, 103, 7, 84, 2, 2, 103, 104, 7, 81,
|
||||||
|
2, 2, 104, 105, 7, 79, 2, 2, 105, 20, 3, 2, 2, 2, 106, 107, 7, 72, 2, 2,
|
||||||
|
107, 108, 7, 75, 2, 2, 108, 109, 7, 78, 2, 2, 109, 110, 7, 86, 2, 2, 110,
|
||||||
|
111, 7, 71, 2, 2, 111, 112, 7, 84, 2, 2, 112, 22, 3, 2, 2, 2, 113, 114,
|
||||||
|
7, 44, 2, 2, 114, 24, 3, 2, 2, 2, 115, 116, 7, 85, 2, 2, 116, 117, 7, 67,
|
||||||
|
2, 2, 117, 118, 7, 79, 2, 2, 118, 119, 7, 71, 2, 2, 119, 26, 3, 2, 2, 2,
|
||||||
|
120, 121, 7, 70, 2, 2, 121, 122, 7, 75, 2, 2, 122, 123, 7, 85, 2, 2, 123,
|
||||||
|
124, 7, 86, 2, 2, 124, 125, 7, 75, 2, 2, 125, 126, 7, 80, 2, 2, 126, 127,
|
||||||
|
7, 69, 2, 2, 127, 128, 7, 86, 2, 2, 128, 28, 3, 2, 2, 2, 129, 130, 7, 42,
|
||||||
|
2, 2, 130, 30, 3, 2, 2, 2, 131, 132, 7, 43, 2, 2, 132, 32, 3, 2, 2, 2,
|
||||||
|
133, 134, 7, 66, 2, 2, 134, 34, 3, 2, 2, 2, 135, 140, 5, 39, 20, 2, 136,
|
||||||
|
139, 5, 37, 19, 2, 137, 139, 5, 39, 20, 2, 138, 136, 3, 2, 2, 2, 138, 137,
|
||||||
|
3, 2, 2, 2, 139, 142, 3, 2, 2, 2, 140, 138, 3, 2, 2, 2, 140, 141, 3, 2,
|
||||||
|
2, 2, 141, 36, 3, 2, 2, 2, 142, 140, 3, 2, 2, 2, 143, 144, 9, 2, 2, 2,
|
||||||
|
144, 38, 3, 2, 2, 2, 145, 146, 9, 3, 2, 2, 146, 40, 3, 2, 2, 2, 147, 151,
|
||||||
|
9, 4, 2, 2, 148, 150, 5, 37, 19, 2, 149, 148, 3, 2, 2, 2, 150, 153, 3,
|
||||||
|
2, 2, 2, 151, 149, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 42, 3, 2, 2,
|
||||||
|
2, 153, 151, 3, 2, 2, 2, 154, 155, 7, 50, 2, 2, 155, 44, 3, 2, 2, 2, 156,
|
||||||
|
161, 7, 36, 2, 2, 157, 160, 5, 47, 24, 2, 158, 160, 5, 55, 28, 2, 159,
|
||||||
|
157, 3, 2, 2, 2, 159, 158, 3, 2, 2, 2, 160, 163, 3, 2, 2, 2, 161, 159,
|
||||||
|
3, 2, 2, 2, 161, 162, 3, 2, 2, 2, 162, 164, 3, 2, 2, 2, 163, 161, 3, 2,
|
||||||
|
2, 2, 164, 175, 7, 36, 2, 2, 165, 170, 7, 41, 2, 2, 166, 169, 5, 47, 24,
|
||||||
|
2, 167, 169, 5, 53, 27, 2, 168, 166, 3, 2, 2, 2, 168, 167, 3, 2, 2, 2,
|
||||||
|
169, 172, 3, 2, 2, 2, 170, 168, 3, 2, 2, 2, 170, 171, 3, 2, 2, 2, 171,
|
||||||
|
173, 3, 2, 2, 2, 172, 170, 3, 2, 2, 2, 173, 175, 7, 41, 2, 2, 174, 156,
|
||||||
|
3, 2, 2, 2, 174, 165, 3, 2, 2, 2, 175, 46, 3, 2, 2, 2, 176, 179, 7, 94,
|
||||||
|
2, 2, 177, 180, 9, 5, 2, 2, 178, 180, 5, 49, 25, 2, 179, 177, 3, 2, 2,
|
||||||
|
2, 179, 178, 3, 2, 2, 2, 180, 48, 3, 2, 2, 2, 181, 182, 7, 119, 2, 2, 182,
|
||||||
|
183, 5, 51, 26, 2, 183, 184, 5, 51, 26, 2, 184, 185, 5, 51, 26, 2, 185,
|
||||||
|
186, 5, 51, 26, 2, 186, 50, 3, 2, 2, 2, 187, 188, 9, 6, 2, 2, 188, 52,
|
||||||
|
3, 2, 2, 2, 189, 190, 10, 7, 2, 2, 190, 54, 3, 2, 2, 2, 191, 192, 10, 8,
|
||||||
|
2, 2, 192, 56, 3, 2, 2, 2, 193, 195, 9, 9, 2, 2, 194, 193, 3, 2, 2, 2,
|
||||||
|
195, 196, 3, 2, 2, 2, 196, 194, 3, 2, 2, 2, 196, 197, 3, 2, 2, 2, 197,
|
||||||
|
198, 3, 2, 2, 2, 198, 199, 8, 29, 2, 2, 199, 58, 3, 2, 2, 2, 14, 2, 78,
|
||||||
|
138, 140, 151, 159, 161, 168, 170, 174, 179, 196, 3, 8, 2, 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
var lexerChannelNames = []string{
|
||||||
|
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
|
||||||
|
}
|
||||||
|
|
||||||
|
var lexerModeNames = []string{
|
||||||
|
"DEFAULT_MODE",
|
||||||
|
}
|
||||||
|
|
||||||
|
var lexerLiteralNames = []string{
|
||||||
|
"", "'AND'", "'OR'", "", "'REP'", "'IN'", "'AS'", "'CBF'", "'SELECT'",
|
||||||
|
"'FROM'", "'FILTER'", "'*'", "'SAME'", "'DISTINCT'", "'('", "')'", "'@'",
|
||||||
|
"", "", "'0'",
|
||||||
|
}
|
||||||
|
|
||||||
|
var lexerSymbolicNames = []string{
|
||||||
|
"", "AND_OP", "OR_OP", "SIMPLE_OP", "REP", "IN", "AS", "CBF", "SELECT",
|
||||||
|
"FROM", "FILTER", "WILDCARD", "CLAUSE_SAME", "CLAUSE_DISTINCT", "L_PAREN",
|
||||||
|
"R_PAREN", "AT", "IDENT", "NUMBER1", "ZERO", "STRING", "WS",
|
||||||
|
}
|
||||||
|
|
||||||
|
var lexerRuleNames = []string{
|
||||||
|
"AND_OP", "OR_OP", "SIMPLE_OP", "REP", "IN", "AS", "CBF", "SELECT", "FROM",
|
||||||
|
"FILTER", "WILDCARD", "CLAUSE_SAME", "CLAUSE_DISTINCT", "L_PAREN", "R_PAREN",
|
||||||
|
"AT", "IDENT", "Digit", "Nondigit", "NUMBER1", "ZERO", "STRING", "ESC",
|
||||||
|
"UNICODE", "HEX", "SAFECODEPOINTSINGLE", "SAFECODEPOINTDOUBLE", "WS",
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryLexer struct {
|
||||||
|
*antlr.BaseLexer
|
||||||
|
channelNames []string
|
||||||
|
modeNames []string
|
||||||
|
// TODO: EOF string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewQueryLexer produces a new lexer instance for the optional input antlr.CharStream.
|
||||||
|
//
|
||||||
|
// The *QueryLexer instance produced may be reused by calling the SetInputStream method.
|
||||||
|
// The initial lexer configuration is expensive to construct, and the object is not thread-safe;
|
||||||
|
// however, if used within a Golang sync.Pool, the construction cost amortizes well and the
|
||||||
|
// objects can be used in a thread-safe manner.
|
||||||
|
func NewQueryLexer(input antlr.CharStream) *QueryLexer {
|
||||||
|
l := new(QueryLexer)
|
||||||
|
lexerDeserializer := antlr.NewATNDeserializer(nil)
|
||||||
|
lexerAtn := lexerDeserializer.DeserializeFromUInt16(serializedLexerAtn)
|
||||||
|
lexerDecisionToDFA := make([]*antlr.DFA, len(lexerAtn.DecisionToState))
|
||||||
|
for index, ds := range lexerAtn.DecisionToState {
|
||||||
|
lexerDecisionToDFA[index] = antlr.NewDFA(ds, index)
|
||||||
|
}
|
||||||
|
l.BaseLexer = antlr.NewBaseLexer(input)
|
||||||
|
l.Interpreter = antlr.NewLexerATNSimulator(l, lexerAtn, lexerDecisionToDFA, antlr.NewPredictionContextCache())
|
||||||
|
|
||||||
|
l.channelNames = lexerChannelNames
|
||||||
|
l.modeNames = lexerModeNames
|
||||||
|
l.RuleNames = lexerRuleNames
|
||||||
|
l.LiteralNames = lexerLiteralNames
|
||||||
|
l.SymbolicNames = lexerSymbolicNames
|
||||||
|
l.GrammarFileName = "QueryLexer.g4"
|
||||||
|
// TODO: l.EOF = antlr.TokenEOF
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryLexer tokens.
|
||||||
|
const (
|
||||||
|
QueryLexerAND_OP = 1
|
||||||
|
QueryLexerOR_OP = 2
|
||||||
|
QueryLexerSIMPLE_OP = 3
|
||||||
|
QueryLexerREP = 4
|
||||||
|
QueryLexerIN = 5
|
||||||
|
QueryLexerAS = 6
|
||||||
|
QueryLexerCBF = 7
|
||||||
|
QueryLexerSELECT = 8
|
||||||
|
QueryLexerFROM = 9
|
||||||
|
QueryLexerFILTER = 10
|
||||||
|
QueryLexerWILDCARD = 11
|
||||||
|
QueryLexerCLAUSE_SAME = 12
|
||||||
|
QueryLexerCLAUSE_DISTINCT = 13
|
||||||
|
QueryLexerL_PAREN = 14
|
||||||
|
QueryLexerR_PAREN = 15
|
||||||
|
QueryLexerAT = 16
|
||||||
|
QueryLexerIDENT = 17
|
||||||
|
QueryLexerNUMBER1 = 18
|
||||||
|
QueryLexerZERO = 19
|
||||||
|
QueryLexerSTRING = 20
|
||||||
|
QueryLexerWS = 21
|
||||||
|
)
|
94
pkg/policy/parser/query_listener.go
Normal file
94
pkg/policy/parser/query_listener.go
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// Code generated from Query.g4 by ANTLR 4.9.2. DO NOT EDIT.
|
||||||
|
|
||||||
|
package parser // Query
|
||||||
|
|
||||||
|
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||||
|
|
||||||
|
// QueryListener is a complete listener for a parse tree produced by Query.
|
||||||
|
type QueryListener interface {
|
||||||
|
antlr.ParseTreeListener
|
||||||
|
|
||||||
|
// EnterPolicy is called when entering the policy production.
|
||||||
|
EnterPolicy(c *PolicyContext)
|
||||||
|
|
||||||
|
// EnterRepStmt is called when entering the repStmt production.
|
||||||
|
EnterRepStmt(c *RepStmtContext)
|
||||||
|
|
||||||
|
// EnterCbfStmt is called when entering the cbfStmt production.
|
||||||
|
EnterCbfStmt(c *CbfStmtContext)
|
||||||
|
|
||||||
|
// EnterSelectStmt is called when entering the selectStmt production.
|
||||||
|
EnterSelectStmt(c *SelectStmtContext)
|
||||||
|
|
||||||
|
// EnterClause is called when entering the clause production.
|
||||||
|
EnterClause(c *ClauseContext)
|
||||||
|
|
||||||
|
// EnterFilterExpr is called when entering the filterExpr production.
|
||||||
|
EnterFilterExpr(c *FilterExprContext)
|
||||||
|
|
||||||
|
// EnterFilterStmt is called when entering the filterStmt production.
|
||||||
|
EnterFilterStmt(c *FilterStmtContext)
|
||||||
|
|
||||||
|
// EnterExpr is called when entering the expr production.
|
||||||
|
EnterExpr(c *ExprContext)
|
||||||
|
|
||||||
|
// EnterFilterKey is called when entering the filterKey production.
|
||||||
|
EnterFilterKey(c *FilterKeyContext)
|
||||||
|
|
||||||
|
// EnterFilterValue is called when entering the filterValue production.
|
||||||
|
EnterFilterValue(c *FilterValueContext)
|
||||||
|
|
||||||
|
// EnterNumber is called when entering the number production.
|
||||||
|
EnterNumber(c *NumberContext)
|
||||||
|
|
||||||
|
// EnterKeyword is called when entering the keyword production.
|
||||||
|
EnterKeyword(c *KeywordContext)
|
||||||
|
|
||||||
|
// EnterIdent is called when entering the ident production.
|
||||||
|
EnterIdent(c *IdentContext)
|
||||||
|
|
||||||
|
// EnterIdentWC is called when entering the identWC production.
|
||||||
|
EnterIdentWC(c *IdentWCContext)
|
||||||
|
|
||||||
|
// ExitPolicy is called when exiting the policy production.
|
||||||
|
ExitPolicy(c *PolicyContext)
|
||||||
|
|
||||||
|
// ExitRepStmt is called when exiting the repStmt production.
|
||||||
|
ExitRepStmt(c *RepStmtContext)
|
||||||
|
|
||||||
|
// ExitCbfStmt is called when exiting the cbfStmt production.
|
||||||
|
ExitCbfStmt(c *CbfStmtContext)
|
||||||
|
|
||||||
|
// ExitSelectStmt is called when exiting the selectStmt production.
|
||||||
|
ExitSelectStmt(c *SelectStmtContext)
|
||||||
|
|
||||||
|
// ExitClause is called when exiting the clause production.
|
||||||
|
ExitClause(c *ClauseContext)
|
||||||
|
|
||||||
|
// ExitFilterExpr is called when exiting the filterExpr production.
|
||||||
|
ExitFilterExpr(c *FilterExprContext)
|
||||||
|
|
||||||
|
// ExitFilterStmt is called when exiting the filterStmt production.
|
||||||
|
ExitFilterStmt(c *FilterStmtContext)
|
||||||
|
|
||||||
|
// ExitExpr is called when exiting the expr production.
|
||||||
|
ExitExpr(c *ExprContext)
|
||||||
|
|
||||||
|
// ExitFilterKey is called when exiting the filterKey production.
|
||||||
|
ExitFilterKey(c *FilterKeyContext)
|
||||||
|
|
||||||
|
// ExitFilterValue is called when exiting the filterValue production.
|
||||||
|
ExitFilterValue(c *FilterValueContext)
|
||||||
|
|
||||||
|
// ExitNumber is called when exiting the number production.
|
||||||
|
ExitNumber(c *NumberContext)
|
||||||
|
|
||||||
|
// ExitKeyword is called when exiting the keyword production.
|
||||||
|
ExitKeyword(c *KeywordContext)
|
||||||
|
|
||||||
|
// ExitIdent is called when exiting the ident production.
|
||||||
|
ExitIdent(c *IdentContext)
|
||||||
|
|
||||||
|
// ExitIdentWC is called when exiting the identWC production.
|
||||||
|
ExitIdentWC(c *IdentWCContext)
|
||||||
|
}
|
2520
pkg/policy/parser/query_parser.go
Normal file
2520
pkg/policy/parser/query_parser.go
Normal file
File diff suppressed because it is too large
Load diff
52
pkg/policy/parser/query_visitor.go
Normal file
52
pkg/policy/parser/query_visitor.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// Code generated from Query.g4 by ANTLR 4.9.2. DO NOT EDIT.
|
||||||
|
|
||||||
|
package parser // Query
|
||||||
|
|
||||||
|
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||||
|
|
||||||
|
// A complete Visitor for a parse tree produced by Query.
|
||||||
|
type QueryVisitor interface {
|
||||||
|
antlr.ParseTreeVisitor
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#policy.
|
||||||
|
VisitPolicy(ctx *PolicyContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#repStmt.
|
||||||
|
VisitRepStmt(ctx *RepStmtContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#cbfStmt.
|
||||||
|
VisitCbfStmt(ctx *CbfStmtContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#selectStmt.
|
||||||
|
VisitSelectStmt(ctx *SelectStmtContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#clause.
|
||||||
|
VisitClause(ctx *ClauseContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#filterExpr.
|
||||||
|
VisitFilterExpr(ctx *FilterExprContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#filterStmt.
|
||||||
|
VisitFilterStmt(ctx *FilterStmtContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#expr.
|
||||||
|
VisitExpr(ctx *ExprContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#filterKey.
|
||||||
|
VisitFilterKey(ctx *FilterKeyContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#filterValue.
|
||||||
|
VisitFilterValue(ctx *FilterValueContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#number.
|
||||||
|
VisitNumber(ctx *NumberContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#keyword.
|
||||||
|
VisitKeyword(ctx *KeywordContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#ident.
|
||||||
|
VisitIdent(ctx *IdentContext) interface{}
|
||||||
|
|
||||||
|
// Visit a parse tree produced by Query#identWC.
|
||||||
|
VisitIdentWC(ctx *IdentWCContext) interface{}
|
||||||
|
}
|
|
@ -3,9 +3,12 @@ package policy
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/antlr/antlr4/runtime/Go/antlr"
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/pkg/policy/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -19,83 +22,256 @@ var (
|
||||||
ErrUnknownFilter = errors.New("policy: filter not found")
|
ErrUnknownFilter = errors.New("policy: filter not found")
|
||||||
// ErrUnknownSelector is returned when a value of IN is unknown.
|
// ErrUnknownSelector is returned when a value of IN is unknown.
|
||||||
ErrUnknownSelector = errors.New("policy: selector not found")
|
ErrUnknownSelector = errors.New("policy: selector not found")
|
||||||
|
// ErrSyntaxError is returned for errors found by ANTLR parser.
|
||||||
|
ErrSyntaxError = errors.New("policy: syntax error")
|
||||||
)
|
)
|
||||||
|
|
||||||
func parse(s string) (*query, error) {
|
type policyVisitor struct {
|
||||||
q := new(query)
|
errors []error
|
||||||
err := parser.Parse(strings.NewReader(s), q)
|
parser.BaseQueryVisitor
|
||||||
if err != nil {
|
antlr.DefaultErrorListener
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return q, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses s into a placement policy.
|
// Parse parses s into a placement policy.
|
||||||
func Parse(s string) (*netmap.PlacementPolicy, error) {
|
func Parse(s string) (*netmap.PlacementPolicy, error) {
|
||||||
q, err := parse(s)
|
return parse(s)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seenFilters := map[string]bool{}
|
func newPolicyVisitor() *policyVisitor {
|
||||||
fs := make([]*netmap.Filter, 0, len(q.Filters))
|
return &policyVisitor{}
|
||||||
for _, qf := range q.Filters {
|
}
|
||||||
f, err := filterFromOrChain(qf.Value, seenFilters)
|
|
||||||
if err != nil {
|
func parse(s string) (*netmap.PlacementPolicy, error) {
|
||||||
|
input := antlr.NewInputStream(s)
|
||||||
|
lexer := parser.NewQueryLexer(input)
|
||||||
|
stream := antlr.NewCommonTokenStream(lexer, 0)
|
||||||
|
|
||||||
|
p := parser.NewQuery(stream)
|
||||||
|
p.BuildParseTrees = true
|
||||||
|
|
||||||
|
v := newPolicyVisitor()
|
||||||
|
p.RemoveErrorListeners()
|
||||||
|
p.AddErrorListener(v)
|
||||||
|
pl := p.Policy().Accept(v)
|
||||||
|
|
||||||
|
if len(v.errors) != 0 {
|
||||||
|
return nil, v.errors[0]
|
||||||
|
}
|
||||||
|
if err := validatePolicy(pl.(*netmap.PlacementPolicy)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
f.SetName(qf.Name)
|
return pl.(*netmap.PlacementPolicy), nil
|
||||||
fs = append(fs, f)
|
}
|
||||||
seenFilters[qf.Name] = true
|
|
||||||
|
func (p *policyVisitor) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
|
||||||
|
p.reportError(fmt.Errorf("%w: line %d:%d %s", ErrSyntaxError, line, column, msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *policyVisitor) reportError(err error) interface{} {
|
||||||
|
p.errors = append(p.errors, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitPolicy implements parser.QueryVisitor interface.
|
||||||
|
func (p *policyVisitor) VisitPolicy(ctx *parser.PolicyContext) interface{} {
|
||||||
|
if len(p.errors) != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pl := new(netmap.PlacementPolicy)
|
||||||
|
|
||||||
|
repStmts := ctx.AllRepStmt()
|
||||||
|
rs := make([]*netmap.Replica, 0, len(repStmts))
|
||||||
|
for _, r := range repStmts {
|
||||||
|
res, ok := r.Accept(p).(*netmap.Replica)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rs = append(rs, res)
|
||||||
|
}
|
||||||
|
pl.SetReplicas(rs...)
|
||||||
|
|
||||||
|
if cbfStmt := ctx.CbfStmt(); cbfStmt != nil {
|
||||||
|
cbf, ok := cbfStmt.(*parser.CbfStmtContext).Accept(p).(uint32)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
pl.SetContainerBackupFactor(cbf)
|
||||||
|
}
|
||||||
|
|
||||||
|
selStmts := ctx.AllSelectStmt()
|
||||||
|
ss := make([]*netmap.Selector, 0, len(selStmts))
|
||||||
|
for _, s := range selStmts {
|
||||||
|
res, ok := s.Accept(p).(*netmap.Selector)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ss = append(ss, res)
|
||||||
|
}
|
||||||
|
pl.SetSelectors(ss...)
|
||||||
|
|
||||||
|
filtStmts := ctx.AllFilterStmt()
|
||||||
|
fs := make([]*netmap.Filter, 0, len(filtStmts))
|
||||||
|
for _, f := range filtStmts {
|
||||||
|
fs = append(fs, f.Accept(p).(*netmap.Filter))
|
||||||
|
}
|
||||||
|
pl.SetFilters(fs...)
|
||||||
|
|
||||||
|
return pl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *policyVisitor) VisitCbfStmt(ctx *parser.CbfStmtContext) interface{} {
|
||||||
|
cbf, err := strconv.ParseUint(ctx.GetBackupFactor().GetText(), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return p.reportError(ErrInvalidNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint32(cbf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitRepStmt implements parser.QueryVisitor interface.
|
||||||
|
func (p *policyVisitor) VisitRepStmt(ctx *parser.RepStmtContext) interface{} {
|
||||||
|
num, err := strconv.ParseUint(ctx.GetCount().GetText(), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return p.reportError(ErrInvalidNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := new(netmap.Replica)
|
||||||
|
rs.SetCount(uint32(num))
|
||||||
|
|
||||||
|
if sel := ctx.GetSelector(); sel != nil {
|
||||||
|
rs.SetSelector(sel.GetText())
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitSelectStmt implements parser.QueryVisitor interface.
|
||||||
|
func (p *policyVisitor) VisitSelectStmt(ctx *parser.SelectStmtContext) interface{} {
|
||||||
|
res, err := strconv.ParseUint(ctx.GetCount().GetText(), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return p.reportError(ErrInvalidNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := new(netmap.Selector)
|
||||||
|
s.SetCount(uint32(res))
|
||||||
|
|
||||||
|
if clStmt := ctx.Clause(); clStmt != nil {
|
||||||
|
s.SetClause(clauseFromString(clStmt.GetText()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if bStmt := ctx.GetBucket(); bStmt != nil {
|
||||||
|
s.SetAttribute(ctx.GetBucket().GetText())
|
||||||
|
}
|
||||||
|
|
||||||
|
s.SetFilter(ctx.GetFilter().GetText()) // either ident or wildcard
|
||||||
|
|
||||||
|
if ctx.AS() != nil {
|
||||||
|
s.SetName(ctx.GetName().GetText())
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitFilterStmt implements parser.QueryVisitor interface.
|
||||||
|
func (p *policyVisitor) VisitFilterStmt(ctx *parser.FilterStmtContext) interface{} {
|
||||||
|
f := p.VisitFilterExpr(ctx.GetExpr().(*parser.FilterExprContext)).(*netmap.Filter)
|
||||||
|
f.SetName(ctx.GetName().GetText())
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *policyVisitor) VisitFilterExpr(ctx *parser.FilterExprContext) interface{} {
|
||||||
|
if eCtx := ctx.Expr(); eCtx != nil {
|
||||||
|
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)
|
||||||
|
|
||||||
|
f1 := ctx.GetF1().Accept(p).(*netmap.Filter)
|
||||||
|
f2 := ctx.GetF2().Accept(p).(*netmap.Filter)
|
||||||
|
|
||||||
|
// Consider f1=(.. AND ..) AND f2. This can be merged because our AND operation
|
||||||
|
// is of arbitrary arity. ANTLR generates left-associative parse-tree by default.
|
||||||
|
if f1.Operation() == op {
|
||||||
|
f.SetInnerFilters(append(f1.InnerFilters(), f2)...)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
f.SetInnerFilters(f1, f2)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitFilterKey implements parser.QueryVisitor interface.
|
||||||
|
func (p *policyVisitor) VisitFilterKey(ctx *parser.FilterKeyContext) interface{} {
|
||||||
|
if id := ctx.Ident(); id != nil {
|
||||||
|
return id.GetText()
|
||||||
|
}
|
||||||
|
|
||||||
|
str := ctx.STRING().GetText()
|
||||||
|
return str[1 : len(str)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *policyVisitor) VisitFilterValue(ctx *parser.FilterValueContext) interface{} {
|
||||||
|
if id := ctx.Ident(); id != nil {
|
||||||
|
return id.GetText()
|
||||||
|
}
|
||||||
|
|
||||||
|
if num := ctx.Number(); num != nil {
|
||||||
|
return num.GetText()
|
||||||
|
}
|
||||||
|
|
||||||
|
str := ctx.STRING().GetText()
|
||||||
|
return str[1 : len(str)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitExpr implements parser.QueryVisitor interface.
|
||||||
|
func (p *policyVisitor) VisitExpr(ctx *parser.ExprContext) interface{} {
|
||||||
|
f := new(netmap.Filter)
|
||||||
|
if flt := ctx.GetFilter(); flt != nil {
|
||||||
|
f.SetName(flt.GetText())
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
key := ctx.GetKey().Accept(p)
|
||||||
|
opStr := ctx.SIMPLE_OP().GetText()
|
||||||
|
value := ctx.GetValue().Accept(p)
|
||||||
|
|
||||||
|
f.SetKey(key.(string))
|
||||||
|
f.SetOperation(operationFromString(opStr))
|
||||||
|
f.SetValue(value.(string))
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// validatePolicy checks high-level constraints such as filter link in SELECT
|
||||||
|
// being actually defined in FILTER section.
|
||||||
|
func validatePolicy(p *netmap.PlacementPolicy) error {
|
||||||
|
seenFilters := map[string]bool{}
|
||||||
|
for _, f := range p.Filters() {
|
||||||
|
seenFilters[f.Name()] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
seenSelectors := map[string]bool{}
|
seenSelectors := map[string]bool{}
|
||||||
ss := make([]*netmap.Selector, 0, len(q.Selectors))
|
for _, s := range p.Selectors() {
|
||||||
for _, qs := range q.Selectors {
|
if flt := s.Filter(); flt != netmap.MainFilterName && !seenFilters[flt] {
|
||||||
if qs.Filter != netmap.MainFilterName && !seenFilters[qs.Filter] {
|
return fmt.Errorf("%w: '%s'", ErrUnknownFilter, flt)
|
||||||
return nil, fmt.Errorf("%w: '%s'", ErrUnknownFilter, qs.Filter)
|
|
||||||
}
|
}
|
||||||
s := netmap.NewSelector()
|
seenSelectors[s.Name()] = true
|
||||||
switch len(qs.Bucket) {
|
|
||||||
case 1: // only bucket
|
|
||||||
s.SetAttribute(qs.Bucket[0])
|
|
||||||
case 2: // clause + bucket
|
|
||||||
s.SetClause(clauseFromString(qs.Bucket[0]))
|
|
||||||
s.SetAttribute(qs.Bucket[1])
|
|
||||||
}
|
|
||||||
s.SetName(qs.Name)
|
|
||||||
seenSelectors[qs.Name] = true
|
|
||||||
s.SetFilter(qs.Filter)
|
|
||||||
if qs.Count == 0 {
|
|
||||||
return nil, fmt.Errorf("%w: SELECT", ErrInvalidNumber)
|
|
||||||
}
|
|
||||||
s.SetCount(qs.Count)
|
|
||||||
ss = append(ss, s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rs := make([]*netmap.Replica, 0, len(q.Replicas))
|
for _, r := range p.Replicas() {
|
||||||
for _, qr := range q.Replicas {
|
if sel := r.Selector(); sel != "" && !seenSelectors[sel] {
|
||||||
r := netmap.NewReplica()
|
return fmt.Errorf("%w: '%s'", ErrUnknownSelector, sel)
|
||||||
if qr.Selector != "" {
|
|
||||||
if !seenSelectors[qr.Selector] {
|
|
||||||
return nil, fmt.Errorf("%w: '%s'", ErrUnknownSelector, qr.Selector)
|
|
||||||
}
|
}
|
||||||
r.SetSelector(qr.Selector)
|
|
||||||
}
|
|
||||||
if qr.Count == 0 {
|
|
||||||
return nil, fmt.Errorf("%w: REP", ErrInvalidNumber)
|
|
||||||
}
|
|
||||||
r.SetCount(uint32(qr.Count))
|
|
||||||
rs = append(rs, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p := new(netmap.PlacementPolicy)
|
return nil
|
||||||
p.SetFilters(fs...)
|
|
||||||
p.SetSelectors(ss...)
|
|
||||||
p.SetReplicas(rs...)
|
|
||||||
p.SetContainerBackupFactor(q.CBF)
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func clauseFromString(s string) netmap.Clause {
|
func clauseFromString(s string) netmap.Clause {
|
||||||
|
@ -105,74 +281,31 @@ func clauseFromString(s string) netmap.Clause {
|
||||||
case "DISTINCT":
|
case "DISTINCT":
|
||||||
return netmap.ClauseDistinct
|
return netmap.ClauseDistinct
|
||||||
default:
|
default:
|
||||||
return 0
|
// Such errors should be handled by ANTLR code thus this panic.
|
||||||
|
panic(fmt.Errorf("BUG: invalid clause: %s", s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterFromOrChain(expr *orChain, seen map[string]bool) (*netmap.Filter, error) {
|
func operationFromString(op string) netmap.Operation {
|
||||||
var fs []*netmap.Filter
|
switch strings.ToUpper(op) {
|
||||||
for _, ac := range expr.Clauses {
|
case "AND":
|
||||||
f, err := filterFromAndChain(ac, seen)
|
return netmap.OpAND
|
||||||
if err != nil {
|
case "OR":
|
||||||
return nil, err
|
return netmap.OpOR
|
||||||
}
|
|
||||||
fs = append(fs, f)
|
|
||||||
}
|
|
||||||
if len(fs) == 1 {
|
|
||||||
return fs[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f := netmap.NewFilter()
|
|
||||||
f.SetOperation(netmap.OpOR)
|
|
||||||
f.SetInnerFilters(fs...)
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterFromAndChain(expr *andChain, seen map[string]bool) (*netmap.Filter, error) {
|
|
||||||
var fs []*netmap.Filter
|
|
||||||
for _, fe := range expr.Clauses {
|
|
||||||
var f *netmap.Filter
|
|
||||||
var err error
|
|
||||||
if fe.Expr != nil {
|
|
||||||
f, err = filterFromSimpleExpr(fe.Expr, seen)
|
|
||||||
} else {
|
|
||||||
f = netmap.NewFilter()
|
|
||||||
f.SetName(fe.Reference)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fs = append(fs, f)
|
|
||||||
}
|
|
||||||
if len(fs) == 1 {
|
|
||||||
return fs[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f := netmap.NewFilter()
|
|
||||||
f.SetOperation(netmap.OpAND)
|
|
||||||
f.SetInnerFilters(fs...)
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterFromSimpleExpr(se *simpleExpr, seen map[string]bool) (*netmap.Filter, error) {
|
|
||||||
f := netmap.NewFilter()
|
|
||||||
f.SetKey(se.Key)
|
|
||||||
switch se.Op {
|
|
||||||
case "EQ":
|
case "EQ":
|
||||||
f.SetOperation(netmap.OpEQ)
|
return netmap.OpEQ
|
||||||
case "NE":
|
case "NE":
|
||||||
f.SetOperation(netmap.OpNE)
|
return netmap.OpNE
|
||||||
case "GE":
|
case "GE":
|
||||||
f.SetOperation(netmap.OpGE)
|
return netmap.OpGE
|
||||||
case "GT":
|
case "GT":
|
||||||
f.SetOperation(netmap.OpGT)
|
return netmap.OpGT
|
||||||
case "LE":
|
case "LE":
|
||||||
f.SetOperation(netmap.OpLE)
|
return netmap.OpLE
|
||||||
case "LT":
|
case "LT":
|
||||||
f.SetOperation(netmap.OpLT)
|
return netmap.OpLT
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("%w: '%s'", ErrUnknownOp, se.Op)
|
// Such errors should be handled by ANTLR code thus this panic.
|
||||||
|
panic(fmt.Errorf("BUG: invalid operation: %s", op))
|
||||||
}
|
}
|
||||||
f.SetValue(se.Value)
|
|
||||||
return f, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
"github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
||||||
|
@ -80,6 +82,32 @@ func TestFromSelectNoAttribute(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestString(t *testing.T) {
|
||||||
|
qTemplate := `REP 1
|
||||||
|
SELECT 1 IN City FROM Filt
|
||||||
|
FILTER Property EQ %s AND Something NE 7 AS Filt`
|
||||||
|
|
||||||
|
testCases := []string{
|
||||||
|
`"double-quoted"`,
|
||||||
|
`"with ' single"`,
|
||||||
|
`'single-quoted'`,
|
||||||
|
`'with " double'`,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range testCases {
|
||||||
|
t.Run(s, func(t *testing.T) {
|
||||||
|
q := fmt.Sprintf(qTemplate, s)
|
||||||
|
r, err := Parse(q)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expected := newFilter("Filt", "", "", netmap.AND,
|
||||||
|
newFilter("", "Property", s[1:len(s)-1], netmap.EQ),
|
||||||
|
newFilter("", "Something", "7", netmap.NE))
|
||||||
|
require.EqualValues(t, []*netmap.Filter{expected}, r.Filters())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFromSelectClause(t *testing.T) {
|
func TestFromSelectClause(t *testing.T) {
|
||||||
q := `REP 4
|
q := `REP 4
|
||||||
SELECT 3 IN Country FROM *
|
SELECT 3 IN Country FROM *
|
||||||
|
@ -188,6 +216,30 @@ FILTER City EQ "SPB" AND SSD EQ true OR City EQ "SPB" AND Rating GE 5 AS SPBSSD`
|
||||||
require.EqualValues(t, expected, r)
|
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) {
|
func TestValidation(t *testing.T) {
|
||||||
t.Run("MissingSelector", func(t *testing.T) {
|
t.Run("MissingSelector", func(t *testing.T) {
|
||||||
q := `REP 3 IN RU`
|
q := `REP 3 IN RU`
|
||||||
|
@ -205,12 +257,12 @@ func TestValidation(t *testing.T) {
|
||||||
SELECT 1 IN City FROM F
|
SELECT 1 IN City FROM F
|
||||||
FILTER Country KEK RU AS F`
|
FILTER Country KEK RU AS F`
|
||||||
_, err := Parse(q)
|
_, err := Parse(q)
|
||||||
require.True(t, errors.Is(err, ErrUnknownOp), "got: %v", err)
|
require.True(t, errors.Is(err, ErrSyntaxError), "got: %v", err)
|
||||||
})
|
})
|
||||||
t.Run("TypoInREP", func(t *testing.T) {
|
t.Run("TypoInREP", func(t *testing.T) {
|
||||||
q := `REK 3`
|
q := `REK 3`
|
||||||
_, err := Parse(q)
|
_, err := Parse(q)
|
||||||
require.Error(t, err)
|
require.True(t, errors.Is(err, ErrSyntaxError))
|
||||||
})
|
})
|
||||||
t.Run("InvalidFilterName", func(t *testing.T) {
|
t.Run("InvalidFilterName", func(t *testing.T) {
|
||||||
q := `REP 3
|
q := `REP 3
|
||||||
|
@ -220,18 +272,29 @@ func TestValidation(t *testing.T) {
|
||||||
_, err := Parse(q)
|
_, err := Parse(q)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
t.Run("InvalidNumberInREP", func(t *testing.T) {
|
}
|
||||||
q := `REP 0`
|
|
||||||
_, err := Parse(q)
|
// Checks that an error is returned in cases when positive 32-bit integer is expected.
|
||||||
require.True(t, errors.Is(err, ErrInvalidNumber), "got: %v", err)
|
func TestInvalidNumbers(t *testing.T) {
|
||||||
|
tmpls := []string{
|
||||||
|
"REP %d",
|
||||||
|
"REP 1 CBF %d",
|
||||||
|
"REP 1 SELECT %d FROM *",
|
||||||
|
}
|
||||||
|
for i := range tmpls {
|
||||||
|
zero := fmt.Sprintf(tmpls[i], 0)
|
||||||
|
t.Run(zero, func(t *testing.T) {
|
||||||
|
_, err := Parse(zero)
|
||||||
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
t.Run("InvalidNumberInREP", func(t *testing.T) {
|
|
||||||
q := `REP 1 IN Good
|
big := fmt.Sprintf(tmpls[i], int64(math.MaxUint32)+1)
|
||||||
SELECT 0 IN City FROM *`
|
t.Run(big, func(t *testing.T) {
|
||||||
_, err := Parse(q)
|
_, err := Parse(big)
|
||||||
require.True(t, errors.Is(err, ErrInvalidNumber), "got: %v", err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFilterStringSymbols(t *testing.T) {
|
func TestFilterStringSymbols(t *testing.T) {
|
||||||
q := `REP 1 IN S
|
q := `REP 1 IN S
|
||||||
|
|
Loading…
Add table
Reference in a new issue