validated LeftRecursion tests

This commit is contained in:
ericvergnaud 2014-10-25 02:21:41 +08:00
parent 31812721c8
commit 740c30d21d
15 changed files with 510 additions and 798 deletions

View File

@ -747,61 +747,61 @@ public class Generator {
file.addParserTest(input, "SemPred", "T", "s", "x y z",
"(s (a (a (a x) y) z))\n", null);
file.addParserTests(input, "TernaryExpr", "T", "s",
"a", "(s (e a) <EOF>)",
"a+b", "(s (e (e a) + (e b)) <EOF>)",
"a*b", "(s (e (e a) * (e b)) <EOF>)",
"a?b:c", "(s (e (e a) ? (e b) : (e c)) <EOF>)",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)",
"a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)",
"a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)",
"a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)",
"a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)");
"a", "(s (e a) <EOF>)\n",
"a+b", "(s (e (e a) + (e b)) <EOF>)\n",
"a*b", "(s (e (e a) * (e b)) <EOF>)\n",
"a?b:c", "(s (e (e a) ? (e b) : (e c)) <EOF>)\n",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)\n",
"a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)\n",
"a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)\n",
"a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)\n",
"a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)\n");
file.addParserTests(input, "Expressions", "T", "s",
"a", "(s (e a) <EOF>)",
"1", "(s (e 1) <EOF>)",
"a-1", "(s (e (e a) - (e 1)) <EOF>)",
"a.b", "(s (e (e a) . b) <EOF>)",
"a.this", "(s (e (e a) . this) <EOF>)",
"-a", "(s (e - (e a)) <EOF>)",
"-a+b", "(s (e (e - (e a)) + (e b)) <EOF>)");
"a", "(s (e a) <EOF>)\n",
"1", "(s (e 1) <EOF>)\n",
"a-1", "(s (e (e a) - (e 1)) <EOF>)\n",
"a.b", "(s (e (e a) . b) <EOF>)\n",
"a.this", "(s (e (e a) . this) <EOF>)\n",
"-a", "(s (e - (e a)) <EOF>)\n",
"-a+b", "(s (e (e - (e a)) + (e b)) <EOF>)\n");
file.addParserTests(input, "JavaExpressions", "T", "s",
"a|b&c", "(s (e (e a) | (e (e b) & (e c))) <EOF>)",
"(a|b)&c", "(s (e (e ( (e (e a) | (e b)) )) & (e c)) <EOF>)",
"a > b", "(s (e (e a) > (e b)) <EOF>)",
"a >> b", "(s (e (e a) >> (e b)) <EOF>)",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)",
"a^b^c", "(s (e (e a) ^ (e (e b) ^ (e c))) <EOF>)",
"(T)x", "(s (e ( (type T) ) (e x)) <EOF>)",
"new A().b", "(s (e (e new (type A) ( )) . b) <EOF>)",
"(T)t.f()", "(s (e (e ( (type T) ) (e (e t) . f)) ( )) <EOF>)",
"a.f(x)==T.c", "(s (e (e (e (e a) . f) ( (expressionList (e x)) )) == (e (e T) . c)) <EOF>)",
"a.f().g(x,1)", "(s (e (e (e (e (e a) . f) ( )) . g) ( (expressionList (e x) , (e 1)) )) <EOF>)",
"new T[((n-1) * x) + 1]", "(s (e new (type T) [ (e (e ( (e (e ( (e (e n) - (e 1)) )) * (e x)) )) + (e 1)) ]) <EOF>)");
"a|b&c", "(s (e (e a) | (e (e b) & (e c))) <EOF>)\n",
"(a|b)&c", "(s (e (e ( (e (e a) | (e b)) )) & (e c)) <EOF>)\n",
"a > b", "(s (e (e a) > (e b)) <EOF>)\n",
"a >> b", "(s (e (e a) >> (e b)) <EOF>)\n",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)\n",
"a^b^c", "(s (e (e a) ^ (e (e b) ^ (e c))) <EOF>)\n",
"(T)x", "(s (e ( (type T) ) (e x)) <EOF>)\n",
"new A().b", "(s (e (e new (type A) ( )) . b) <EOF>)\n",
"(T)t.f()", "(s (e (e ( (type T) ) (e (e t) . f)) ( )) <EOF>)\n",
"a.f(x)==T.c", "(s (e (e (e (e a) . f) ( (expressionList (e x)) )) == (e (e T) . c)) <EOF>)\n",
"a.f().g(x,1)", "(s (e (e (e (e (e a) . f) ( )) . g) ( (expressionList (e x) , (e 1)) )) <EOF>)\n",
"new T[((n-1) * x) + 1]", "(s (e new (type T) [ (e (e ( (e (e ( (e (e n) - (e 1)) )) * (e x)) )) + (e 1)) ]) <EOF>)\n");
file.addParserTests(input, "Declarations", "T", "s",
"a", "(s (declarator a) <EOF>)",
"*a", "(s (declarator * (declarator a)) <EOF>)",
"**a", "(s (declarator * (declarator * (declarator a))) <EOF>)",
"a[3]", "(s (declarator (declarator a) [ (e 3) ]) <EOF>)",
"b[]", "(s (declarator (declarator b) [ ]) <EOF>)",
"(a)", "(s (declarator ( (declarator a) )) <EOF>)",
"a[]()", "(s (declarator (declarator (declarator a) [ ]) ( )) <EOF>)",
"a[][]", "(s (declarator (declarator (declarator a) [ ]) [ ]) <EOF>)",
"*a[]", "(s (declarator * (declarator (declarator a) [ ])) <EOF>)",
"(*a)[]", "(s (declarator (declarator ( (declarator * (declarator a)) )) [ ]) <EOF>)");
"a", "(s (declarator a) <EOF>)\n",
"*a", "(s (declarator * (declarator a)) <EOF>)\n",
"**a", "(s (declarator * (declarator * (declarator a))) <EOF>)\n",
"a[3]", "(s (declarator (declarator a) [ (e 3) ]) <EOF>)\n",
"b[]", "(s (declarator (declarator b) [ ]) <EOF>)\n",
"(a)", "(s (declarator ( (declarator a) )) <EOF>)\n",
"a[]()", "(s (declarator (declarator (declarator a) [ ]) ( )) <EOF>)\n",
"a[][]", "(s (declarator (declarator (declarator a) [ ]) [ ]) <EOF>)\n",
"*a[]", "(s (declarator * (declarator (declarator a) [ ])) <EOF>)\n",
"(*a)[]", "(s (declarator (declarator ( (declarator * (declarator a)) )) [ ]) <EOF>)\n");
file.addParserTests(input, "ReturnValueAndActions", "T", "s",
"4", "4",
"1+2", "3",
"1+2*3", "7",
"(1+2)*3", "9");
"4", "4\n",
"1+2", "3\n",
"1+2*3", "7\n",
"(1+2)*3", "9\n");
file.addParserTests(input, "LabelsOnOpSubrule", "T", "s",
"4", "(s (e 4))",
"1*2/3", "(s (e (e (e 1) * (e 2)) / (e 3)))",
"(1/2)*3", "(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))");
"4", "(s (e 4))\n",
"1*2/3", "(s (e (e (e 1) * (e 2)) / (e 3)))\n",
"(1/2)*3", "(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))\n");
file.addParserTests(input, "ReturnValueAndActionsAndLabels", "T", "s",
"4", "4",
"1+2", "3",
"1+2*3", "7",
"i++*3", "12");
"4", "4\n",
"1+2", "3\n",
"1+2*3", "7\n",
"i++*3", "12\n");
/**
* This is a regression test for antlr/antlr4#433 "Not all context accessor
* methods are generated when an alternative rule label is used for multiple
@ -809,14 +809,14 @@ public class Generator {
* https://github.com/antlr/antlr4/issues/433
*/
file.addParserTests(input, "MultipleAlternativesWithCommonLabel", "T", "s",
"4", "4",
"1+2", "3",
"1+2*3", "7",
"i++*3", "12");
"4", "4\n",
"1+2", "3\n",
"1+2*3", "7\n",
"i++*3", "12\n");
file.addParserTests(input, "PrefixOpWithActionAndLabel", "T", "s",
"a", "a",
"a+b", "(a+b)",
"a=b+c", "((a=b)+c)");
"a", "a\n",
"a+b", "(a+b)\n",
"a=b+c", "((a=b)+c)\n");
file.addParserTests(input, "AmbigLR", "Expr", "prog",
"1\n", "",
"a = 5\n", "",
@ -839,6 +839,69 @@ public class Generator {
file.addParserTest(input, "PrecedenceFilterConsidersContext", "T", "prog",
"aa",
"(prog (statement (letterA a)) (statement (letterA a)) <EOF>)\n", null);
/**
* This is a regression test for antlr/antlr4#625 "Duplicate action breaks
* operator precedence"
* https://github.com/antlr/antlr4/issues/625
*/
file.addParserTests(input, "MultipleActions", "T", "s",
"4", "(s (e 4))\n",
"1*2/3", "(s (e (e (e 1) * (e 2)) / (e 3)))\n",
"(1/2)*3", "(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))\n");
/**
* This is a regression test for antlr/antlr4#625 "Duplicate action breaks
* operator precedence"
* https://github.com/antlr/antlr4/issues/625
*/
file.addParserTests(input, "MultipleActionsPredicatesOptions", "T", "s",
"4", "(s (e 4))\n",
"1*2/3", "(s (e (e (e 1) * (e 2)) / (e 3)))\n",
"(1/2)*3", "(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))\n");
file.addParserTest(input, "SemPredFailOption", "T", "s",
"x y z",
"(s (a (a x) y z))\n",
"line 1:4 rule a custom message\n");
/**
* This is a regression test for antlr/antlr4#542 "First alternative cannot
* be right-associative".
* https://github.com/antlr/antlr4/issues/542
*/
file.addParserTests(input, "TernaryExprExplicitAssociativity", "T", "s",
"a", "(s (e a) <EOF>)\n",
"a+b", "(s (e (e a) + (e b)) <EOF>)\n",
"a*b", "(s (e (e a) * (e b)) <EOF>)\n",
"a?b:c", "(s (e (e a) ? (e b) : (e c)) <EOF>)\n",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)\n",
"a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)\n",
"a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)\n",
"a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)\n",
"a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)\n");
/**
* This is a regression test for antlr/antlr4#677 "labels not working in
* grammar file".
* https://github.com/antlr/antlr4/issues/677
*
* <p>This test treats {@code ,} and {@code >>} as part of a single compound
* operator (similar to a ternary operator).</p>
*/
file.addParserTests(input, "ReturnValueAndActionsList1", "T", "s",
"a*b", "(s (expr (expr a) * (expr b)) <EOF>)\n",
"a,c>>x", "(s (expr (expr a) , (expr c) >> (expr x)) <EOF>)\n",
"x", "(s (expr x) <EOF>)\n",
"a*b,c,x*y>>r", "(s (expr (expr (expr a) * (expr b)) , (expr c) , (expr (expr x) * (expr y)) >> (expr r)) <EOF>)\n");
/**
* This is a regression test for antlr/antlr4#677 "labels not working in
* grammar file".
* https://github.com/antlr/antlr4/issues/677
*
* <p>This test treats the {@code ,} and {@code >>} operators separately.</p>
*/
file.addParserTests(input, "ReturnValueAndActionsList2", "T", "s",
"a*b", "(s (expr (expr a) * (expr b)) <EOF>)\n",
"a,c>>x", "(s (expr (expr (expr a) , (expr c)) >> (expr x)) <EOF>)\n",
"x", "(s (expr x) <EOF>)\n",
"a*b,c,x*y>>r", "(s (expr (expr (expr (expr (expr a) * (expr b)) , (expr c)) , (expr (expr x) * (expr y))) >> (expr r)) <EOF>)\n");
return file;
}

