[#3] policy: use ANTLRv4 parser generator

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
remotes/fyrchik/master
Evgenii Stratonikov 2021-05-21 18:12:32 +03:00
parent 86a9aa9259
commit 3aeeafe79e
21 changed files with 3586 additions and 241 deletions

4
.gitattributes vendored 100644
View File

@ -0,0 +1,4 @@
/pkg/policy/parser/*.go -diff
/pkg/policy/parser/generate.go diff
**/*.interp -diff
**/*.tokens -diff

2
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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.

View File

@ -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;

View File

@ -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)`
}

View 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;

View 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]

View 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

View 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 ;

File diff suppressed because one or more lines are too long

View 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

View File

@ -0,0 +1,3 @@
package parser
//go:generate antlr4 -Dlanguage=Go -visitor QueryLexer.g4 Query.g4

View 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) {}

View 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)
}

View 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
)

View 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)
}

File diff suppressed because it is too large Load Diff

View 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{}
}

View File

@ -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
}

View File

@ -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)
})
}