forked from TrueCloudLab/frostfs-sdk-go
[#3] policy: use ANTLRv4 parser generator
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
86a9aa9259
commit
3aeeafe79e
21 changed files with 3586 additions and 241 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
|
||||
|
||||
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/stretchr/testify v1.6.1
|
||||
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/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
|
||||
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-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-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
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/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/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=
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// 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:
|
||||
// 1. Grouping filter expressions in parenthesis is not supported right now.
|
||||
|
|
|
@ -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)`
|
||||
}
|
45
pkg/policy/parser/Query.g4
Normal file
45
pkg/policy/parser/Query.g4
Normal file
|
@ -0,0 +1,45 @@
|
|||
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
|
||||
| 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, 125, 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, 3, 7, 3, 7, 3, 7, 7, 7, 86, 10, 7, 12, 7, 14, 7, 89, 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, 102, 10, 9, 3, 10, 3, 10, 5, 10, 106, 10, 10, 3, 11, 3, 11, 3, 11, 5, 11, 111, 10, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 5, 14, 119, 10, 14, 3, 15, 3, 15, 5, 15, 123, 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, 126, 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, 76, 3, 2, 2, 2, 14, 90, 3, 2, 2, 2, 16, 101, 3, 2, 2, 2, 18, 105, 3, 2, 2, 2, 20, 110, 3, 2, 2, 2, 22, 112, 3, 2, 2, 2, 24, 114, 3, 2, 2, 2, 26, 118, 3, 2, 2, 2, 28, 122, 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, 5, 16, 9, 2, 78, 87, 3, 2, 2, 2, 79, 80, 12, 5, 2, 2, 80, 81, 7, 3, 2, 2, 81, 86, 5, 12, 7, 6, 82, 83, 12, 4, 2, 2, 83, 84, 7, 4, 2, 2, 84, 86, 5, 12, 7, 5, 85, 79, 3, 2, 2, 2, 85, 82, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 13, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 91, 7, 12, 2, 2, 91, 92, 5, 12, 7, 2, 92, 93, 7, 8, 2, 2, 93, 94, 5, 26, 14, 2, 94, 15, 3, 2, 2, 2, 95, 96, 7, 18, 2, 2, 96, 102, 5, 26, 14, 2, 97, 98, 5, 18, 10, 2, 98, 99, 7, 5, 2, 2, 99, 100, 5, 20, 11, 2, 100, 102, 3, 2, 2, 2, 101, 95, 3, 2, 2, 2, 101, 97, 3, 2, 2, 2, 102, 17, 3, 2, 2, 2, 103, 106, 5, 26, 14, 2, 104, 106, 7, 22, 2, 2, 105, 103, 3, 2, 2, 2, 105, 104, 3, 2, 2, 2, 106, 19, 3, 2, 2, 2, 107, 111, 5, 26, 14, 2, 108, 111, 5, 22, 12, 2, 109, 111, 7, 22, 2, 2, 110, 107, 3, 2, 2, 2, 110, 108, 3, 2, 2, 2, 110, 109, 3, 2, 2, 2, 111, 21, 3, 2, 2, 2, 112, 113, 9, 3, 2, 2, 113, 23, 3, 2, 2, 2, 114, 115, 9, 4, 2, 2, 115, 25, 3, 2, 2, 2, 116, 119, 5, 24, 13, 2, 117, 119, 7, 19, 2, 2, 118, 116, 3, 2, 2, 2, 118, 117, 3, 2, 2, 2, 119, 27, 3, 2, 2, 2, 120, 123, 5, 26, 14, 2, 121, 123, 7, 13, 2, 2, 122, 120, 3, 2, 2, 2, 122, 121, 3, 2, 2, 2, 123, 29, 3, 2, 2, 2, 17, 33, 36, 41, 47, 54, 63, 66, 72, 85, 87, 101, 105, 110, 118, 122]
|
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)
|
||||
}
|
2474
pkg/policy/parser/query_parser.go
Normal file
2474
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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pkg/policy/parser"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -19,83 +22,252 @@ var (
|
|||
ErrUnknownFilter = errors.New("policy: filter not found")
|
||||
// ErrUnknownSelector is returned when a value of IN is unknown.
|
||||
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) {
|
||||
q := new(query)
|
||||
err := parser.Parse(strings.NewReader(s), q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q, nil
|
||||
type policyVisitor struct {
|
||||
errors []error
|
||||
parser.BaseQueryVisitor
|
||||
antlr.DefaultErrorListener
|
||||
}
|
||||
|
||||
// Parse parses s into a placement policy.
|
||||
func Parse(s string) (*netmap.PlacementPolicy, error) {
|
||||
q, err := parse(s)
|
||||
if err != nil {
|
||||
return parse(s)
|
||||
}
|
||||
|
||||
func newPolicyVisitor() *policyVisitor {
|
||||
return &policyVisitor{}
|
||||
}
|
||||
|
||||
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 pl.(*netmap.PlacementPolicy), nil
|
||||
}
|
||||
|
||||
seenFilters := map[string]bool{}
|
||||
fs := make([]*netmap.Filter, 0, len(q.Filters))
|
||||
for _, qf := range q.Filters {
|
||||
f, err := filterFromOrChain(qf.Value, seenFilters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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
|
||||
}
|
||||
f.SetName(qf.Name)
|
||||
fs = append(fs, f)
|
||||
seenFilters[qf.Name] = true
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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{}
|
||||
ss := make([]*netmap.Selector, 0, len(q.Selectors))
|
||||
for _, qs := range q.Selectors {
|
||||
if qs.Filter != netmap.MainFilterName && !seenFilters[qs.Filter] {
|
||||
return nil, fmt.Errorf("%w: '%s'", ErrUnknownFilter, qs.Filter)
|
||||
for _, s := range p.Selectors() {
|
||||
if flt := s.Filter(); flt != netmap.MainFilterName && !seenFilters[flt] {
|
||||
return fmt.Errorf("%w: '%s'", ErrUnknownFilter, flt)
|
||||
}
|
||||
s := netmap.NewSelector()
|
||||
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)
|
||||
seenSelectors[s.Name()] = true
|
||||
}
|
||||
|
||||
rs := make([]*netmap.Replica, 0, len(q.Replicas))
|
||||
for _, qr := range q.Replicas {
|
||||
r := netmap.NewReplica()
|
||||
if qr.Selector != "" {
|
||||
if !seenSelectors[qr.Selector] {
|
||||
return nil, fmt.Errorf("%w: '%s'", ErrUnknownSelector, qr.Selector)
|
||||
}
|
||||
r.SetSelector(qr.Selector)
|
||||
for _, r := range p.Replicas() {
|
||||
if sel := r.Selector(); sel != "" && !seenSelectors[sel] {
|
||||
return fmt.Errorf("%w: '%s'", ErrUnknownSelector, sel)
|
||||
}
|
||||
if qr.Count == 0 {
|
||||
return nil, fmt.Errorf("%w: REP", ErrInvalidNumber)
|
||||
}
|
||||
r.SetCount(uint32(qr.Count))
|
||||
rs = append(rs, r)
|
||||
}
|
||||
|
||||
p := new(netmap.PlacementPolicy)
|
||||
p.SetFilters(fs...)
|
||||
p.SetSelectors(ss...)
|
||||
p.SetReplicas(rs...)
|
||||
p.SetContainerBackupFactor(q.CBF)
|
||||
|
||||
return p, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func clauseFromString(s string) netmap.Clause {
|
||||
|
@ -105,74 +277,31 @@ func clauseFromString(s string) netmap.Clause {
|
|||
case "DISTINCT":
|
||||
return netmap.ClauseDistinct
|
||||
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) {
|
||||
var fs []*netmap.Filter
|
||||
for _, ac := range expr.Clauses {
|
||||
f, err := filterFromAndChain(ac, seen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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 {
|
||||
func operationFromString(op string) netmap.Operation {
|
||||
switch strings.ToUpper(op) {
|
||||
case "AND":
|
||||
return netmap.OpAND
|
||||
case "OR":
|
||||
return netmap.OpOR
|
||||
case "EQ":
|
||||
f.SetOperation(netmap.OpEQ)
|
||||
return netmap.OpEQ
|
||||
case "NE":
|
||||
f.SetOperation(netmap.OpNE)
|
||||
return netmap.OpNE
|
||||
case "GE":
|
||||
f.SetOperation(netmap.OpGE)
|
||||
return netmap.OpGE
|
||||
case "GT":
|
||||
f.SetOperation(netmap.OpGT)
|
||||
return netmap.OpGT
|
||||
case "LE":
|
||||
f.SetOperation(netmap.OpLE)
|
||||
return netmap.OpLE
|
||||
case "LT":
|
||||
f.SetOperation(netmap.OpLT)
|
||||
return netmap.OpLT
|
||||
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,7 @@ package policy
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
||||
|
@ -80,6 +81,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) {
|
||||
q := `REP 4
|
||||
SELECT 3 IN Country FROM *
|
||||
|
@ -205,12 +232,12 @@ func TestValidation(t *testing.T) {
|
|||
SELECT 1 IN City FROM F
|
||||
FILTER Country KEK RU AS F`
|
||||
_, 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) {
|
||||
q := `REK 3`
|
||||
_, err := Parse(q)
|
||||
require.Error(t, err)
|
||||
require.True(t, errors.Is(err, ErrSyntaxError))
|
||||
})
|
||||
t.Run("InvalidFilterName", func(t *testing.T) {
|
||||
q := `REP 3
|
||||
|
@ -223,13 +250,13 @@ func TestValidation(t *testing.T) {
|
|||
t.Run("InvalidNumberInREP", func(t *testing.T) {
|
||||
q := `REP 0`
|
||||
_, err := Parse(q)
|
||||
require.True(t, errors.Is(err, ErrInvalidNumber), "got: %v", err)
|
||||
require.True(t, errors.Is(err, ErrSyntaxError), "got: %v", err)
|
||||
})
|
||||
t.Run("InvalidNumberInREP", func(t *testing.T) {
|
||||
q := `REP 1 IN Good
|
||||
SELECT 0 IN City FROM *`
|
||||
_, err := Parse(q)
|
||||
require.True(t, errors.Is(err, ErrInvalidNumber), "got: %v", err)
|
||||
require.True(t, errors.Is(err, ErrSyntaxError), "got: %v", err)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue