1 /* 2 * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. 3 * Use of this file is governed by the BSD 3-clause license that 4 * can be found in the LICENSE.txt file in the project root. 5 */ 6 7 package org.antlr.v4.test.tool; 8 9 import org.antlr.v4.tool.ErrorType; 10 import org.junit.Before; 11 import org.junit.Test; 12 13 /** */ 14 public class TestLeftRecursionToolIssues extends BaseJavaToolTest { 15 protected boolean debug = false; 16 17 @Before 18 @Override testSetUp()19 public void testSetUp() throws Exception { 20 super.testSetUp(); 21 } 22 testCheckForNonLeftRecursiveRule()23 @Test public void testCheckForNonLeftRecursiveRule() throws Exception { 24 String grammar = 25 "grammar T;\n" + 26 "s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" + 27 "a : a ID\n" + 28 " ;\n" + 29 "ID : 'a'..'z'+ ;\n" + 30 "WS : (' '|'\\n') -> skip ;\n"; 31 String expected = 32 "error(" + ErrorType.NO_NON_LR_ALTS.code + "): T.g4:3:0: left recursive rule a must contain an alternative which is not left recursive\n"; 33 testErrors(new String[] { grammar, expected }, false); 34 } 35 testCheckForLeftRecursiveEmptyFollow()36 @Test public void testCheckForLeftRecursiveEmptyFollow() throws Exception { 37 String grammar = 38 "grammar T;\n" + 39 "s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" + 40 "a : a ID?\n" + 41 " | ID\n" + 42 " ;\n" + 43 "ID : 'a'..'z'+ ;\n" + 44 "WS : (' '|'\\n') -> skip ;\n"; 45 String expected = 46 "error(" + ErrorType.EPSILON_LR_FOLLOW.code + "): T.g4:3:0: left recursive rule a contains a left recursive alternative which can be followed by the empty string\n"; 47 testErrors(new String[] { grammar, expected }, false); 48 } 49 50 /** Reproduces https://github.com/antlr/antlr4/issues/855 */ testLeftRecursiveRuleRefWithArg()51 @Test public void testLeftRecursiveRuleRefWithArg() throws Exception { 52 String grammar = 53 "grammar T;\n" + 54 "statement\n" + 55 "locals[Scope scope]\n" + 56 " : expressionA[$scope] ';'\n" + 57 " ;\n" + 58 "expressionA[Scope scope]\n" + 59 " : atom[$scope]\n" + 60 " | expressionA[$scope] '[' expressionA[$scope] ']'\n" + 61 " ;\n" + 62 "atom[Scope scope]\n" + 63 " : 'dummy'\n" + 64 " ;\n"; 65 String expected = 66 "error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:6:0: rule expressionA is left recursive but doesn't conform to a pattern ANTLR can handle\n"; 67 testErrors(new String[]{grammar, expected}, false); 68 } 69 70 /** Reproduces https://github.com/antlr/antlr4/issues/855 */ testLeftRecursiveRuleRefWithArg2()71 @Test public void testLeftRecursiveRuleRefWithArg2() throws Exception { 72 String grammar = 73 "grammar T;\n" + 74 "a[int i] : 'x'\n" + 75 " | a[3] 'y'\n" + 76 " ;"; 77 String expected = 78 "error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:2:0: rule a is left recursive but doesn't conform to a pattern ANTLR can handle\n"; 79 testErrors(new String[]{grammar, expected}, false); 80 } 81 82 /** Reproduces https://github.com/antlr/antlr4/issues/855 */ testLeftRecursiveRuleRefWithArg3()83 @Test public void testLeftRecursiveRuleRefWithArg3() throws Exception { 84 String grammar = 85 "grammar T;\n" + 86 "a : 'x'\n" + 87 " | a[3] 'y'\n" + 88 " ;"; 89 String expected = 90 "error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:2:0: rule a is left recursive but doesn't conform to a pattern ANTLR can handle\n"; 91 testErrors(new String[]{grammar, expected}, false); 92 } 93 94 /** Reproduces https://github.com/antlr/antlr4/issues/822 */ testIsolatedLeftRecursiveRuleRef()95 @Test public void testIsolatedLeftRecursiveRuleRef() throws Exception { 96 String grammar = 97 "grammar T;\n" + 98 "a : a | b ;\n" + 99 "b : 'B' ;\n"; 100 String expected = 101 "error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:2:0: rule a is left recursive but doesn't conform to a pattern ANTLR can handle\n"; 102 testErrors(new String[]{grammar, expected}, false); 103 } 104 105 /** Reproduces https://github.com/antlr/antlr4/issues/773 */ testArgOnPrimaryRuleInLeftRecursiveRule()106 @Test public void testArgOnPrimaryRuleInLeftRecursiveRule() throws Exception { 107 String grammar = 108 "grammar T;\n" + 109 "val: dval[1]\n" + 110 " | val '*' val\n" + 111 " ;\n" + 112 "dval[int x]: '.';\n"; 113 String expected = ""; // dval[1] should not be error 114 testErrors(new String[]{grammar, expected}, false); 115 } 116 } 117