|
|
@ -15,16 +15,17 @@ internal static class FilterGrammar
|
|
|
|
from close in Character.EqualTo(open)
|
|
|
|
from close in Character.EqualTo(open)
|
|
|
|
select value;
|
|
|
|
select value;
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<char> FreeCharacter =
|
|
|
|
private static readonly TextParser<string> UnquotedString =
|
|
|
|
Character.Matching(c =>
|
|
|
|
Parse.OneOf(
|
|
|
|
|
|
|
|
EscapedCharacter,
|
|
|
|
|
|
|
|
Character.Matching(
|
|
|
|
|
|
|
|
c =>
|
|
|
|
!char.IsWhiteSpace(c) &&
|
|
|
|
!char.IsWhiteSpace(c) &&
|
|
|
|
// Avoid all special tokens used by the grammar
|
|
|
|
// Avoid all special tokens used by the grammar
|
|
|
|
c is not ('(' or ')' or '"' or '\'' or '-' or '|' or '&'),
|
|
|
|
c is not ('(' or ')' or '"' or '\'' or '-' or '~' or '|' or '&'),
|
|
|
|
"any character except whitespace or `(`, `)`, `\"`, `'`, `-`, `|`, `&`"
|
|
|
|
"any character except whitespace or `(`, `)`, `\"`, `'`, `-`, `|`, `&`"
|
|
|
|
);
|
|
|
|
)
|
|
|
|
|
|
|
|
).AtLeastOnce().Text();
|
|
|
|
private static readonly TextParser<string> UnquotedString =
|
|
|
|
|
|
|
|
Parse.OneOf(EscapedCharacter, FreeCharacter).AtLeastOnce().Text();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<string> String =
|
|
|
|
private static readonly TextParser<string> String =
|
|
|
|
Parse.OneOf(QuotedString, UnquotedString).Named("text string");
|
|
|
|
Parse.OneOf(QuotedString, UnquotedString).Named("text string");
|
|
|
@ -64,19 +65,7 @@ internal static class FilterGrammar
|
|
|
|
.Select(k => (MessageFilter) new HasMessageFilter(k))
|
|
|
|
.Select(k => (MessageFilter) new HasMessageFilter(k))
|
|
|
|
.Named("has:<value>");
|
|
|
|
.Named("has:<value>");
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<MessageFilter> NegatedFilter = Character
|
|
|
|
private static readonly TextParser<MessageFilter> PrimitiveFilter = Parse.OneOf(
|
|
|
|
.EqualTo('-')
|
|
|
|
|
|
|
|
.IgnoreThen(Parse.Ref(() => StandaloneFilter!))
|
|
|
|
|
|
|
|
.Select(f => (MessageFilter) new NegatedMessageFilter(f));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<MessageFilter> GroupedFilter =
|
|
|
|
|
|
|
|
from open in Character.EqualTo('(')
|
|
|
|
|
|
|
|
from content in Parse.Ref(() => BinaryExpressionFilter!).Token()
|
|
|
|
|
|
|
|
from close in Character.EqualTo(')')
|
|
|
|
|
|
|
|
select content;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<MessageFilter> StandaloneFilter = Parse.OneOf(
|
|
|
|
|
|
|
|
GroupedFilter,
|
|
|
|
|
|
|
|
FromFilter,
|
|
|
|
FromFilter,
|
|
|
|
MentionsFilter,
|
|
|
|
MentionsFilter,
|
|
|
|
ReactionFilter,
|
|
|
|
ReactionFilter,
|
|
|
@ -84,19 +73,33 @@ internal static class FilterGrammar
|
|
|
|
ContainsFilter
|
|
|
|
ContainsFilter
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<MessageFilter> UnaryExpressionFilter = Parse.OneOf(
|
|
|
|
private static readonly TextParser<MessageFilter> GroupedFilter =
|
|
|
|
NegatedFilter,
|
|
|
|
from open in Character.EqualTo('(')
|
|
|
|
StandaloneFilter
|
|
|
|
from content in Parse.Ref(() => ChainedFilter!).Token()
|
|
|
|
);
|
|
|
|
from close in Character.EqualTo(')')
|
|
|
|
|
|
|
|
select content;
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<MessageFilter> BinaryExpressionFilter = Parse.Chain(
|
|
|
|
private static readonly TextParser<MessageFilter> NegatedFilter = Character
|
|
|
|
|
|
|
|
// Dash is annoying to use from CLI due to conflicts with options, so we provide tilde as an alias
|
|
|
|
|
|
|
|
.In('-', '~')
|
|
|
|
|
|
|
|
.IgnoreThen(Parse.OneOf(GroupedFilter, PrimitiveFilter))
|
|
|
|
|
|
|
|
.Select(f => (MessageFilter) new NegatedMessageFilter(f));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly TextParser<MessageFilter> ChainedFilter = Parse.Chain(
|
|
|
|
|
|
|
|
// Operator
|
|
|
|
Parse.OneOf(
|
|
|
|
Parse.OneOf(
|
|
|
|
// Explicit operator
|
|
|
|
// Explicit operator
|
|
|
|
Character.In('|', '&').Token().Try(),
|
|
|
|
Character.In('|', '&').Token().Try(),
|
|
|
|
// Implicit operator (resolves to 'and')
|
|
|
|
// Implicit operator (resolves to 'and')
|
|
|
|
Character.WhiteSpace.AtLeastOnce().IgnoreThen(Parse.Return(' '))
|
|
|
|
Character.WhiteSpace.AtLeastOnce().IgnoreThen(Parse.Return(' '))
|
|
|
|
),
|
|
|
|
),
|
|
|
|
UnaryExpressionFilter,
|
|
|
|
// Operand
|
|
|
|
|
|
|
|
Parse.OneOf(
|
|
|
|
|
|
|
|
NegatedFilter,
|
|
|
|
|
|
|
|
GroupedFilter,
|
|
|
|
|
|
|
|
PrimitiveFilter
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
// Reducer
|
|
|
|
(op, left, right) => op switch
|
|
|
|
(op, left, right) => op switch
|
|
|
|
{
|
|
|
|
{
|
|
|
|
'|' => new BinaryExpressionMessageFilter(left, right, BinaryExpressionKind.Or),
|
|
|
|
'|' => new BinaryExpressionMessageFilter(left, right, BinaryExpressionKind.Or),
|
|
|
@ -105,5 +108,5 @@ internal static class FilterGrammar
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly TextParser<MessageFilter> Filter =
|
|
|
|
public static readonly TextParser<MessageFilter> Filter =
|
|
|
|
BinaryExpressionFilter.Token().AtEnd();
|
|
|
|
ChainedFilter.Token().AtEnd();
|
|
|
|
}
|
|
|
|
}
|