validate SemPredEvalParser tests

This commit is contained in:
ericvergnaud 2014-10-25 03:40:35 +08:00
parent 2716bbd62d
commit ba76b053a7
13 changed files with 134 additions and 738 deletions

View File

@ -224,36 +224,40 @@ public class Generator {
private TestFile buildSemPredEvalParser() throws Exception {
TestFile file = new TestFile("SemPredEvalParser");
file.addParserTest(input, "SimpleValidate", "T", "s",
TestMethod tm = file.addParserTest(input, "SimpleValidate", "T", "s",
"x",
"",
"line 1:0 no viable alternative at input 'x'\n");
file.addParserTest(input, "SimpleValidate2", "T", "s",
tm.debug = true;
tm = file.addParserTest(input, "SimpleValidate2", "T", "s",
"3 4 x",
"alt 2\n" + "alt 2\n",
"line 1:4 no viable alternative at input 'x'\n");
tm.debug = true;
file.addParserTest(input, "AtomWithClosureInTranslatedLRRule", "T", "start",
"a+b+a",
"",
null);
file.addParserTest(input, "ValidateInDFA", "T", "s",
tm = file.addParserTest(input, "ValidateInDFA", "T", "s",
"x ; y",
"",
"line 1:0 no viable alternative at input 'x'\n" +
"line 1:4 no viable alternative at input 'y'\n");
file.addParserTest(input, "Simple", "T", "s",
tm.debug = true;
tm = file.addParserTest(input, "Simple", "T", "s",
"x y 3",
"alt 2\n" + "alt 2\n" + "alt 3\n",
null);
// Under new predicate ordering rules (see antlr/antlr4#29), the first
// alt with an acceptable config (unpredicated, or predicated and evaluates
// to true) is chosen.
tm.debug = true;
file.addParserTest(input, "Order", "T", "s",
"x y",
"alt 1\n" + "alt 1\n",
null);
// We have n-2 predicates for n alternatives. pick first alt
file.addParserTest(input, "2UnpredicatedAlts", "T", "s",
tm = file.addParserTest(input, "2UnpredicatedAlts", "T", "s",
"x; y",
"alt 1\n" +
"alt 1\n",
@ -261,7 +265,8 @@ public class Generator {
"line 1:0 reportAmbiguity d=0 (a): ambigAlts={1, 2}, input='x'\n" +
"line 1:3 reportAttemptingFullContext d=0 (a), input='y'\n" +
"line 1:3 reportAmbiguity d=0 (a): ambigAlts={1, 2}, input='y'\n");
file.addParserTest(input, "2UnpredicatedAltsAndOneOrthogonalAlt", "T", "s",
tm.debug = true;
tm = file.addParserTest(input, "2UnpredicatedAltsAndOneOrthogonalAlt", "T", "s",
"34; x; y",
"alt 1\n" + "alt 2\n" + "alt 2\n",
"line 1:4 reportAttemptingFullContext d=0 (a), input='x'\n" +
@ -271,24 +276,28 @@ public class Generator {
// The parser consumes ID and moves to the 2nd token INT.
// To properly evaluate the predicates after matching ID INT,
// we must correctly see come back to starting index so LT(1) works
file.addParserTest(input, "RewindBeforePredEval", "T", "s",
tm.debug = true;
tm = file.addParserTest(input, "RewindBeforePredEval", "T", "s",
"y 3 x 4",
"alt 2\n" + "alt 1\n",
null);
// checks that we throw exception if all alts
// are covered with a predicate and none succeeds
tm.debug = true;
file.addParserTest(input, "NoTruePredsThrowsNoViableAlt", "T", "s",
"y 3 x 4",
"",
"line 1:0 no viable alternative at input 'y'\n");
file.addParserTest(input, "ToLeft", "T", "s",
tm = file.addParserTest(input, "ToLeft", "T", "s",
"x x y",
"alt 2\n" + "alt 2\n" + "alt 2\n",
null);
file.addParserTest(input, "UnpredicatedPathsInAlt", "T", "s",
tm.debug = true;
tm = file.addParserTest(input, "UnpredicatedPathsInAlt", "T", "s",
"x 4",
"alt 1\n",
null);
tm.debug = true;
file.addParserTest(input, "ActionHidesPreds", "T", "s",
"x x y",
"alt 1\n" + "alt 1\n" + "alt 1\n",
@ -298,20 +307,22 @@ public class Generator {
* the predicates assuming that all necessary information is available.
* The i++ action is done outside of the prediction and so it is executed.
*/
file.addParserTest(input, "ToLeftWithVaryingPredicate", "T", "s",
tm = file.addParserTest(input, "ToLeftWithVaryingPredicate", "T", "s",
"x x y",
"i=1\n" + "alt 2\n" + "i=2\n" + "alt 1\n" + "i=3\n" + "alt 2\n",
null);
tm.debug = true;
/**
* In this case, we're passing a parameter into a rule that uses that
* information to predict the alternatives. This is the special case
* where we know exactly which context we are in. The context stack
* is empty and we have not dipped into the outer context to make a decision.
*/
file.addParserTest(input, "PredicateDependentOnArg", "T", "s",
tm = file.addParserTest(input, "PredicateDependentOnArg", "T", "s",
"a b",
"alt 2\n" + "alt 1\n",
null);
tm.debug = true;
/** In this case, we have to ensure that the predicates are not
tested during the closure after recognizing the 1st ID. The
closure will fall off the end of 'a' 1st time and reach into the
@ -322,61 +333,70 @@ public class Generator {
simulation doesn't crash with context object issues when it
encounters preds during FOLLOW.
*/
file.addParserTest(input, "PredicateDependentOnArg2", "T", "s",
tm = file.addParserTest(input, "PredicateDependentOnArg2", "T", "s",
"a b",
"",
null);
// uses ID ';' or ID '.' lookahead to solve s. preds not tested.
file.addParserTest(input, "DependentPredNotInOuterCtxShouldBeIgnored", "T", "s",
tm.debug = true;
// uses ID ';' or ID '.' lookahead to solve s. preds not tested.
tm = file.addParserTest(input, "DependentPredNotInOuterCtxShouldBeIgnored", "T", "s",
"a;",
"alt 2\n",
null);
file.addParserTest(input, "IndependentPredNotPassedOuterCtxToAvoidCastException", "T", "s",
tm.debug = true;
tm = file.addParserTest(input, "IndependentPredNotPassedOuterCtxToAvoidCastException", "T", "s",
"a;",
"alt 2\n",
null);
/** During a global follow operation, we still collect semantic
tm.debug = true;
/** During a global follow operation, we still collect semantic
* predicates as long as they are not dependent on local context
*/
file.addParserTest(input, "PredsInGlobalFOLLOW", "T", "s",
tm = file.addParserTest(input, "PredsInGlobalFOLLOW", "T", "s",
"a!",
"eval=true\n" + /* now we are parsing */ "parse\n",
null);
/** We cannot collect predicates that are dependent on local context if
tm.debug = true;
/** We cannot collect predicates that are dependent on local context if
* we are doing a global follow. They appear as if they were not there at all.
*/
file.addParserTest(input, "DepedentPredsInGlobalFOLLOW","T", "s",
tm = file.addParserTest(input, "DepedentPredsInGlobalFOLLOW","T", "s",
"a!",
"eval=true\n" + "parse\n",
null);
/** Regular non-forced actions can create side effects used by semantic
tm.debug = true;
/** Regular non-forced actions can create side effects used by semantic
* predicates and so we cannot evaluate any semantic predicate
* encountered after having seen a regular action. This includes
* during global follow operations.
*/
file.addParserTest(input, "ActionsHidePredsInGlobalFOLLOW", "T", "s",
tm = file.addParserTest(input, "ActionsHidePredsInGlobalFOLLOW", "T", "s",
"a!",
"eval=true\n" + "parse\n",
null);
file.addParserTestsWithErrors(input, "PredTestedEvenWhenUnAmbig", "T", "primary",
tm.debug = true;
tm = file.addParserTestsWithErrors(input, "PredTestedEvenWhenUnAmbig", "T", "primary",
"abc", "ID abc\n", null,
"enum", "", "line 1:0 no viable alternative at input 'enum'\n");
tm.debug = true;
/**
* This is a regression test for antlr/antlr4#218 "ANTLR4 EOF Related Bug".
* https://github.com/antlr/antlr4/issues/218
*/
file.addParserTest(input, "DisabledAlternative", "T", "cppCompilationUnit",
tm = file.addParserTest(input, "DisabledAlternative", "T", "cppCompilationUnit",
"hello",
"",
null);
tm.debug = true;
/** Loopback doesn't eval predicate at start of alt */
file.addParserTestsWithErrors(input, "PredFromAltTestedInLoopBack", "T", "file_",
tm = file.addParserTestsWithErrors(input, "PredFromAltTestedInLoopBack", "T", "file_",
"s\n\n\nx\n",
"(file_ (para (paraContent s) \n \n) (para (paraContent \n x \n)) <EOF>)\n",
"(file_ (para (paraContent s) \\n \\n) (para (paraContent \\n x \\n)) <EOF>)\n",
"line 5:2 mismatched input '<EOF>' expecting '\n'\n",
"s\n\n\nx\n\n",
"(file_ (para (paraContent s) \n \n) (para (paraContent \n x) \n \n) <EOF>)\n",
"(file_ (para (paraContent s) \\n \\n) (para (paraContent \\n x) \\n \\n) <EOF>)\n",
null);
tm.debug = true;
return file;
}

View File

@ -3,7 +3,7 @@ s : {<LL_EXACT_AMBIG_DETECTION()>} a ';' a ';' a;
a : INT {<writeln("\"alt 1\"")>}
| ID {<writeln("\"alt 2\"")>} // must pick this one for ID since pred is false
| ID {<writeln("\"alt 3\"")>}
| {<false>}? ID {console.log(\"alt 4\");}
| {<false>}? ID {<writeln("\"alt 4\"")>}
;
ID : 'a'..'z'+ ;
INT : '0'..'9'+;

View File

@ -1,5 +1,5 @@
grammar <grammarName>;
@members {<InitMember("i","0")>}
@members {<InitIntMember("i","0")>}
s : a+ ;
a : {<SetMember("i","1")>} ID {<MemberEquals("i","1")>}? {<writeln("\"alt 1\"")>}
| {<SetMember("i","2")>} ID {<MemberEquals("i","2")>}? {<writeln("\"alt 2\"")>}

View File

@ -1,6 +1,5 @@
grammar <grammarName>;
@members {
this.p = function(v) {
<Declare_pred()>
}
s : e {} {<true:Invoke_pred()>}? {<writeln("\"parse\"")>} '!' ;

View File

@ -1,7 +1,7 @@
grammar <grammarName>;
s : b[2] ';' | b[2] '.' ; // decision in s drills down to ctx-dependent pred in a;
b[int i] : a[i] ;
a[int i]" +
a[int i]
: {<ValEquals("$i","1")>}? ID {<writeln("\"alt 1\"")>}
| {<ValEquals("$i","2")>}? ID {<writeln("\"alt 2\"")>}
;

View File

@ -1,5 +1,5 @@
grammar <grammarName>;
@members {<InitMember("enumKeyword",true)>}
@members {<InitBooleanMember("enumKeyword",true)>}
primary
: ID {<writeln("\"ID \"+$ID.text")>}
| {!<GetMember("enumKeyword")>}? 'enum' {<writeln("\"enum\"")>}

View File

@ -1,8 +1,8 @@
grammar <grammarName>;
@members {i=0}
@members {<InitIntMember("i","0")>}
s : a[2] a[1];
"a[int i]" +
" : {<ValEquals("$i","1")>}? ID {<writeln("\"alt 1\"")>}
a[int i]
: {<ValEquals("$i","1")>}? ID {<writeln("\"alt 1\"")>}
| {<ValEquals("$i","2")>}? ID {<writeln("\"alt 2\"")>}
;
ID : 'a'..'z'+ ;

View File

@ -1,9 +1,9 @@
grammar <grammarName>;
@members {i=0}
@members {<InitIntMember("i","0")>}
s : a[2] a[1];
a[int i]" +
: {<ValEquals("$i","1")>}? ID {<writeln("\"alt 1\"")>}
| {<ValEquals("$i","2")>}? ID {<writeln("\"alt 2\"")>}
a[int i]
: {<ValEquals("$i","1")>}? ID
| {<ValEquals("$i","2")>}? ID
;
ID : 'a'..'z'+ ;
INT : '0'..'9'+;

View File

@ -1,6 +1,7 @@
grammar <grammarName>;
@members {this.i=0}
s : ({<AddMember("i","1")>\n<PlusMember("\"i=\"","i"):writeln()>} a)+ ;
@members {<InitIntMember("i","0")>}
s : ({<AddMember("i","1")>
<PlusMember("\"i=\"","i"):writeln()>} a)+ ;
a : {<ModMemberEquals("i","2","0")>}? ID {<writeln("\"alt 1\"")>}
| {<ModMemberNotEquals("i","2","0")>}? ID {<writeln("\"alt 2\"")>}
;

View File

@ -109,7 +109,9 @@ DeclareLocal(s,v) ::= "Object <s> = <v>;"
AssignLocal(s,v) ::= "<s> = <v>;"
InitMember(n,v) ::= <%this.<n> = <v>;%>
InitIntMember(n,v) ::= <%int <n> = <v>;%>
InitBooleanMember(n,v) ::= <%boolean <n> = <v>;%>
GetMember(n) ::= <%this.<n>%>
@ -119,11 +121,11 @@ AddMember(n,v) ::= <%this.<n> += <v>;%>
PlusMember(v,n) ::= <%<v> + this.<n>%>
MemberEquals(n,v) ::= <%this.<n> === <v>%>
MemberEquals(n,v) ::= <%this.<n> == <v>%>
ModMemberEquals(n,m,v) ::= <%this.<n> % m === <v>%>
ModMemberEquals(n,m,v) ::= <%this.<n> % <m> == <v>%>
ModMemberNotEquals(n,m,v) ::= <%this.<n> % m != <v>%>
ModMemberNotEquals(n,m,v) ::= <%this.<n> % <m> != <v>%>
DumpDFA() ::= "this.dumpDFA();"
@ -141,7 +143,7 @@ Column() ::= "this.getCharPositionInLine()"
Text() ::= "this.getText()"
ValEquals(a,b) ::= <%<a>===<b>%>
ValEquals(a,b) ::= <%<a>==<b>%>
TextEquals(a) ::= <%this.getText().equals("<a>")%>
@ -149,7 +151,7 @@ PlusText(a) ::= <%"<a>" + this.getText()%>
InputText() ::= "this._input.getText()"
LTEquals(i, v) ::= <%this._input.LT(<i>).text===<v>%>
LTEquals(i, v) ::= <%this._input.LT(<i>).getText().equals(<v>)%>
LANotEquals(i, v) ::= <%this._input.LA(<i>)!=<v>%>
@ -161,7 +163,7 @@ GetExpectedTokenNames() ::= "this.getExpectedTokens().toString(this.tokenNames)"
WriteRuleInvocationStack() ::= "System.out.println(getRuleInvocationStack());"
LL_EXACT_AMBIG_DETECTION() ::= <<this._interp.predictionMode = antlr4.atn.PredictionMode.LL_EXACT_AMBIG_DETECTION;>>
LL_EXACT_AMBIG_DETECTION() ::= <<_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);>>
PositionAdjustingLexer() ::= <<
@ -320,10 +322,10 @@ Declare_foo() ::= <<public void foo() {System.out.println("foo");}>>
Invoke_foo() ::= "this.foo();"
Declare_pred() ::= <<this.pred = function(v) {
document.getElementById('output').value += 'eval=" + v.toString() + '\\n';
Declare_pred() ::= <<boolean pred(boolean v) {
System.out.println("eval="+v);
return v;
};
}
>>
Invoke_pred(v) ::= <<this.pred(<v>)>>

View File

@ -79,7 +79,7 @@ public class TestFullContextParsing extends BaseTest {
String testFullContextIF_THEN_ELSEParse(String input) throws Exception {
String grammar = "grammar T;\n" +
"s \n" +
"@init {this._interp.predictionMode = antlr4.atn.PredictionMode.LL_EXACT_AMBIG_DETECTION;}\n" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
"@after {this.dumpDFA();}\n" +
" : '{' stat* '}' ;\n" +
"stat: 'if' ID 'then' stat ('else' ID)?\n" +
@ -136,7 +136,7 @@ public class TestFullContextParsing extends BaseTest {
public void testLoopsSimulateTailRecursion() throws Exception {
String grammar = "grammar T;\n" +
"prog\n" +
"@init {this._interp.predictionMode = antlr4.atn.PredictionMode.LL_EXACT_AMBIG_DETECTION;}\n" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
" : expr_or_assign*;\n" +
"expr_or_assign\n" +
" : expr '++' {System.out.println(\"fail.\");}\n" +
@ -158,7 +158,7 @@ public class TestFullContextParsing extends BaseTest {
public void testAmbiguityNoLoop() throws Exception {
String grammar = "grammar T;\n" +
"prog\n" +
"@init {this._interp.predictionMode = antlr4.atn.PredictionMode.LL_EXACT_AMBIG_DETECTION;}\n" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
" : expr expr {System.out.println(\"alt 1\");}\n" +
" | expr\n" +
" ;\n" +
@ -176,7 +176,7 @@ public class TestFullContextParsing extends BaseTest {
String testExprAmbiguity(String input) throws Exception {
String grammar = "grammar T;\n" +
"s\n" +
"@init {this._interp.predictionMode = antlr4.atn.PredictionMode.LL_EXACT_AMBIG_DETECTION;}\n" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
": expr[0] {System.out.println($expr.ctx.toStringTree(this));};\n" +
" expr[int _p]\n" +
" : ID \n" +

View File

@ -15,7 +15,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x", true);
assertEquals("", found);
assertEquals("line 1:0 no viable alternative at input 'x'\n", this.stderrDuringParse);
}
@ -30,7 +30,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "3 4 x", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "3 4 x", true);
assertEquals("alt 2\nalt 2\n", found);
assertEquals("line 1:4 no viable alternative at input 'x'\n", this.stderrDuringParse);
}
@ -60,7 +60,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x ; y", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x ; y", true);
assertEquals("", found);
assertEquals("line 1:0 no viable alternative at input 'x'\nline 1:4 no viable alternative at input 'y'\n", this.stderrDuringParse);
}
@ -76,7 +76,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x y 3", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x y 3", true);
assertEquals("alt 2\nalt 2\nalt 3\n", found);
assertNull(this.stderrDuringParse);
}
@ -101,7 +101,7 @@ public class TestSemPredEvalParser extends BaseTest {
@Test
public void test2UnpredicatedAlts() throws Exception {
String grammar = "grammar T;\n" +
"s : {this._interp.predictionMode = antlr4.atn.PredictionMode.LL_EXACT_AMBIG_DETECTION;} a ';' a; // do 2x: once in ATN, next in DFA\n" +
"s : {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);} a ';' a; // do 2x: once in ATN, next in DFA\n" +
"a : ID {System.out.println(\"alt 1\");}\n" +
" | ID {System.out.println(\"alt 2\");}\n" +
" | {false}? ID {System.out.println(\"alt 3\");}\n" +
@ -109,7 +109,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x; y", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x; y", true);
assertEquals("alt 1\nalt 1\n", found);
assertEquals("line 1:0 reportAttemptingFullContext d=0 (a), input='x'\nline 1:0 reportAmbiguity d=0 (a): ambigAlts={1, 2}, input='x'\nline 1:3 reportAttemptingFullContext d=0 (a), input='y'\nline 1:3 reportAmbiguity d=0 (a): ambigAlts={1, 2}, input='y'\n", this.stderrDuringParse);
}
@ -117,16 +117,16 @@ public class TestSemPredEvalParser extends BaseTest {
@Test
public void test2UnpredicatedAltsAndOneOrthogonalAlt() throws Exception {
String grammar = "grammar T;\n" +
"s : {this._interp.predictionMode = antlr4.atn.PredictionMode.LL_EXACT_AMBIG_DETECTION;} a ';' a ';' a;\n" +
"s : {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);} a ';' a ';' a;\n" +
"a : INT {System.out.println(\"alt 1\");}\n" +
" | ID {System.out.println(\"alt 2\");} // must pick this one for ID since pred is false\n" +
" | ID {System.out.println(\"alt 3\");}\n" +
" | {false}? ID {console.log(\\\"alt 4\\\");}\n" +
" | {false}? ID {System.out.println(\"alt 4\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "34; x; y", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "34; x; y", true);
assertEquals("alt 1\nalt 2\nalt 2\n", found);
assertEquals("line 1:4 reportAttemptingFullContext d=0 (a), input='x'\nline 1:4 reportAmbiguity d=0 (a): ambigAlts={2, 3}, input='x'\nline 1:7 reportAttemptingFullContext d=0 (a), input='y'\nline 1:7 reportAmbiguity d=0 (a): ambigAlts={2, 3}, input='y'\n", this.stderrDuringParse);
}
@ -135,13 +135,13 @@ public class TestSemPredEvalParser extends BaseTest {
public void testRewindBeforePredEval() throws Exception {
String grammar = "grammar T;\n" +
"s : a a;\n" +
"a : {this._input.LT(1).text===\"x\"}? ID INT {System.out.println(\"alt 1\");}\n" +
" | {this._input.LT(1).text===\"y\"}? ID INT {System.out.println(\"alt 2\");}\n" +
"a : {this._input.LT(1).getText().equals(\"x\")}? ID INT {System.out.println(\"alt 1\");}\n" +
" | {this._input.LT(1).getText().equals(\"y\")}? ID INT {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "y 3 x 4", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "y 3 x 4", true);
assertEquals("alt 2\nalt 1\n", found);
assertNull(this.stderrDuringParse);
}
@ -171,7 +171,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x x y", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x x y", true);
assertEquals("alt 2\nalt 2\nalt 2\n", found);
assertNull(this.stderrDuringParse);
}
@ -190,7 +190,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x 4", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x 4", true);
assertEquals("alt 1\n", found);
assertNull(this.stderrDuringParse);
}
@ -198,10 +198,10 @@ public class TestSemPredEvalParser extends BaseTest {
@Test
public void testActionHidesPreds() throws Exception {
String grammar = "grammar T;\n" +
"@members {this.i = 0;}\n" +
"@members {int i = 0;}\n" +
"s : a+ ;\n" +
"a : {this.i = 1;} ID {this.i === 1}? {System.out.println(\"alt 1\");}\n" +
" | {this.i = 2;} ID {this.i === 2}? {System.out.println(\"alt 2\");}\n" +
"a : {this.i = 1;} ID {this.i == 1}? {System.out.println(\"alt 1\");}\n" +
" | {this.i = 2;} ID {this.i == 2}? {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
@ -214,15 +214,16 @@ public class TestSemPredEvalParser extends BaseTest {
@Test
public void testToLeftWithVaryingPredicate() throws Exception {
String grammar = "grammar T;\n" +
"@members {this.i=0}\n" +
"s : ({this.i += 1;\\nSystem.out.println(\"i=\" + this.i);} a)+ ;\n" +
"a : {this.i % m === 0}? ID {System.out.println(\"alt 1\");}\n" +
" | {this.i % m != 0}? ID {System.out.println(\"alt 2\");}\n" +
"@members {int i = 0;}\n" +
"s : ({this.i += 1;\n" +
" System.out.println(\"i=\" + this.i);} a)+ ;\n" +
"a : {this.i % 2 == 0}? ID {System.out.println(\"alt 1\");}\n" +
" | {this.i % 2 != 0}? ID {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x x y", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x x y", true);
assertEquals("i=1\nalt 2\ni=2\nalt 1\ni=3\nalt 2\n", found);
assertNull(this.stderrDuringParse);
}
@ -230,16 +231,16 @@ public class TestSemPredEvalParser extends BaseTest {
@Test
public void testPredicateDependentOnArg() throws Exception {
String grammar = "grammar T;\n" +
"@members {i=0}\n" +
"@members {int i = 0;}\n" +
"s : a[2] a[1];\n" +
"\"a[int i]\" +\n" +
"\" : {$i===1}? ID {System.out.println(\"alt 1\");}\n" +
" | {$i===2}? ID {System.out.println(\"alt 2\");}\n" +
"a[int i]\n" +
" : {$i==1}? ID {System.out.println(\"alt 1\");}\n" +
" | {$i==2}? ID {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a b", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a b", true);
assertEquals("alt 2\nalt 1\n", found);
assertNull(this.stderrDuringParse);
}
@ -247,16 +248,16 @@ public class TestSemPredEvalParser extends BaseTest {
@Test
public void testPredicateDependentOnArg2() throws Exception {
String grammar = "grammar T;\n" +
"@members {i=0}\n" +
"@members {int i = 0;}\n" +
"s : a[2] a[1];\n" +
"a[int i]\" +\n" +
" : {$i===1}? ID {System.out.println(\"alt 1\");}\n" +
" | {$i===2}? ID {System.out.println(\"alt 2\");}\n" +
"a[int i]\n" +
" : {$i==1}? ID \n" +
" | {$i==2}? ID \n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a b", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a b", true);
assertEquals("", found);
assertNull(this.stderrDuringParse);
}
@ -266,14 +267,14 @@ public class TestSemPredEvalParser extends BaseTest {
String grammar = "grammar T;\n" +
"s : b[2] ';' | b[2] '.' ; // decision in s drills down to ctx-dependent pred in a;\n" +
"b[int i] : a[i] ;\n" +
"a[int i]\" +\n" +
" : {$i===1}? ID {System.out.println(\"alt 1\");}\n" +
" | {$i===2}? ID {System.out.println(\"alt 2\");}\n" +
"a[int i]\n" +
" : {$i==1}? ID {System.out.println(\"alt 1\");}\n" +
" | {$i==2}? ID {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a;", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a;", true);
assertEquals("alt 2\n", found);
assertNull(this.stderrDuringParse);
}
@ -290,7 +291,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a;", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a;", true);
assertEquals("alt 2\n", found);
assertNull(this.stderrDuringParse);
}
@ -299,10 +300,10 @@ public class TestSemPredEvalParser extends BaseTest {
public void testPredsInGlobalFOLLOW() throws Exception {
String grammar = "grammar T;\n" +
"@members {\n" +
"this.pred = function(v) {\n" +
" document.getElementById('output').value += 'eval=\" + v.toString() + '\\n';\n" +
"boolean pred(boolean v) {\n" +
" System.out.println(\"eval=\"+v);\n" +
" return v;\n" +
"};\n" +
"}\n" +
"}\n" +
"s : e {this.pred(true)}? {System.out.println(\"parse\");} '!' ;\n" +
"t : e {this.pred(false)}? ID ;\n" +
@ -310,7 +311,7 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a!", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a!", true);
assertEquals("eval=true\nparse\n", found);
assertNull(this.stderrDuringParse);
}
@ -319,19 +320,19 @@ public class TestSemPredEvalParser extends BaseTest {
public void testDepedentPredsInGlobalFOLLOW() throws Exception {
String grammar = "grammar T;\n" +
"@members {\n" +
"this.pred = function(v) {\n" +
" document.getElementById('output').value += 'eval=\" + v.toString() + '\\n';\n" +
"boolean pred(boolean v) {\n" +
" System.out.println(\"eval=\"+v);\n" +
" return v;\n" +
"};\n" +
"}\n" +
"}\n" +
"s : a[99] ;\n" +
"a[int i] : e {this.pred($i===99)}? {System.out.println(\"parse\");} '!' ;\n" +
"b[int i] : e {this.pred($i===99)}? ID ;\n" +
"a[int i] : e {this.pred($i==99)}? {System.out.println(\"parse\");} '!' ;\n" +
"b[int i] : e {this.pred($i==99)}? ID ;\n" +
"e : ID | ; // non-LL(1) so we use ATN\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a!", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a!", true);
assertEquals("eval=true\nparse\n", found);
assertNull(this.stderrDuringParse);
}
@ -340,11 +341,10 @@ public class TestSemPredEvalParser extends BaseTest {
public void testActionsHidePredsInGlobalFOLLOW() throws Exception {
String grammar = "grammar T;\n" +
"@members {\n" +
"this.p = function(v) {\n" +
"this.pred = function(v) {\n" +
" document.getElementById('output').value += 'eval=\" + v.toString() + '\\n';\n" +
"boolean pred(boolean v) {\n" +
" System.out.println(\"eval=\"+v);\n" +
" return v;\n" +
"};\n" +
"}\n" +
"}\n" +
"s : e {} {this.pred(true)}? {System.out.println(\"parse\");} '!' ;\n" +
"t : e {} {this.pred(false)}? ID ;\n" +
@ -352,21 +352,21 @@ public class TestSemPredEvalParser extends BaseTest {
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a!", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a!", true);
assertEquals("eval=true\nparse\n", found);
assertNull(this.stderrDuringParse);
}
String testPredTestedEvenWhenUnAmbig(String input) throws Exception {
String grammar = "grammar T;\n" +
"@members {this.enumKeyword = true;}\n" +
"@members {boolean enumKeyword = true;}\n" +
"primary\n" +
" : ID {System.out.println(\"ID \"+$ID.text);}\n" +
" | {!this.enumKeyword}? 'enum' {System.out.println(\"enum\");}\n" +
" ;\n" +
"ID : [a-z]+ ;\n" +
"WS : [ \\t\\n\\r]+ -> skip ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "primary", input, false);
return execParser("T.g4", grammar, "TParser", "TLexer", "primary", input, true);
}
@Test
@ -390,7 +390,7 @@ public class TestSemPredEvalParser extends BaseTest {
"content: anything | {false}? .;\n" +
"anything: ANY_CHAR;\n" +
"ANY_CHAR: [_a-zA-Z0-9];";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "cppCompilationUnit", "hello", false);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "cppCompilationUnit", "hello", true);
assertEquals("", found);
assertNull(this.stderrDuringParse);
}
@ -405,20 +405,20 @@ public class TestSemPredEvalParser extends BaseTest {
"NL : '\\n' ;\n" +
"s : 's' ;\n" +
"X : 'x' ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "file_", input, false);
return execParser("T.g4", grammar, "TParser", "TLexer", "file_", input, true);
}
@Test
public void testPredFromAltTestedInLoopBack_1() throws Exception {
String found = testPredFromAltTestedInLoopBack("s\n\n\nx\n");
assertEquals("(file_ (para (paraContent s) \n \n) (para (paraContent \n x \n)) <EOF>)\n", found);
assertEquals("(file_ (para (paraContent s) \\n \\n) (para (paraContent \\n x \\n)) <EOF>)\n", found);
assertEquals("line 5:2 mismatched input '<EOF>' expecting '\n'\n", this.stderrDuringParse);
}
@Test
public void testPredFromAltTestedInLoopBack_2() throws Exception {
String found = testPredFromAltTestedInLoopBack("s\n\n\nx\n\n");
assertEquals("(file_ (para (paraContent s) \n \n) (para (paraContent \n x) \n \n) <EOF>)\n", found);
assertEquals("(file_ (para (paraContent s) \\n \\n) (para (paraContent \\n x) \\n \\n) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}

View File

@ -1,626 +0,0 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Terence Parr
* Copyright (c) 2012 Sam Harwell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.test.tool;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class TestSemPredEvalParser extends BaseTest {
// TEST VALIDATING PREDS
@Test public void testSimpleValidate() throws Exception {
String grammar =
"grammar T;\n" +
"s : a ;\n" +
"a : {false}? ID {System.out.println(\"alt 1\");}\n" +
" | {true}? INT {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
/*String found = */execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x", false);
String expecting = "line 1:0 no viable alternative at input 'x'\n";
assertEquals(expecting, stderrDuringParse);
}
@Test public void testSimpleValidate2() throws Exception {
String grammar =
"grammar T;\n" +
"s : a a a;\n" +
"a : {false}? ID {System.out.println(\"alt 1\");}\n" +
" | {true}? INT {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"3 4 x", false);
String expecting =
"alt 2\n" +
"alt 2\n";
assertEquals(expecting, found);
expecting = "line 1:4 no viable alternative at input 'x'\n";
assertEquals(expecting, stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#196
* "element+ in expression grammar doesn't parse properly"
* https://github.com/antlr/antlr4/issues/196
*/
@Test public void testAtomWithClosureInTranslatedLRRule() throws Exception {
String grammar =
"grammar T;\n" +
"start : e[0] EOF;\n" +
"e[int _p]\n" +
" : ( 'a'\n" +
" | 'b'+\n" +
" )\n" +
" ( {3 >= $_p}? '+' e[4]\n" +
" )*\n" +
" ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "start",
"a+b+a", false);
String expecting = "";
assertEquals(expecting, found);
assertNull(stderrDuringParse);
}
@Test public void testValidateInDFA() throws Exception {
String grammar =
"grammar T;\n" +
"s : a ';' a;\n" +
// ';' helps us to resynchronize without consuming
// 2nd 'a' reference. We our testing that the DFA also
// throws an exception if the validating predicate fails
"a : {false}? ID {System.out.println(\"alt 1\");}\n" +
" | {true}? INT {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x ; y", false);
String expecting = "";
assertEquals(expecting, found);
expecting =
"line 1:0 no viable alternative at input 'x'\n" +
"line 1:4 no viable alternative at input 'y'\n";
assertEquals(expecting, stderrDuringParse);
}
// TEST DISAMBIG PREDS
@Test public void testSimple() throws Exception {
String grammar =
"grammar T;\n" +
"s : a a a;\n" + // do 3x: once in ATN, next in DFA then INT in ATN
"a : {false}? ID {System.out.println(\"alt 1\");}\n" +
" | {true}? ID {System.out.println(\"alt 2\");}\n" +
" | INT {System.out.println(\"alt 3\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x y 3", false);
String expecting =
"alt 2\n" +
"alt 2\n" +
"alt 3\n";
assertEquals(expecting, found);
}
@Test public void testOrder() throws Exception {
// Under new predicate ordering rules (see antlr/antlr4#29), the first
// alt with an acceptable config (unpredicated, or predicated and evaluates
// to true) is chosen.
String grammar =
"grammar T;\n" +
"s : a {} a;\n" + // do 2x: once in ATN, next in DFA;
// action blocks lookahead from falling off of 'a'
// and looking into 2nd 'a' ref. !ctx dependent pred
"a : ID {System.out.println(\"alt 1\");}\n" +
" | {true}? ID {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x y", false);
String expecting =
"alt 1\n" +
"alt 1\n";
assertEquals(expecting, found);
}
@Test public void test2UnpredicatedAlts() throws Exception {
// We have n-2 predicates for n alternatives. pick first alt
String grammar =
"grammar T;\n" +
"@header {" +
"import java.util.*;" +
"}" +
"s : {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
" a ';' a;\n" + // do 2x: once in ATN, next in DFA
"a : ID {System.out.println(\"alt 1\");}\n" +
" | ID {System.out.println(\"alt 2\");}\n" +
" | {false}? ID {System.out.println(\"alt 3\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x; y", true);
String expecting =
"alt 1\n" +
"alt 1\n";
assertEquals(expecting, found);
assertEquals("line 1:0 reportAttemptingFullContext d=0 (a), input='x'\n" +
"line 1:0 reportAmbiguity d=0 (a): ambigAlts={1, 2}, input='x'\n" +
"line 1:3 reportAttemptingFullContext d=0 (a), input='y'\n" +
"line 1:3 reportAmbiguity d=0 (a): ambigAlts={1, 2}, input='y'\n",
this.stderrDuringParse);
}
@Test public void test2UnpredicatedAltsAndOneOrthogonalAlt() throws Exception {
String grammar =
"grammar T;\n" +
"@header {" +
"import java.util.*;" +
"}" +
"s : {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
" a ';' a ';' a;\n" +
"a : INT {System.out.println(\"alt 1\");}\n" +
" | ID {System.out.println(\"alt 2\");}\n" + // must pick this one for ID since pred is false
" | ID {System.out.println(\"alt 3\");}\n" +
" | {false}? ID {System.out.println(\"alt 4\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"34; x; y", true);
String expecting =
"alt 1\n" +
"alt 2\n" +
"alt 2\n";
assertEquals(expecting, found);
assertEquals("line 1:4 reportAttemptingFullContext d=0 (a), input='x'\n" +
"line 1:4 reportAmbiguity d=0 (a): ambigAlts={2, 3}, input='x'\n" +
"line 1:7 reportAttemptingFullContext d=0 (a), input='y'\n" +
"line 1:7 reportAmbiguity d=0 (a): ambigAlts={2, 3}, input='y'\n",
this.stderrDuringParse);
}
@Test public void testRewindBeforePredEval() throws Exception {
// The parser consumes ID and moves to the 2nd token INT.
// To properly evaluate the predicates after matching ID INT,
// we must correctly see come back to starting index so LT(1) works
String grammar =
"grammar T;\n" +
"s : a a;\n" +
"a : {_input.LT(1).getText().equals(\"x\")}? ID INT {System.out.println(\"alt 1\");}\n" +
" | {_input.LT(1).getText().equals(\"y\")}? ID INT {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"y 3 x 4", false);
String expecting =
"alt 2\n" +
"alt 1\n";
assertEquals(expecting, found);
}
@Test public void testNoTruePredsThrowsNoViableAlt() throws Exception {
// checks that we throw exception if all alts
// are covered with a predicate and none succeeds
String grammar =
"grammar T;\n" +
"s : a a;\n" +
"a : {false}? ID INT {System.out.println(\"alt 1\");}\n" +
" | {false}? ID INT {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
execParser("T.g4", grammar, "TParser", "TLexer", "s",
"y 3 x 4", false);
String expecting = "line 1:0 no viable alternative at input 'y'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testToLeft() throws Exception {
String grammar =
"grammar T;\n" +
"s : a+ ;\n" +
"a : {false}? ID {System.out.println(\"alt 1\");}\n" +
" | {true}? ID {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"alt 2\n" +
"alt 2\n" +
"alt 2\n";
assertEquals(expecting, found);
}
@Test
public void testUnpredicatedPathsInAlt() throws Exception{
String grammar =
"grammar T;\n" +
"s : a {System.out.println(\"alt 1\");}\n" +
" | b {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"a : {false}? ID INT\n" +
" | ID INT\n" +
" ;\n" +
"b : ID ID\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x 4", false);
String expecting =
"alt 1\n";
assertEquals(expecting, found);
expecting = null;
assertEquals(expecting, stderrDuringParse);
}
@Test public void testActionHidesPreds() throws Exception {
// can't see preds, resolves to first alt found (1 in this case)
String grammar =
"grammar T;\n" +
"@parser::members {int i;}\n" +
"s : a+ ;\n" +
"a : {i=1;} ID {i==1}? {System.out.println(\"alt 1\");}\n" +
" | {i=2;} ID {i==2}? {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"alt 1\n" +
"alt 1\n" +
"alt 1\n";
assertEquals(expecting, found);
}
/** In this case, we use predicates that depend on global information
* like we would do for a symbol table. We simply execute
* the predicates assuming that all necessary information is available.
* The i++ action is done outside of the prediction and so it is executed.
*/
@Test public void testToLeftWithVaryingPredicate() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {int i=0;}\n" +
"s : ({i++; System.out.println(\"i=\"+i);} a)+ ;\n" +
"a : {i % 2 == 0}? ID {System.out.println(\"alt 1\");}\n" +
" | {i % 2 != 0}? ID {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"i=1\n" +
"alt 2\n" +
"i=2\n" +
"alt 1\n" +
"i=3\n" +
"alt 2\n";
assertEquals(expecting, found);
}
/**
* In this case, we're passing a parameter into a rule that uses that
* information to predict the alternatives. This is the special case
* where we know exactly which context we are in. The context stack
* is empty and we have not dipped into the outer context to make a decision.
*/
@Test public void testPredicateDependentOnArg() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {int i=0;}\n" +
"s : a[2] a[1];\n" +
"a[int i]" +
" : {$i==1}? ID {System.out.println(\"alt 1\");}\n" +
" | {$i==2}? ID {System.out.println(\"alt 2\");}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"a b", false);
String expecting =
"alt 2\n" +
"alt 1\n";
assertEquals(expecting, found);
}
/** In this case, we have to ensure that the predicates are not
tested during the closure after recognizing the 1st ID. The
closure will fall off the end of 'a' 1st time and reach into the
a[1] rule invocation. It should not execute predicates because it
does not know what the parameter is. The context stack will not
be empty and so they should be ignored. It will not affect
recognition, however. We are really making sure the ATN
simulation doesn't crash with context object issues when it
encounters preds during FOLLOW.
*/
@Test public void testPredicateDependentOnArg2() throws Exception {
String grammar =
"grammar T;\n" +
"s : a[2] a[1];\n" +
"a[int i]" +
" : {$i==1}? ID\n" +
" | {$i==2}? ID\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"a b", false);
String expecting =
"";
assertEquals(expecting, found);
}
@Test public void testDependentPredNotInOuterCtxShouldBeIgnored() throws Exception {
// uses ID ';' or ID '.' lookahead to solve s. preds not tested.
String grammar =
"grammar T;\n" +
"s : b[2] ';' | b[2] '.' ;\n" + // decision in s drills down to ctx-dependent pred in a;
"b[int i] : a[i] ;\n" +
"a[int i]" +
" : {$i==1}? ID {System.out.println(\"alt 1\");}\n" +
" | {$i==2}? ID {System.out.println(\"alt 2\");}\n" +
" ;" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"a;", false);
String expecting =
"alt 2\n";
assertEquals(expecting, found);
}
@Test public void testIndependentPredNotPassedOuterCtxToAvoidCastException() throws Exception {
String grammar =
"grammar T;\n" +
"s : b ';' | b '.' ;\n" +
"b : a ;\n" +
"a" +
" : {false}? ID {System.out.println(\"alt 1\");}\n" +
" | {true}? ID {System.out.println(\"alt 2\");}\n" +
" ;" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"a;", false);
String expecting =
"alt 2\n";
assertEquals(expecting, found);
}
/** During a global follow operation, we still collect semantic
* predicates as long as they are not dependent on local context
*/
@Test public void testPredsInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {" +
"void f(Object s) {System.out.println(s);}\n" +
"boolean p(boolean v) {System.out.println(\"eval=\"+v); return v;}\n" +
"}\n" +
"s : e {p(true)}? {f(\"parse\");} '!' ;\n" +
"t : e {p(false)}? ID ;\n" +
"e : ID | ;\n" + // non-LL(1) so we use ATN
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"a!", false);
String expecting =
"eval=true\n" + // now we are parsing
"parse\n";
assertEquals(expecting, found);
}
/** We cannot collect predicates that are dependent on local context if
* we are doing a global follow. They appear as if they were not there at all.
*/
@Test public void testDepedentPredsInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {" +
"void f(Object s) {System.out.println(s);}\n" +
"boolean p(boolean v) {System.out.println(\"eval=\"+v); return v;}\n" +
"}\n" +
"s : a[99] ;\n" +
"a[int i] : e {p($i==99)}? {f(\"parse\");} '!' ;\n" +
"b[int i] : e {p($i==99)}? ID ;\n" +
"e : ID | ;\n" + // non-LL(1) so we use ATN
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"a!", false);
String expecting =
"eval=true\n" +
"parse\n";
assertEquals(expecting, found);
}
/** Regular non-forced actions can create side effects used by semantic
* predicates and so we cannot evaluate any semantic predicate
* encountered after having seen a regular action. This includes
* during global follow operations.
*/
@Test public void testActionsHidePredsInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {" +
"void f(Object s) {System.out.println(s);}\n" +
"boolean p(boolean v) {System.out.println(\"eval=\"+v); return v;}\n" +
"}\n" +
"s : e {} {p(true)}? {f(\"parse\");} '!' ;\n" +
"t : e {} {p(false)}? ID ;\n" +
"e : ID | ;\n" + // non-LL(1) so we use ATN
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"a!", false);
String expecting =
"eval=true\n" +
"parse\n";
assertEquals(expecting, found);
}
@Test public void testPredTestedEvenWhenUnAmbig() throws Exception {
String grammar =
"grammar T;\n" +
"\n" +
"@parser::members {boolean enumKeyword = true;}\n" +
"\n" +
"primary\n" +
" : ID {System.out.println(\"ID \"+$ID.text);}\n" +
" | {!enumKeyword}? 'enum' {System.out.println(\"enum\");}\n" +
" ;\n" +
"\n" +
"ID : [a-z]+ ;\n" +
"\n" +
"WS : [ \\t\\n\\r]+ -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "primary",
"abc", false);
assertEquals("ID abc\n", found);
execParser("T.g4", grammar, "TParser", "TLexer", "primary",
"enum", false);
assertEquals("line 1:0 no viable alternative at input 'enum'\n", stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#218 "ANTLR4 EOF Related Bug".
* https://github.com/antlr/antlr4/issues/218
*/
@Test public void testDisabledAlternative() {
String grammar =
"grammar AnnotProcessor;\n" +
"\n" +
"cppCompilationUnit : content+ EOF;\n" +
"\n" +
"content: anything | {false}? .;\n" +
"\n" +
"anything: ANY_CHAR;\n" +
"\n" +
"ANY_CHAR: [_a-zA-Z0-9];\n";
String input = "hello";
String found = execParser("AnnotProcessor.g4", grammar, "AnnotProcessorParser", "AnnotProcessorLexer", "cppCompilationUnit",
input, false);
assertEquals("", found);
assertNull(stderrDuringParse);
}
/** Loopback doesn't eval predicate at start of alt */
@Test public void testPredFromAltTestedInLoopBack() {
String grammar =
"grammar T2;\n" +
"\n" +
"file\n" +
"@after {System.out.println($ctx.toStringTree(this));}\n" +
" : para para EOF ;" +
"para: paraContent NL NL ;\n"+
"paraContent : ('s'|'x'|{_input.LA(2)!=NL}? NL)+ ;\n"+
"NL : '\\n' ;\n"+
"S : 's' ;\n"+
"X : 'x' ;\n";
String input = "s\n\n\nx\n";
String found = execParser("T2.g4", grammar, "T2Parser", "T2Lexer", "file",
input, true);
assertEquals("(file (para (paraContent s) \\n \\n) (para (paraContent \\n x \\n)) <EOF>)\n", found);
assertEquals(stderrDuringParse, "line 5:2 mismatched input '<EOF>' expecting '\n'\n");
input = "s\n\n\nx\n\n";
found = execParser("T2.g4", grammar, "T2Parser", "T2Lexer", "file",
input, true);
assertEquals("(file (para (paraContent s) \\n \\n) (para (paraContent \\n x) \\n \\n) <EOF>)\n", found);
assertNull(stderrDuringParse);
}
}