View File

@ -0,0 +1,8 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : e ;
e : a=e op=('*'|'/') b=e {}{}
| INT {}{}
| '(' x=e ')' {}{}
;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,9 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : e ;
e : a=e op=('*'|'/') b=e {}{true}?
| a=e op=('+'|'-') b=e {}\<p=3>{true}?\<fail='Message'>
| INT {}{}
| '(' x=e ')' {}{}
;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -1,13 +1,13 @@
grammar <grammarName>;
s : e {<writeln("$e.v")>};
e returns [int v]
: e '*' e {$v = $ctx.e(0).v * $ctx.e(1).v;} # binary
| e '+' e {$v = $ctx.e(0).v + $ctx.e(1).v;} # binary
: e '*' e {$v = <Cast("BinaryContext","$ctx")>.e(0).v * <Cast("BinaryContext","$ctx")>.e(1).v;} # binary
| e '+' e {$v = <Cast("BinaryContext","$ctx")>.e(0).v + <Cast("BinaryContext","$ctx")>.e(1).v;} # binary
| INT {$v = $INT.int;} # anInt
| '(' e ')' {$v = $e.v;} # parens
| left=e INC {<assert("$ctx.INC() !== null")>;$v = $left.v + 1;} # unary
| left=e DEC {<assert("$ctx.DEC() !== null")>;$v = $left.v - 1;} # unary
| ID {$v = 3} # anID
| left=e INC {<Cast("UnaryContext","$ctx"):Concat(".INC() != null"):Assert()>$v = $left.v + 1;} # unary
| left=e DEC {<Cast("UnaryContext","$ctx"):Concat(".DEC() != null"):Assert()>$v = $left.v - 1;} # unary
| ID {<AssignLocal("$v","3")>} # anID
;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;

View File

