-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
1,572 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"[rust]": { | ||
"editor.defaultFormatter": "rust-lang.rust-analyzer" | ||
}, | ||
"rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu", | ||
"rust-analyzer.runnables.extraEnv": { | ||
"RUSTFLAGS": "-Awarnings" | ||
}, | ||
"rust-analyzer.cargo.extraEnv": { | ||
"RUSTFLAGS": "-Awarnings" | ||
}, | ||
"rust-analyzer.server.extraEnv": { | ||
"RUSTFLAGS": "-Awarnings" | ||
}, | ||
"rust-analyzer.check.extraEnv": { | ||
"RUSTFLAGS": "-Awarnings" | ||
}, | ||
"rust-analyzer.showUnlinkedFileNotification": false, | ||
"rust-analyzer.cargo.features": "all", | ||
"rust-analyzer.check.features": "all" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
use pest::error::InputLocation; | ||
use thiserror::Error; | ||
|
||
use crate::request::schema::ValueType; | ||
|
||
use super::parser::Rule; | ||
|
||
#[derive(Error, Debug, Clone, PartialEq, Eq)] | ||
pub enum FilterError { | ||
#[error("failed to parse filter from `{start}` to `{end}`")] | ||
Parse { start: usize, end: usize }, | ||
#[error("invalid filter value `{0}`")] | ||
InvalidNumber(String), | ||
#[error("expected filter type `{expected}`, but got `{actual}`")] | ||
InvalidType { | ||
expected: ValueType, | ||
actual: ValueType, | ||
}, | ||
#[error("incomparable filter type `{0}`")] | ||
IncomparableType(ValueType), | ||
#[error("expected a filter value")] | ||
ExpectedValue, | ||
} | ||
|
||
pub type FilterResult<T> = Result<T, FilterError>; | ||
|
||
impl From<pest::error::Error<Rule>> for FilterError { | ||
fn from(err: pest::error::Error<Rule>) -> Self { | ||
match err.location { | ||
InputLocation::Pos(pos) => FilterError::Parse { | ||
start: pos, | ||
end: pos, | ||
}, | ||
InputLocation::Span(span) => FilterError::Parse { | ||
start: span.0, | ||
end: span.1, | ||
}, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
WHITESPACE = _{ " " | "\t" | "\r" | "\n" } | ||
|
||
// Filter, possibly empty. | ||
filter = { | ||
SOI | ||
~ expression? | ||
~ EOI | ||
} | ||
|
||
// Expressions may either be a conjunction (AND) of sequences or a simple | ||
// sequence. | ||
// | ||
// Note, the AND is case-sensitive. | ||
// | ||
// Example: `a b AND c AND d` | ||
// | ||
// The expression `(a b) AND c AND d` is equivalent to the example. | ||
expression = { | ||
sequence ~ ("AND" ~ sequence)* | ||
} | ||
|
||
// Sequence is composed of one or more whitespace (WHITESPACE) separated factors. | ||
// | ||
// A sequence expresses a logical relationship between 'factors' where | ||
// the ranking of a filter result may be scored according to the number | ||
// factors that match and other such criteria as the proximity of factors | ||
// to each other within a document. | ||
// | ||
// When filters are used with exact match semantics rather than fuzzy | ||
// match semantics, a sequence is equivalent to AND. | ||
// | ||
// Example: `New York Giants OR Yankees` | ||
// | ||
// The expression `New York (Giants OR Yankees)` is equivalent to the | ||
// example. | ||
sequence = _{ | ||
factor ~ factor* | ||
} | ||
|
||
// Factors may either be a disjunction (OR) of terms or a simple term. | ||
// | ||
// Note, the OR is case-sensitive. | ||
// | ||
// Example: `a < 10 OR a >= 100` | ||
factor = { | ||
term ~ ("OR" ~ term)* | ||
} | ||
|
||
// Terms may either be unary or simple expressions. | ||
// | ||
// Unary expressions negate the simple expression, either mathematically `-` | ||
// or logically `NOT`. The negation styles may be used interchangeably. | ||
// | ||
// Note, the `NOT` is case-sensitive and must be followed by at least one | ||
// whitespace (WHITESPACE). | ||
// | ||
// Examples: | ||
// * logical not : `NOT (a OR b)` | ||
// * alternative not : `-file:".java"` | ||
// * negation : `-30` | ||
term = @{ | ||
("NOT" ~ WHITESPACE+)? ~ simple | ||
} | ||
|
||
// Simple expressions may either be a restriction or a nested (composite) | ||
// expression. | ||
simple = _{ | ||
restriction | composite | ||
} | ||
|
||
// Restrictions express a relationship between a comparable value and a | ||
// single argument. When the restriction only specifies a comparable | ||
// without an operator, this is a global restriction. | ||
// | ||
// Note, restrictions are not whitespace sensitive. | ||
// | ||
// Examples: | ||
// * equality : `package=com.google` | ||
// * inequality : `msg != 'hello'` | ||
// * greater than : `1 > 0` | ||
// * greater or equal : `2.5 >= 2.4` | ||
// * less than : `yesterday < request.time` | ||
// * less or equal : `experiment.rollout <= cohort(request.user)` | ||
// * has : `map:key` | ||
// * global : `prod` | ||
// | ||
// In addition to the global, equality, and ordering operators, filters | ||
// also support the has (`:`) operator. The has operator is unique in | ||
// that it can test for presence or value based on the proto3 type of | ||
// the `comparable` value. The has operator is useful for validating the | ||
// structure and contents of complex values. | ||
restriction = !{ | ||
comparable ~ (comparator ~ arg)? | ||
} | ||
|
||
// Comparable may either be a member, function or a value. | ||
comparable = { | ||
function | value | name | ||
} | ||
|
||
// Function calls may use simple or qualified names with zero or more | ||
// arguments. | ||
// | ||
// All functions declared within the list filter, apart from the special | ||
// `arguments` function must be provided by the host service. | ||
// | ||
// Examples: | ||
// * `regex(m.key, '^.*prod.*$')` | ||
// * `math.mem('30mb')` | ||
// | ||
// Antipattern: simple and qualified function names may include keywords: | ||
// NOT, AND, OR. It is not recommended that any of these names be used | ||
// within functions exposed by a service that supports list filters. | ||
function = { | ||
name ~ "(" ~ argList? ~ ")" | ||
} | ||
|
||
// Comparators supported by list filters. | ||
comparator = { | ||
"<=" | "<" | ">=" | ">" | "!=" | "=" | ":" | ||
} | ||
|
||
// Composite is a parenthesized expression, commonly used to group | ||
// terms or clarify operator precedence. | ||
// | ||
// Example: `(msg.endsWith('world') AND retries < 10)` | ||
composite = !{ | ||
"(" ~ expression ~ ")" | ||
} | ||
|
||
name = @{ | ||
identifier ~ ("." ~ identifier)* | ||
} | ||
|
||
identifier = ${ !keyword ~ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* } | ||
|
||
keyword = { "AND" | "OR" | "NOT" } | ||
|
||
argList = _{ | ||
arg ~ ("," ~ arg)* | ||
} | ||
|
||
arg = _{ | ||
comparable | composite | ||
} | ||
|
||
value = _{ string | boolean | number | any } | ||
|
||
string = ${ "\"" ~ inner ~ "\"" } | ||
inner = @{ char* } | ||
char = { | ||
!("\"" | "\\") ~ ANY | ||
| "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") | ||
| "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) | ||
} | ||
|
||
boolean = { "true" | "false" } | ||
|
||
number = @{ | ||
"-"? | ||
~ ("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) | ||
~ ("." ~ ASCII_DIGIT*)? | ||
~ (^"e" ~ ("+" | "-")? ~ ASCII_DIGIT+)? | ||
} | ||
|
||
any = { "*" } |
Oops, something went wrong.