Извините за название, это было лучшее, что я мог придумать, пытаясь быть точным ... Я пытаюсь разобрать Lucene-like (Упрощенно с упорядочением) ...
Последовательности, которые я попытка сопоставления может выглядеть так (каждая строка представляет собой отдельную последовательность, переданную сама по себе):
age: [5 TO 9] // fails: line 1:11 mismatched input '9' expecting WS
age: [5 TO *] // fails: line 1:11 mismatched input '*' expecting WS
age: [* TO 9] // success
age: [2345 TO 2110] // fails: line 1:14 mismatched input '2110' expecting WS
height: [1.6 TO 2.0] // success
height: [* TO 2.0] // success
height: [1.6 TO *] // success
born: [2020-03-02 TO 2020-03-25] // success
born: [2020-03-02T21:21:00 TO 2020-03-25T21:23:00] // success
born: [2020-03-02T21:24:00+01:00 TO 2020-03-25T21:24:00+01:00] // success
born: [* TO 2020-03-25T21:24:00+01:00] // success
born: [2020-03-02T21:24:00+01:00 TO *] // success
etc.
Если я заменю «TO» на «-», все те, которые потерпели неудачу, внезапно проходят.
age: [5 - 9] // success
age: [5 - *] // success
age: [* - 9] // success
age: [2345 - 2110] // success
Однако в данный момент нежелательно поддерживать этот синтаксис, я добавил его, чтобы посмотреть, оказал ли он влияние, и, к моему удивлению, это оказало ... Итак, в грамматике у меня есть WS ( TO | MINUS ) WS
прямо сейчас, которое должно быть просто WS TO WS
Проблемная область грамматики:
rangeClause :
fieldName = name
WS? COLON WS?
start = ( LSBR | LCBR ) WS?
from = simple_value
WS ( TO | MINUS ) WS
to = simple_value WS?
end =( RSBR | RCBR );
Очевидно, похоже, что у него возникают проблемы, как только он сталкивается "Integer" в начале предложения Range, когда используется TO, но я пока не могу понять, почему.
Полная грамматика: -target = JavaScript (я не проверял других на данный момент)
grammar SimplifiedWithOrdering;
/* Inspired by: https://github.com/lrowe/lucenequery */
/*
* Parser Rules
*/
query : WS? clause = defaultClause (WS order = orderingClause)? WS? EOF;
/*
This implements all clauses grouped into batches of the same type.
The order implements precedence (important).
*/
defaultClause : orClause (WS? orClause)*;
orClause : andClause (orOperator andClause)*;
andClause : notClause (andOperator notClause)*;
notClause : basicClause (notOperator basicClause)*;
basicClause :
WS? LPA defaultClause WS? RPA
| WS? atom
;
atom : value | field | rangeClause;
rangeClause :
fieldName = name
WS? COLON WS?
start = ( LSBR | LCBR ) WS?
from = simple_value
WS ( TO | MINUS ) WS
to = simple_value WS?
end =( RSBR | RCBR );
//Order
orderingClause : WS? ORDER WS BY WS orderingField ( WS? COMMA WS? orderingField )* WS?;
orderingField : WS? fieldName = name (WS direction = orderingDirection)?;
orderingDirection : (ASC | DESC);
field : fieldName = name WS? fieldOperator = operator WS? fieldValue = value;
name : TERM;
value : TERM #VTerm
| WILDCARD_TERM #VWildcard
| NUMBER #VNumber
| PHRASE #VPhrase
| STAR #VMatchAll
| DATE #VDate
| DATE_TIME #VDateTime
| DATE_OFFSET #VDateOffset
;
simple_value : TERM #STerm
| STAR #SMatchAll
| NUMBER #SNumber
| DATE #SDate
| DATE_TIME #SDateTime
| DATE_OFFSET #SDateOffset
;
andOperator : WS? AND;
orOperator : WS? OR;
notOperator : WS? (AND WS)? NOT;
operator : COLON #Equals
;
/*
* Lexer Rules
*/
LPA : '(';
RPA : ')';
LSBR : '[';
RSBR : ']';
LCBR : '{';
RCBR : '}';
STAR : '*';
QMARK : '?';
COMMA : ',';
PLUS : '+';
MINUS : '-';
DOT : '.';
COLON : ':';
AND : A N D ;
OR : O R ;
NOT : N O T ;
ORDER : O R D E R ;
BY : B Y ;
ASC : A S C ;
DESC : D E S C ;
TO : T O ;
WS : (' '|'\t'|'\r'|'\n'|'\u3000')+;
fragment INT : [0-9];
fragment ESC : '\\' .;
NUMBER : MINUS? INT+ ('.' INT+)?;
// Special Date Handling:
//updated > 2018-03-04T14:41:23+00:00
fragment TIMEOFFSET : ( MINUS | PLUS ) INT INT ( ':' INT INT );
TIME : INT INT ':' INT INT ( ':' INT INT )? TIMEOFFSET?;
DATE : INT INT INT INT MINUS INT INT MINUS INT INT;
DATE_TIME : DATE 'T' TIME;
// Special Timespan Handling:
fragment TIME_IDEN_CHAR : [a-zA-Z];
fragment NOW : N O W;
fragment TODAY : T O D A Y;
fragment SIMPLE_TIMESPAN : (INT+ '.')? INT INT ':' INT INT ( ':' INT INT ('.' INT INT))?;
fragment COMPLEX_TIMESPAN_PART : INT+ WS? TIME_IDEN_CHAR+;
fragment COMPLEX_TIMESPAN : (COMPLEX_TIMESPAN_PART WS?)+;
fragment TIME_SPAN : SIMPLE_TIMESPAN | COMPLEX_TIMESPAN;
DATE_OFFSET : (NOW | TODAY)? WS? (PLUS|MINUS)? WS? TIME_SPAN;
fragment TERM_CHAR : (~( ' ' | '\t' | '\n' | '\r' | '\u3000' | '\'' | '"'
| '(' | ')' | '[' | ']' | '{' | '}'
| '!' | ':' | '~' | '>' | '=' | '<'
| '?' | '*'
| '\\'| ',' )| ESC );
fragment WILDCARD_CHAR : (~( ' ' | '\t' | '\n' | '\r' | '\u3000' | '\'' | '"'
| '(' | ')' | '[' | ']' | '{' | '}'
| '!' | ':' | '~' | '>' | '=' | '<'
| '\\'| ',' )| ESC );
TERM : TERM_CHAR+ ;
WILDCARD_TERM : WILDCARD_CHAR+;
PHRASE : '"' ( ESC | ~('"'|'\\'))+ '"';
fragment A : [aA];
fragment B : [bB];
fragment C : [cC];
fragment D : [dD];
fragment E : [eE];
fragment F : [fF];
fragment G : [gG];
fragment H : [hH];
fragment I : [iI];
fragment J : [jJ];
fragment K : [kK];
fragment L : [lL];
fragment M : [mM];
fragment N : [nN];
fragment O : [oO];
fragment P : [pP];
fragment Q : [qQ];
fragment R : [rR];
fragment S : [sS];
fragment T : [tT];
fragment U : [uU];
fragment V : [vV];
fragment W : [wW];
fragment X : [xX];
fragment Y : [yY];
fragment Z : [zZ];