@ -1,9 +1,9 @@
grammar <grammarName>;
s : e {<writeln("$e.result")>} ;
e returns [String result]
: ID '=' e1=e {$result = \"(\" + $ID.text + \"=\" + $e1.result + \")\";}
: ID '=' e1=e {$result = "(" + $ID.text + "=" + $e1.result + ")";}
| ID {$result = $ID.text;}
| e1=e '+' e2=e {$result = \"(\" + $e1.result + \"+\" + $e2.result + \")\";}
| e1=e '+' e2=e {$result = "(" + $e1.result + "+" + $e2.result + ")";}
;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;

View File

@ -1,6 +1,6 @@
grammar <grammarName>;
s : e {<writeln("$e.v")>};
e returns [int v, list ignored]
e returns [int v, <StringList()> ignored]
: a=e '*' b=e {$v = $a.v * $b.v;}
| a=e '+' b=e {$v = $a.v + $b.v;}
| INT {$v = $INT.int;}

View File

@ -0,0 +1,13 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : expr EOF;
expr:
a=expr '*' a=expr #Factor
| b+=expr (',' b+=expr)* '>>' c=expr #Send
| ID #JustId //semantic check on modifiers
;
ID : ('a'..'z'|'A'..'Z'|'_')
('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
;
WS : [ \t\n]+ -> skip ;

View File

@ -0,0 +1,12 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : expr EOF;
expr:
a=expr '*' a=expr #Factor
| b+=expr ',' b+=expr #Comma
| b+=expr '>>' c=expr #Send
| ID #JustId //semantic check on modifiers
;
ID : ('a'..'z'|'A'..'Z'|'_')
('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
;
WS : [ \t\n]+ -> skip ;

View File

@ -0,0 +1,7 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : a ;
a : a ID {false}?\<fail='custom message'>
| ID
;
ID : 'a'..'z'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,10 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : e EOF; // must indicate EOF can follow or 'a\<EOF>' won't match
e :\<assoc=right> e '*' e
|\<assoc=right> e '+' e
|\<assoc=right> e '?' e ':' e
|\<assoc=right> e '=' e
| ID
;
ID : 'a'..'z'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -46,4 +46,4 @@ DATE : '\'' DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT (
SQ_STRING : '\'' ('\'\'' | ~'\'')* '\'';
DQ_STRING : '\"' ('\\\"' | ~'\"')* '\"';
WS : [ \t\n\r]+ -> skip ;
COMMENTS : ('/*' .*? '*/' | '//' ~'\n'* '\n' ) -> skip;\n";
COMMENTS : ('/*' .*? '*/' | '//' ~'\n'* '\n' ) -> skip;

View File

@ -1,7 +1,7 @@
grammar <grammarName>;
ifStatement
@after {
<DeclareLocal("items = $ctx.elseIfStatement()")>
<DeclareLocal("items","$ctx.elseIfStatement()")>
}
: 'if' expression
( ( 'then'

View File

@ -99,9 +99,15 @@ writeln(s) ::= <<System.out.println(<s>);>>
write(s) ::= <<System.out.print(<s>);>>
assert(s) ::= <<console.assert(<s>);>>
Assert(s) ::= <<assert(<s>);>>
DeclareLocal(s) ::= "Object <s>;"
Cast(t,v) ::= "((<t>)<v>)"
Concat(a,b) ::= "<a><b>"
DeclareLocal(s,v) ::= "Object <s> = <v>;"
AssignLocal(s,v) ::= "<s> = <v>;"
InitMember(n,v) ::= <%this.<n> = <v>;%>
@ -123,6 +129,8 @@ DumpDFA() ::= "this.dumpDFA();"
Pass() ::= ""
StringList() ::= "List\<String>"
BuildParseTrees() ::= "this.buildParseTrees = true;"
BailErrorStrategy() ::= <%setErrorHandler(new BailErrorStrategy());%>

View File

@ -99,63 +99,63 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testTernaryExpr_1() throws Exception {
String found = testTernaryExpr("a");
assertEquals("(s (e a) <EOF>)", found);
assertEquals("(s (e a) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_2() throws Exception {
String found = testTernaryExpr("a+b");
assertEquals("(s (e (e a) + (e b)) <EOF>)", found);
assertEquals("(s (e (e a) + (e b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_3() throws Exception {
String found = testTernaryExpr("a*b");
assertEquals("(s (e (e a) * (e b)) <EOF>)", found);
assertEquals("(s (e (e a) * (e b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_4() throws Exception {
String found = testTernaryExpr("a?b:c");
assertEquals("(s (e (e a) ? (e b) : (e c)) <EOF>)", found);
assertEquals("(s (e (e a) ? (e b) : (e c)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_5() throws Exception {
String found = testTernaryExpr("a=b=c");
assertEquals("(s (e (e a) = (e (e b) = (e c))) <EOF>)", found);
assertEquals("(s (e (e a) = (e (e b) = (e c))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_6() throws Exception {
String found = testTernaryExpr("a?b+c:d");
assertEquals("(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)", found);
assertEquals("(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_7() throws Exception {
String found = testTernaryExpr("a?b=c:d");
assertEquals("(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)", found);
assertEquals("(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_8() throws Exception {
String found = testTernaryExpr("a? b?c:d : e");
assertEquals("(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)", found);
assertEquals("(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExpr_9() throws Exception {
String found = testTernaryExpr("a?b: c?d:e");
assertEquals("(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)", found);
assertEquals("(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@ -179,49 +179,49 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testExpressions_1() throws Exception {
String found = testExpressions("a");
assertEquals("(s (e a) <EOF>)", found);
assertEquals("(s (e a) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testExpressions_2() throws Exception {
String found = testExpressions("1");
assertEquals("(s (e 1) <EOF>)", found);
assertEquals("(s (e 1) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testExpressions_3() throws Exception {
String found = testExpressions("a-1");
assertEquals("(s (e (e a) - (e 1)) <EOF>)", found);
assertEquals("(s (e (e a) - (e 1)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testExpressions_4() throws Exception {
String found = testExpressions("a.b");
assertEquals("(s (e (e a) . b) <EOF>)", found);
assertEquals("(s (e (e a) . b) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testExpressions_5() throws Exception {
String found = testExpressions("a.this");
assertEquals("(s (e (e a) . this) <EOF>)", found);
assertEquals("(s (e (e a) . this) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testExpressions_6() throws Exception {
String found = testExpressions("-a");
assertEquals("(s (e - (e a)) <EOF>)", found);
assertEquals("(s (e - (e a)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testExpressions_7() throws Exception {
String found = testExpressions("-a+b");
assertEquals("(s (e (e - (e a)) + (e b)) <EOF>)", found);
assertEquals("(s (e (e - (e a)) + (e b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@ -288,84 +288,84 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testJavaExpressions_1() throws Exception {
String found = testJavaExpressions("a|b&c");
assertEquals("(s (e (e a) | (e (e b) & (e c))) <EOF>)", found);
assertEquals("(s (e (e a) | (e (e b) & (e c))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_2() throws Exception {
String found = testJavaExpressions("(a|b)&c");
assertEquals("(s (e (e ( (e (e a) | (e b)) )) & (e c)) <EOF>)", found);
assertEquals("(s (e (e ( (e (e a) | (e b)) )) & (e c)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_3() throws Exception {
String found = testJavaExpressions("a > b");
assertEquals("(s (e (e a) > (e b)) <EOF>)", found);
assertEquals("(s (e (e a) > (e b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_4() throws Exception {
String found = testJavaExpressions("a >> b");
assertEquals("(s (e (e a) >> (e b)) <EOF>)", found);
assertEquals("(s (e (e a) >> (e b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_5() throws Exception {
String found = testJavaExpressions("a=b=c");
assertEquals("(s (e (e a) = (e (e b) = (e c))) <EOF>)", found);
assertEquals("(s (e (e a) = (e (e b) = (e c))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_6() throws Exception {
String found = testJavaExpressions("a^b^c");
assertEquals("(s (e (e a) ^ (e (e b) ^ (e c))) <EOF>)", found);
assertEquals("(s (e (e a) ^ (e (e b) ^ (e c))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_7() throws Exception {
String found = testJavaExpressions("(T)x");
assertEquals("(s (e ( (type T) ) (e x)) <EOF>)", found);
assertEquals("(s (e ( (type T) ) (e x)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_8() throws Exception {
String found = testJavaExpressions("new A().b");
assertEquals("(s (e (e new (type A) ( )) . b) <EOF>)", found);
assertEquals("(s (e (e new (type A) ( )) . b) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_9() throws Exception {
String found = testJavaExpressions("(T)t.f()");
assertEquals("(s (e (e ( (type T) ) (e (e t) . f)) ( )) <EOF>)", found);
assertEquals("(s (e (e ( (type T) ) (e (e t) . f)) ( )) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_10() throws Exception {
String found = testJavaExpressions("a.f(x)==T.c");
assertEquals("(s (e (e (e (e a) . f) ( (expressionList (e x)) )) == (e (e T) . c)) <EOF>)", found);
assertEquals("(s (e (e (e (e a) . f) ( (expressionList (e x)) )) == (e (e T) . c)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_11() throws Exception {
String found = testJavaExpressions("a.f().g(x,1)");
assertEquals("(s (e (e (e (e (e a) . f) ( )) . g) ( (expressionList (e x) , (e 1)) )) <EOF>)", found);
assertEquals("(s (e (e (e (e (e a) . f) ( )) . g) ( (expressionList (e x) , (e 1)) )) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testJavaExpressions_12() throws Exception {
String found = testJavaExpressions("new T[((n-1) * x) + 1]");
assertEquals("(s (e new (type T) [ (e (e ( (e (e ( (e (e n) - (e 1)) )) * (e x)) )) + (e 1)) ]) <EOF>)", found);
assertEquals("(s (e new (type T) [ (e (e ( (e (e ( (e (e n) - (e 1)) )) * (e x)) )) + (e 1)) ]) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@ -390,77 +390,77 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testDeclarations_1() throws Exception {
String found = testDeclarations("a");
assertEquals("(s (declarator a) <EOF>)", found);
assertEquals("(s (declarator a) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_2() throws Exception {
String found = testDeclarations("*a");
assertEquals("(s (declarator * (declarator a)) <EOF>)", found);
assertEquals("(s (declarator * (declarator a)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_3() throws Exception {
String found = testDeclarations("**a");
assertEquals("(s (declarator * (declarator * (declarator a))) <EOF>)", found);
assertEquals("(s (declarator * (declarator * (declarator a))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_4() throws Exception {
String found = testDeclarations("a[3]");
assertEquals("(s (declarator (declarator a) [ (e 3) ]) <EOF>)", found);
assertEquals("(s (declarator (declarator a) [ (e 3) ]) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_5() throws Exception {
String found = testDeclarations("b[]");
assertEquals("(s (declarator (declarator b) [ ]) <EOF>)", found);
assertEquals("(s (declarator (declarator b) [ ]) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_6() throws Exception {
String found = testDeclarations("(a)");
assertEquals("(s (declarator ( (declarator a) )) <EOF>)", found);
assertEquals("(s (declarator ( (declarator a) )) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_7() throws Exception {
String found = testDeclarations("a[]()");
assertEquals("(s (declarator (declarator (declarator a) [ ]) ( )) <EOF>)", found);
assertEquals("(s (declarator (declarator (declarator a) [ ]) ( )) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_8() throws Exception {
String found = testDeclarations("a[][]");
assertEquals("(s (declarator (declarator (declarator a) [ ]) [ ]) <EOF>)", found);
assertEquals("(s (declarator (declarator (declarator a) [ ]) [ ]) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_9() throws Exception {
String found = testDeclarations("*a[]");
assertEquals("(s (declarator * (declarator (declarator a) [ ])) <EOF>)", found);
assertEquals("(s (declarator * (declarator (declarator a) [ ])) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testDeclarations_10() throws Exception {
String found = testDeclarations("(*a)[]");
assertEquals("(s (declarator (declarator ( (declarator * (declarator a)) )) [ ]) <EOF>)", found);
assertEquals("(s (declarator (declarator ( (declarator * (declarator a)) )) [ ]) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
String testReturnValueAndActions(String input) throws Exception {
String grammar = "grammar T;\n" +
"s : e {System.out.println($e.v);}; \n" +
"e returns [int v, list ignored]\n" +
"e returns [int v, List<String> ignored]\n" +
" : a=e '*' b=e {$v = $a.v * $b.v;}\n" +
" | a=e '+' b=e {$v = $a.v + $b.v;}\n" +
" | INT {$v = $INT.int;}\n" +
@ -474,28 +474,28 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testReturnValueAndActions_1() throws Exception {
String found = testReturnValueAndActions("4");
assertEquals("4", found);
assertEquals("4\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActions_2() throws Exception {
String found = testReturnValueAndActions("1+2");
assertEquals("3", found);
assertEquals("3\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActions_3() throws Exception {
String found = testReturnValueAndActions("1+2*3");
assertEquals("7", found);
assertEquals("7\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActions_4() throws Exception {
String found = testReturnValueAndActions("(1+2)*3");
assertEquals("9", found);
assertEquals("9\n", found);
assertNull(this.stderrDuringParse);
}
@ -514,21 +514,21 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testLabelsOnOpSubrule_1() throws Exception {
String found = testLabelsOnOpSubrule("4");
assertEquals("(s (e 4))", found);
assertEquals("(s (e 4))\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testLabelsOnOpSubrule_2() throws Exception {
String found = testLabelsOnOpSubrule("1*2/3");
assertEquals("(s (e (e (e 1) * (e 2)) / (e 3)))", found);
assertEquals("(s (e (e (e 1) * (e 2)) / (e 3)))\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testLabelsOnOpSubrule_3() throws Exception {
String found = testLabelsOnOpSubrule("(1/2)*3");
assertEquals("(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))", found);
assertEquals("(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))\n", found);
assertNull(this.stderrDuringParse);
}
@ -553,28 +553,28 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testReturnValueAndActionsAndLabels_1() throws Exception {
String found = testReturnValueAndActionsAndLabels("4");
assertEquals("4", found);
assertEquals("4\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsAndLabels_2() throws Exception {
String found = testReturnValueAndActionsAndLabels("1+2");
assertEquals("3", found);
assertEquals("3\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsAndLabels_3() throws Exception {
String found = testReturnValueAndActionsAndLabels("1+2*3");
assertEquals("7", found);
assertEquals("7\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsAndLabels_4() throws Exception {
String found = testReturnValueAndActionsAndLabels("i++*3");
assertEquals("12", found);
assertEquals("12\n", found);
assertNull(this.stderrDuringParse);
}
@ -582,13 +582,13 @@ public class TestLeftRecursion extends BaseTest {
String grammar = "grammar T;\n" +
"s : e {System.out.println($e.v);}; \n" +
"e returns [int v]\n" +
" : e '*' e {$v = $ctx.e(0).v * $ctx.e(1).v;} # binary\n" +
" | e '+' e {$v = $ctx.e(0).v + $ctx.e(1).v;} # binary\n" +
" : e '*' e {$v = ((BinaryContext)$ctx).e(0).v * ((BinaryContext)$ctx).e(1).v;} # binary\n" +
" | e '+' e {$v = ((BinaryContext)$ctx).e(0).v + ((BinaryContext)$ctx).e(1).v;} # binary\n" +
" | INT {$v = $INT.int;} # anInt\n" +
" | '(' e ')' {$v = $e.v;} # parens\n" +
" | left=e INC {console.assert($ctx.INC() !== null);;$v = $left.v + 1;} # unary\n" +
" | left=e DEC {console.assert($ctx.DEC() !== null);;$v = $left.v - 1;} # unary\n" +
" | ID {$v = 3} # anID\n" +
" | left=e INC {assert(((UnaryContext)$ctx).INC() != null);$v = $left.v + 1;} # unary\n" +
" | left=e DEC {assert(((UnaryContext)$ctx).DEC() != null);$v = $left.v - 1;} # unary\n" +
" | ID {$v = 3;} # anID\n" +
" ; \n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
@ -601,28 +601,28 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testMultipleAlternativesWithCommonLabel_1() throws Exception {
String found = testMultipleAlternativesWithCommonLabel("4");
assertEquals("4", found);
assertEquals("4\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testMultipleAlternativesWithCommonLabel_2() throws Exception {
String found = testMultipleAlternativesWithCommonLabel("1+2");
assertEquals("3", found);
assertEquals("3\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testMultipleAlternativesWithCommonLabel_3() throws Exception {
String found = testMultipleAlternativesWithCommonLabel("1+2*3");
assertEquals("7", found);
assertEquals("7\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testMultipleAlternativesWithCommonLabel_4() throws Exception {
String found = testMultipleAlternativesWithCommonLabel("i++*3");
assertEquals("12", found);
assertEquals("12\n", found);
assertNull(this.stderrDuringParse);
}
@ -630,9 +630,9 @@ public class TestLeftRecursion extends BaseTest {
String grammar = "grammar T;\n" +
"s : e {System.out.println($e.result);} ;\n" +
"e returns [String result]\n" +
" : ID '=' e1=e {$result = \\\"(\\\" + $ID.text + \\\"=\\\" + $e1.result + \\\")\\\";}\n" +
" : ID '=' e1=e {$result = \"(\" + $ID.text + \"=\" + $e1.result + \")\";}\n" +
" | ID {$result = $ID.text;}\n" +
" | e1=e '+' e2=e {$result = \\\"(\\\" + $e1.result + \\\"+\\\" + $e2.result + \\\")\\\";}\n" +
" | e1=e '+' e2=e {$result = \"(\" + $e1.result + \"+\" + $e2.result + \")\";}\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
@ -643,21 +643,21 @@ public class TestLeftRecursion extends BaseTest {
@Test
public void testPrefixOpWithActionAndLabel_1() throws Exception {
String found = testPrefixOpWithActionAndLabel("a");
assertEquals("a", found);
assertEquals("a\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testPrefixOpWithActionAndLabel_2() throws Exception {
String found = testPrefixOpWithActionAndLabel("a+b");
assertEquals("(a+b)", found);
assertEquals("(a+b)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testPrefixOpWithActionAndLabel_3() throws Exception {
String found = testPrefixOpWithActionAndLabel("a=b+c");
assertEquals("((a=b)+c)", found);
assertEquals("((a=b)+c)\n", found);
assertNull(this.stderrDuringParse);
}
@ -770,7 +770,7 @@ public class TestLeftRecursion extends BaseTest {
"SQ_STRING : '\\'' ('\\'\\'' | ~'\\'')* '\\'';\n" +
"DQ_STRING : '\\\"' ('\\\\\"' | ~'\\\"')* '\\\"';\n" +
"WS : [ \\t\\n\\r]+ -> skip ;\n" +
"COMMENTS : ('/*' .*? '*/' | '//' ~'\\n'* '\\n' ) -> skip;\\n\";";
"COMMENTS : ('/*' .*? '*/' | '//' ~'\\n'* '\\n' ) -> skip;";
return execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", input, false);
}
@ -801,5 +801,252 @@ public class TestLeftRecursion extends BaseTest {
assertNull(this.stderrDuringParse);
}
String testMultipleActions(String input) throws Exception {
String grammar = "grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e ;\n" +
"e : a=e op=('*'|'/') b=e {}{}\n" +
" | INT {}{}\n" +
" | '(' x=e ')' {}{}\n" +
" ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
}
@Test
public void testMultipleActions_1() throws Exception {
String found = testMultipleActions("4");
assertEquals("(s (e 4))\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testMultipleActions_2() throws Exception {
String found = testMultipleActions("1*2/3");
assertEquals("(s (e (e (e 1) * (e 2)) / (e 3)))\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testMultipleActions_3() throws Exception {
String found = testMultipleActions("(1/2)*3");
assertEquals("(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))\n", found);
assertNull(this.stderrDuringParse);
}
String testMultipleActionsPredicatesOptions(String input) throws Exception {
String grammar = "grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e ;\n" +
"e : a=e op=('*'|'/') b=e {}{true}?\n" +
" | a=e op=('+'|'-') b=e {}<p=3>{true}?<fail='Message'>\n" +
" | INT {}{}\n" +
" | '(' x=e ')' {}{}\n" +
" ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
}
@Test
public void testMultipleActionsPredicatesOptions_1() throws Exception {
String found = testMultipleActionsPredicatesOptions("4");
assertEquals("(s (e 4))\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testMultipleActionsPredicatesOptions_2() throws Exception {
String found = testMultipleActionsPredicatesOptions("1*2/3");
assertEquals("(s (e (e (e 1) * (e 2)) / (e 3)))\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testMultipleActionsPredicatesOptions_3() throws Exception {
String found = testMultipleActionsPredicatesOptions("(1/2)*3");
assertEquals("(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testSemPredFailOption() throws Exception {
String grammar = "grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" +
"a : a ID {false}?<fail='custom message'>\n" +
" | ID\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x y z", false);
assertEquals("(s (a (a x) y z))\n", found);
assertEquals("line 1:4 rule a custom message\n", this.stderrDuringParse);
}
String testTernaryExprExplicitAssociativity(String input) throws Exception {
String grammar = "grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e EOF; // must indicate EOF can follow or 'a<EOF>' won't match\n" +
"e :<assoc=right> e '*' e\n" +
" |<assoc=right> e '+' e\n" +
" |<assoc=right> e '?' e ':' e\n" +
" |<assoc=right> e '=' e\n" +
" | ID\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
}
@Test
public void testTernaryExprExplicitAssociativity_1() throws Exception {
String found = testTernaryExprExplicitAssociativity("a");
assertEquals("(s (e a) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_2() throws Exception {
String found = testTernaryExprExplicitAssociativity("a+b");
assertEquals("(s (e (e a) + (e b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_3() throws Exception {
String found = testTernaryExprExplicitAssociativity("a*b");
assertEquals("(s (e (e a) * (e b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_4() throws Exception {
String found = testTernaryExprExplicitAssociativity("a?b:c");
assertEquals("(s (e (e a) ? (e b) : (e c)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_5() throws Exception {
String found = testTernaryExprExplicitAssociativity("a=b=c");
assertEquals("(s (e (e a) = (e (e b) = (e c))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_6() throws Exception {
String found = testTernaryExprExplicitAssociativity("a?b+c:d");
assertEquals("(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_7() throws Exception {
String found = testTernaryExprExplicitAssociativity("a?b=c:d");
assertEquals("(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_8() throws Exception {
String found = testTernaryExprExplicitAssociativity("a? b?c:d : e");
assertEquals("(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testTernaryExprExplicitAssociativity_9() throws Exception {
String found = testTernaryExprExplicitAssociativity("a?b: c?d:e");
assertEquals("(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
String testReturnValueAndActionsList1(String input) throws Exception {
String grammar = "grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : expr EOF;\n" +
"expr:\n" +
" a=expr '*' a=expr #Factor\n" +
" | b+=expr (',' b+=expr)* '>>' c=expr #Send\n" +
" | ID #JustId //semantic check on modifiers\n" +
";\n" +
"\n" +
"ID : ('a'..'z'|'A'..'Z'|'_')\n" +
" ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*\n" +
";\n" +
"\n" +
"WS : [ \\t\\n]+ -> skip ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
}
@Test
public void testReturnValueAndActionsList1_1() throws Exception {
String found = testReturnValueAndActionsList1("a*b");
assertEquals("(s (expr (expr a) * (expr b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsList1_2() throws Exception {
String found = testReturnValueAndActionsList1("a,c>>x");
assertEquals("(s (expr (expr a) , (expr c) >> (expr x)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsList1_3() throws Exception {
String found = testReturnValueAndActionsList1("x");
assertEquals("(s (expr x) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsList1_4() throws Exception {
String found = testReturnValueAndActionsList1("a*b,c,x*y>>r");
assertEquals("(s (expr (expr (expr a) * (expr b)) , (expr c) , (expr (expr x) * (expr y)) >> (expr r)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
String testReturnValueAndActionsList2(String input) throws Exception {
String grammar = "grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : expr EOF;\n" +
"expr:\n" +
" a=expr '*' a=expr #Factor\n" +
" | b+=expr ',' b+=expr #Comma\n" +
" | b+=expr '>>' c=expr #Send\n" +
" | ID #JustId //semantic check on modifiers\n" +
" ;\n" +
"ID : ('a'..'z'|'A'..'Z'|'_')\n" +
" ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*\n" +
";\n" +
"WS : [ \\t\\n]+ -> skip ;";
return execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
}
@Test
public void testReturnValueAndActionsList2_1() throws Exception {
String found = testReturnValueAndActionsList2("a*b");
assertEquals("(s (expr (expr a) * (expr b)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsList2_2() throws Exception {
String found = testReturnValueAndActionsList2("a,c>>x");
assertEquals("(s (expr (expr (expr a) , (expr c)) >> (expr x)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsList2_3() throws Exception {
String found = testReturnValueAndActionsList2("x");
assertEquals("(s (expr x) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testReturnValueAndActionsList2_4() throws Exception {
String found = testReturnValueAndActionsList2("a*b,c,x*y>>r");
assertEquals("(s (expr (expr (expr (expr (expr a) * (expr b)) , (expr c)) , (expr (expr x) * (expr y))) >> (expr r)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
}

View File

@ -33,520 +33,10 @@ package org.antlr.v4.test.tool;
import org.antlr.v4.tool.ErrorType;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/** */
public class TestLeftRecursion extends BaseTest {
protected boolean debug = false;
@Test public void testSimple() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" +
"a : a ID\n" +
" | ID" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"s", "x", debug);
String expecting = "(s (a x))\n";
assertEquals(expecting, found);
found = execParser("T.g4", grammar, "TParser", "TLexer",
"s", "x y", debug);
expecting = "(s (a (a x) y))\n";
assertEquals(expecting, found);
found = execParser("T.g4", grammar, "TParser", "TLexer",
"s", "x y z", debug);
expecting = "(s (a (a (a x) y) z))\n";
assertEquals(expecting, found);
}
/**
* This is a regression test for "Support direct calls to left-recursive
* rules".
* https://github.com/antlr/antlr4/issues/161
*/
@Test public void testDirectCallToLeftRecursiveRule() throws Exception {
String grammar =
"grammar T;\n" +
"a @after {System.out.println($ctx.toStringTree(this));} : a ID\n" +
" | ID" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x", debug);
String expecting = "(a x)\n";
assertEquals(expecting, found);
found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x y", debug);
expecting = "(a (a x) y)\n";
assertEquals(expecting, found);
found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x y z", debug);
expecting = "(a (a (a x) y) z)\n";
assertEquals(expecting, found);
}
@Test public void testSemPred() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" +
"a : a {true}? ID\n" +
" | ID" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"s", "x y z", debug);
String expecting = "(s (a (a (a x) y) z))\n";
assertEquals(expecting, found);
}
@Test
public void testSemPredFailOption() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" +
"a : a ID {false}?<fail='custom message'>\n" +
" | ID" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"s", "x y z", debug);
String expecting = "(s (a (a x) y z))\n";
assertEquals(expecting, found);
assertEquals("line 1:4 rule a custom message\n", stderrDuringParse);
}
@Test public void testTernaryExpr() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e EOF ;\n" + // must indicate EOF can follow or 'a<EOF>' won't match
"e : e '*' e" +
" | e '+' e" +
" |<assoc=right> e '?' e ':' e" +
" |<assoc=right> e '=' e" +
" | ID" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"a", "(s (e a) <EOF>)",
"a+b", "(s (e (e a) + (e b)) <EOF>)",
"a*b", "(s (e (e a) * (e b)) <EOF>)",
"a?b:c", "(s (e (e a) ? (e b) : (e c)) <EOF>)",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)",
"a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)",
"a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)",
"a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)",
"a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)",
};
runTests(grammar, tests, "s");
}
/**
* This is a regression test for antlr/antlr4#542 "First alternative cannot
* be right-associative".
* https://github.com/antlr/antlr4/issues/542
*/
@Test public void testTernaryExprExplicitAssociativity() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e EOF ;\n" + // must indicate EOF can follow or 'a<EOF>' won't match
"e :<assoc=right> e '*' e" +
" |<assoc=right> e '+' e" +
" |<assoc=right> e '?' e ':' e" +
" |<assoc=right> e '=' e" +
" | ID" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"a", "(s (e a) <EOF>)",
"a+b", "(s (e (e a) + (e b)) <EOF>)",
"a*b", "(s (e (e a) * (e b)) <EOF>)",
"a?b:c", "(s (e (e a) ? (e b) : (e c)) <EOF>)",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)",
"a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)",
"a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)",
"a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)",
"a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)",
};
runTests(grammar, tests, "s");
}
@Test public void testExpressions() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e EOF ;\n" + // must indicate EOF can follow
"e : e '.' ID\n" +
" | e '.' 'this'\n" +
" | '-' e\n" +
" | e '*' e\n" +
" | e ('+'|'-') e\n" +
" | INT\n" +
" | ID\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"a", "(s (e a) <EOF>)",
"1", "(s (e 1) <EOF>)",
"a-1", "(s (e (e a) - (e 1)) <EOF>)",
"a.b", "(s (e (e a) . b) <EOF>)",
"a.this", "(s (e (e a) . this) <EOF>)",
"-a", "(s (e - (e a)) <EOF>)",
"-a+b", "(s (e (e - (e a)) + (e b)) <EOF>)",
};
runTests(grammar, tests, "s");
}
@Test public void testJavaExpressions() throws Exception {
// Generates about 7k in bytecodes for generated e_ rule;
// Well within the 64k method limit. e_primary compiles
// to about 2k in bytecodes.
// this is simplified from real java
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e EOF ;\n" + // must indicate EOF can follow
"expressionList\n" +
" : e (',' e)*\n" +
" ;\n" +
"e : '(' e ')'\n" +
" | 'this' \n" +
" | 'super'\n" +
" | INT\n" +
" | ID\n" +
" | type '.' 'class'\n" +
" | e '.' ID\n" +
" | e '.' 'this'\n" +
" | e '.' 'super' '(' expressionList? ')'\n" +
" | e '.' 'new' ID '(' expressionList? ')'\n" +
" | 'new' type ( '(' expressionList? ')' | ('[' e ']')+)\n" +
" | e '[' e ']'\n" +
" | '(' type ')' e\n" +
" | e ('++' | '--')\n" +
" | e '(' expressionList? ')'\n" +
" | ('+'|'-'|'++'|'--') e\n" +
" | ('~'|'!') e\n" +
" | e ('*'|'/'|'%') e\n" +
" | e ('+'|'-') e\n" +
" | e ('<<' | '>>>' | '>>') e\n" +
" | e ('<=' | '>=' | '>' | '<') e\n" +
" | e 'instanceof' e\n" +
" | e ('==' | '!=') e\n" +
" | e '&' e\n" +
" |<assoc=right> e '^' e\n" +
" | e '|' e\n" +
" | e '&&' e\n" +
" | e '||' e\n" +
" | e '?' e ':' e\n" +
" |<assoc=right>" +
" e ('='\n" +
" |'+='\n" +
" |'-='\n" +
" |'*='\n" +
" |'/='\n" +
" |'&='\n" +
" |'|='\n" +
" |'^='\n" +
" |'>>='\n" +
" |'>>>='\n" +
" |'<<='\n" +
" |'%=') e\n" +
" ;\n" +
"type: ID \n" +
" | ID '[' ']'\n" +
" | 'int'\n" +
" | 'int' '[' ']' \n" +
" ;\n" +
"ID : ('a'..'z'|'A'..'Z'|'_'|'$')+;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"a|b&c", "(s (e (e a) | (e (e b) & (e c))) <EOF>)",
"(a|b)&c", "(s (e (e ( (e (e a) | (e b)) )) & (e c)) <EOF>)",
"a > b", "(s (e (e a) > (e b)) <EOF>)",
"a >> b", "(s (e (e a) >> (e b)) <EOF>)",
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)",
"a^b^c", "(s (e (e a) ^ (e (e b) ^ (e c))) <EOF>)",
"(T)x", "(s (e ( (type T) ) (e x)) <EOF>)",
"new A().b", "(s (e (e new (type A) ( )) . b) <EOF>)",
"(T)t.f()", "(s (e (e ( (type T) ) (e (e t) . f)) ( )) <EOF>)",
"a.f(x)==T.c", "(s (e (e (e (e a) . f) ( (expressionList (e x)) )) == (e (e T) . c)) <EOF>)",
"a.f().g(x,1)", "(s (e (e (e (e (e a) . f) ( )) . g) ( (expressionList (e x) , (e 1)) )) <EOF>)",
"new T[((n-1) * x) + 1]", "(s (e new (type T) [ (e (e ( (e (e ( (e (e n) - (e 1)) )) * (e x)) )) + (e 1)) ]) <EOF>)",
};
runTests(grammar, tests, "s");
}
@Test public void testDeclarations() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : declarator EOF ;\n" + // must indicate EOF can follow
"declarator\n" +
" : declarator '[' e ']'\n" +
" | declarator '[' ']'\n" +
" | declarator '(' ')'\n" +
" | '*' declarator\n" + // binds less tight than suffixes
" | '(' declarator ')'\n" +
" | ID\n" +
" ;\n" +
"e : INT ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"a", "(s (declarator a) <EOF>)",
"*a", "(s (declarator * (declarator a)) <EOF>)",
"**a", "(s (declarator * (declarator * (declarator a))) <EOF>)",
"a[3]", "(s (declarator (declarator a) [ (e 3) ]) <EOF>)",
"b[]", "(s (declarator (declarator b) [ ]) <EOF>)",
"(a)", "(s (declarator ( (declarator a) )) <EOF>)",
"a[]()", "(s (declarator (declarator (declarator a) [ ]) ( )) <EOF>)",
"a[][]", "(s (declarator (declarator (declarator a) [ ]) [ ]) <EOF>)",
"*a[]", "(s (declarator * (declarator (declarator a) [ ])) <EOF>)",
"(*a)[]", "(s (declarator (declarator ( (declarator * (declarator a)) )) [ ]) <EOF>)",
};
runTests(grammar, tests, "s");
}
@Test public void testReturnValueAndActions() throws Exception {
String grammar =
"grammar T;\n" +
"s : e {System.out.println($e.v);} ;\n" +
"e returns [int v, List<String> ignored]\n" +
" : a=e '*' b=e {$v = $a.v * $b.v;}\n" +
" | a=e '+' b=e {$v = $a.v + $b.v;}\n" +
" | INT {$v = $INT.int;}\n" +
" | '(' x=e ')' {$v = $x.v;}\n" +
" ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"4", "4",
"1+2", "3",
"1+2*3", "7",
"(1+2)*3", "9",
};
runTests(grammar, tests, "s");
}
/**
* This is a regression test for antlr/antlr4#677 "labels not working in
* grammar file".
* https://github.com/antlr/antlr4/issues/677
*
* <p>This test treats {@code ,} and {@code >>} as part of a single compound
* operator (similar to a ternary operator).</p>
*/
@Test public void testReturnValueAndActionsList1() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : expr EOF;\n" +
"expr:\n" +
" a=expr '*' a=expr #Factor\n" +
" | b+=expr (',' b+=expr)* '>>' c=expr #Send\n" +
" | ID #JustId //semantic check on modifiers\n" +
";\n" +
"\n" +
"ID : ('a'..'z'|'A'..'Z'|'_')\n" +
" ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*\n" +
";\n" +
"\n" +
"WS : [ \\t\\n]+ -> skip ;\n";
String[] tests = {
"a*b", "(s (expr (expr a) * (expr b)) <EOF>)",
"a,c>>x", "(s (expr (expr a) , (expr c) >> (expr x)) <EOF>)",
"x", "(s (expr x) <EOF>)",
"a*b,c,x*y>>r", "(s (expr (expr (expr a) * (expr b)) , (expr c) , (expr (expr x) * (expr y)) >> (expr r)) <EOF>)",
};
runTests(grammar, tests, "s");
}
/**
* This is a regression test for antlr/antlr4#677 "labels not working in
* grammar file".
* https://github.com/antlr/antlr4/issues/677
*
* <p>This test treats the {@code ,} and {@code >>} operators separately.</p>
*/
@Test public void testReturnValueAndActionsList2() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : expr EOF;\n" +
"expr:\n" +
" a=expr '*' a=expr #Factor\n" +
" | b+=expr ',' b+=expr #Comma\n" +
" | b+=expr '>>' c=expr #Send\n" +
" | ID #JustId //semantic check on modifiers\n" +
";\n" +
"\n" +
"ID : ('a'..'z'|'A'..'Z'|'_')\n" +
" ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*\n" +
";\n" +
"\n" +
"WS : [ \\t\\n]+ -> skip ;\n";
String[] tests = {
"a*b", "(s (expr (expr a) * (expr b)) <EOF>)",
"a,c>>x", "(s (expr (expr (expr a) , (expr c)) >> (expr x)) <EOF>)",
"x", "(s (expr x) <EOF>)",
"a*b,c,x*y>>r", "(s (expr (expr (expr (expr (expr a) * (expr b)) , (expr c)) , (expr (expr x) * (expr y))) >> (expr r)) <EOF>)",
};
runTests(grammar, tests, "s");
}
@Test public void testLabelsOnOpSubrule() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e ;\n" +
"e : a=e op=('*'|'/') b=e {}\n" +
" | INT {}\n" +
" | '(' x=e ')' {}\n" +
" ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"4", "(s (e 4))",
"1*2/3", "(s (e (e (e 1) * (e 2)) / (e 3)))",
"(1/2)*3", "(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))",
};
runTests(grammar, tests, "s");
}
@Test public void testReturnValueAndActionsAndLabels() throws Exception {
String grammar =
"grammar T;\n" +
"s : q=e {System.out.println($e.v);} ;\n" +
"\n" +
"e returns [int v]\n" +
" : a=e op='*' b=e {$v = $a.v * $b.v;} # mult\n" +
" | a=e '+' b=e {$v = $a.v + $b.v;} # add\n" +
" | INT {$v = $INT.int;} # anInt\n" +
" | '(' x=e ')' {$v = $x.v;} # parens\n" +
" | x=e '++' {$v = $x.v+1;} # inc\n" +
" | e '--' # dec\n" +
" | ID {$v = 3;} # anID\n" +
" ; \n" +
"\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"4", "4",
"1+2", "3",
"1+2*3", "7",
"i++*3", "12",
};
runTests(grammar, tests, "s");
}
/**
* This is a regression test for antlr/antlr4#433 "Not all context accessor
* methods are generated when an alternative rule label is used for multiple
* alternatives".
* https://github.com/antlr/antlr4/issues/433
*/
@Test public void testMultipleAlternativesWithCommonLabel() throws Exception {
String grammar =
"grammar T;\n" +
"s : e {System.out.println($e.v);} ;\n" +
"\n" +
"e returns [int v]\n" +
" : e '*' e {$v = ((BinaryContext)$ctx).e(0).v * ((BinaryContext)$ctx).e(1).v;} # binary\n" +
" | e '+' e {$v = ((BinaryContext)$ctx).e(0).v + ((BinaryContext)$ctx).e(1).v;} # binary\n" +
" | INT {$v = $INT.int;} # anInt\n" +
" | '(' e ')' {$v = $e.v;} # parens\n" +
" | left=e INC {assert(((UnaryContext)$ctx).INC() != null); $v = $left.v + 1;} # unary\n" +
" | left=e DEC {assert(((UnaryContext)$ctx).DEC() != null); $v = $left.v - 1;} # unary\n" +
" | ID {$v = 3;} # anID\n" +
" ; \n" +
"\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"INC : '++' ;\n" +
"DEC : '--' ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"4", "4",
"1+2", "3",
"1+2*3", "7",
"i++*3", "12",
};
runTests(grammar, tests, "s");
}
@Test public void testPrefixOpWithActionAndLabel() throws Exception {
String grammar =
"grammar T;\n" +
"s : e {System.out.println($e.result);} ;\n" +
"\n" +
"e returns [String result]\n" +
" : ID '=' e1=e { $result = \"(\" + $ID.getText() + \"=\" + $e1.result + \")\"; }\n" +
" | ID { $result = $ID.getText(); }\n" +
" | e1=e '+' e2=e { $result = \"(\" + $e1.result + \"+\" + $e2.result + \")\"; }\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"a", "a",
"a+b", "(a+b)",
"a=b+c", "((a=b)+c)",
};
runTests(grammar, tests, "s");
}
@Test
public void testAmbigLR() throws Exception {
String grammar =
"grammar Expr;\n" +
"prog: stat ;\n" +
"stat: expr NEWLINE # printExpr\n" +
" | ID '=' expr NEWLINE # assign\n" +
" | NEWLINE # blank\n" +
" ;\n" +
"expr: expr ('*'|'/') expr # MulDiv\n" +
" | expr ('+'|'-') expr # AddSub\n" +
" | INT # int\n" +
" | ID # id\n" +
" | '(' expr ')' # parens\n" +
" ;\n" +
"\n" +
"MUL : '*' ; // assigns token name to '*' used above in grammar\n" +
"DIV : '/' ;\n" +
"ADD : '+' ;\n" +
"SUB : '-' ;\n" +
"ID : [a-zA-Z]+ ; // match identifiers\n" +
"INT : [0-9]+ ; // match integers\n" +
"NEWLINE:'\\r'? '\\n' ; // return newlines to parser (is end-statement signal)\n" +
"WS : [ \\t]+ -> skip ; // toss out whitespace\n";
String result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "1\n", true);
assertNull(stderrDuringParse);
result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "a = 5\n", true);
assertNull(stderrDuringParse);
result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "b = 6\n", true);
assertNull(stderrDuringParse);
result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "a+b*2\n", true);
assertNull(stderrDuringParse);
result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "(1+2)*3\n", true);
assertNull(stderrDuringParse);
}
@Test public void testCheckForNonLeftRecursiveRule() throws Exception {
String grammar =
"grammar T;\n" +
@ -574,159 +64,4 @@ public class TestLeftRecursion extends BaseTest {
testErrors(new String[] { grammar, expected }, false);
}
/**
* This is a regression test for #239 "recoursive parser using implicit
* tokens ignore white space lexer rule".
* https://github.com/antlr/antlr4/issues/239
*/
@Test public void testWhitespaceInfluence() {
String grammar =
"grammar Expr;\n" +
"prog : expression EOF;\n" +
"expression\n" +
" : ID '(' expression (',' expression)* ')' # doFunction\n" +
" | '(' expression ')' # doParenthesis\n" +
" | '!' expression # doNot\n" +
" | '-' expression # doNegate\n" +
" | '+' expression # doPositiv\n" +
" | expression '^' expression # doPower\n" +
" | expression '*' expression # doMultipy\n" +
" | expression '/' expression # doDivide\n" +
" | expression '%' expression # doModulo\n" +
" | expression '-' expression # doMinus\n" +
" | expression '+' expression # doPlus\n" +
" | expression '=' expression # doEqual\n" +
" | expression '!=' expression # doNotEqual\n" +
" | expression '>' expression # doGreather\n" +
" | expression '>=' expression # doGreatherEqual\n" +
" | expression '<' expression # doLesser\n" +
" | expression '<=' expression # doLesserEqual\n" +
" | expression K_IN '(' expression (',' expression)* ')' # doIn\n" +
" | expression ( '&' | K_AND) expression # doAnd\n" +
" | expression ( '|' | K_OR) expression # doOr\n" +
" | '[' expression (',' expression)* ']' # newArray\n" +
" | K_TRUE # newTrueBoolean\n" +
" | K_FALSE # newFalseBoolean\n" +
" | NUMBER # newNumber\n" +
" | DATE # newDateTime\n" +
" | ID # newIdentifier\n" +
" | SQ_STRING # newString\n" +
" | K_NULL # newNull\n" +
" ;\n" +
"\n" +
"// Fragments\n" +
"fragment DIGIT : '0' .. '9'; \n" +
"fragment UPPER : 'A' .. 'Z';\n" +
"fragment LOWER : 'a' .. 'z';\n" +
"fragment LETTER : LOWER | UPPER;\n" +
"fragment WORD : LETTER | '_' | '$' | '#' | '.';\n" +
"fragment ALPHANUM : WORD | DIGIT; \n" +
"\n" +
"// Tokens\n" +
"ID : LETTER ALPHANUM*;\n" +
"NUMBER : DIGIT+ ('.' DIGIT+)? (('e'|'E')('+'|'-')? DIGIT+)?;\n" +
"DATE : '\\'' DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT (' ' DIGIT DIGIT ':' DIGIT DIGIT ':' DIGIT DIGIT ('.' DIGIT+)?)? '\\'';\n" +
"SQ_STRING : '\\'' ('\\'\\'' | ~'\\'')* '\\'';\n" +
"DQ_STRING : '\"' ('\\\\\"' | ~'\"')* '\"';\n" +
"WS : [ \\t\\n\\r]+ -> skip ;\n" +
"COMMENTS : ('/*' .*? '*/' | '//' ~'\\n'* '\\n' ) -> skip;\n";
String expected =
"";
String result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "Test(1,3)", false);
assertEquals(expected, result);
assertNull(stderrDuringParse);
expected =
"";
result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "Test(1, 3)", false);
assertEquals(expected, result);
assertNull(stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#509 "Incorrect rule chosen in
* unambiguous grammar".
* https://github.com/antlr/antlr4/issues/509
*/
@Test public void testPrecedenceFilterConsidersContext() throws Exception {
String grammar =
"grammar T;\n" +
"prog\n" +
"@after {System.out.println($ctx.toStringTree(this));}\n" +
": statement* EOF {};\n" +
"statement: letterA | statement letterA 'b' ;\n" +
"letterA: 'a';\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "prog",
"aa", false);
assertEquals("(prog (statement (letterA a)) (statement (letterA a)) <EOF>)\n", found);
}
/**
* This is a regression test for antlr/antlr4#625 "Duplicate action breaks
* operator precedence"
* https://github.com/antlr/antlr4/issues/625
*/
@Test public void testMultipleActions() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e ;\n" +
"e : a=e op=('*'|'/') b=e {}{}\n" +
" | INT {}{}\n" +
" | '(' x=e ')' {}{}\n" +
" ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"4", "(s (e 4))",
"1*2/3", "(s (e (e (e 1) * (e 2)) / (e 3)))",
"(1/2)*3", "(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))",
};
runTests(grammar, tests, "s");
}
/**
* This is a regression test for antlr/antlr4#625 "Duplicate action breaks
* operator precedence"
* https://github.com/antlr/antlr4/issues/625
*/
@Test public void testMultipleActionsPredicatesOptions() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : e ;\n" +
"e : a=e op=('*'|'/') b=e {}{true}?\n" +
" | a=e op=('+'|'-') b=e {}<p=3>{true}?<fail='Message'>\n" +
" | INT {}{}\n" +
" | '(' x=e ')' {}{}\n" +
" ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"4", "(s (e 4))",
"1*2/3", "(s (e (e (e 1) * (e 2)) / (e 3)))",
"(1/2)*3", "(s (e (e ( (e (e 1) / (e 2)) )) * (e 3)))",
};
runTests(grammar, tests, "s");
}
public void runTests(String grammar, String[] tests, String startRule) {
boolean success = rawGenerateAndBuildRecognizer("T.g4", grammar, "TParser", "TLexer");
assertTrue(success);
writeRecognizerAndCompile("TParser",
"TLexer",
startRule,
debug,
false);
for (int i=0; i<tests.length; i+=2) {
String test = tests[i];
String expecting = tests[i+1]+"\n";
writeFile(tmpdir, "input", test);
String found = execRecognizer();
System.out.print(test+" -> "+found);
assertEquals(expecting, found);
}
}
}