0

I'm trying to design a simple query language as following

grammar FilterExpression;


// Lexer rules

AND : 'AND' ;
OR  : 'OR' ;
NOT : 'NOT';

GT : '>' ;
GE : '>=' ;
LT : '<' ;
LE : '<=' ;
EQ : '=' ;

DECIMAL    : '-'?[0-9]+('.'[0-9]+)? ;
KEY       : ~[ \t\r\n\\"~=<>:(),]+ ;
QUOTED_WORD: ["] ('\\"' | ~["])* ["] ;
NEWLINE    : '\r'? '\n';
WS         : [ \t\r\n]+ -> skip ;



StringFilter   : KEY ':' QUOTED_WORD;
NumericalFilter  : KEY (GT | GE | LT | LE | EQ) DECIMAL;

condition      : StringFilter                                # stringCondition
               | NumericalFilter                             # numericalCondition
               | StringFilter op=(AND|OR) StringFilter       # combinedStringCondition
               | NumericalFilter op=(AND|OR) NumericalFilter # combinedNumericalCondition
               | condition AND condition                     # combinedCondition
               | '(' condition ')'                           # parens
               ;

I added a few tests and would like to verify if they work as expected. To my surprise, some cases which should be clearly wrong passed

For instance when I type

(brand:"apple" AND t>3) 1>3

where the 1>3 is deliberately put as an error. However it seems Antlr is still happily generating a tree which looks like: enter image description here

Is it because my grammar has some problems I didn't realize?

I also tried in IntelliJ plugin (because I thought grun might not behaving as expected) but it give

Test code I'm using. Note I also tried to use BailErrorStrategy but these doesn't seem to help

public class ParserTest {
  private class BailLexer extends FilterExpressionLexer {
    public BailLexer(CharStream input) {
      super(input);
    }
    public void recover(LexerNoViableAltException e) {
      throw new RuntimeException(e);
    }
  }


  private FilterExpressionParser createParser(String filterString) {
    //FilterExpressionLexer lexer = new FilterExpressionLexer(CharStreams.fromString(filterString));
    FilterExpressionLexer lexer = new BailLexer(CharStreams.fromString(filterString));
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    FilterExpressionParser parser = new FilterExpressionParser(tokens);

    parser.setErrorHandler(new BailErrorStrategy());
    parser.addErrorListener(new ANTLRErrorListener() {
      @Override
      public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
        System.out.print("here1");
      }

      @Override
      public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
        System.out.print("here2");

      }

      @Override
      public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) {
        System.out.print("here3");

      }

      @Override
      public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction, ATNConfigSet configs) {

        System.out.print("here4");
      }
    });

    return parser;
  }

  @Test
  public void test() {
    FilterExpressionParser parser = createParser("(brand:\"apple\" AND t>3) 1>3");
    parser.condition();
  }

}
Eddie Xie
  • 875
  • 1
  • 8
  • 20

1 Answers1

1

Looks like I found the answer finally.

The reason is in the grammar I didn't provide an EOF. And obviously in ANTLR it's perfectly fine to parse the prefix os syntax. that's why the rest of the test string

(brand:"apple" AND t>3) 1>3 i.e. 1>3 is allowed.

See discussion here: https://github.com/antlr/antlr4/issues/351

Then I changed the grammar a little to add an EOF at the end of the syntax condition EOF everything works

Eddie Xie
  • 875
  • 1
  • 8
  • 20