fetched runtime-tests-generator branch into master and did a manual merge. Fixes #76 as I was right there anyway.

This commit is contained in:
Terence Parr 2014-11-15 18:13:22 -08:00
commit 29c2712ae1
310 changed files with 18111 additions and 5316 deletions

View File

@ -23,7 +23,7 @@
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.43.1</version>
<version>2.44.0</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -1,820 +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;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.GrammarSemanticsMessage;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class TestCompositeGrammars extends BaseTest {
protected boolean debug = false;
@Test public void testImportFileLocationInSubdir() throws Exception {
String slave =
"parser grammar S;\n" +
"a : B {System.out.println(\"S.a\");} ;\n";
mkdir(tmpdir);
String subdir = tmpdir + "/sub";
mkdir(subdir);
writeFile(subdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a ;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
writeFile(tmpdir, "M.g4", master);
ErrorQueue equeue = antlr("M.g4", false, "-lib", subdir);
assertEquals(equeue.size(), 0);
}
@Test public void testImportFileNotSearchedForInOutputDir() throws Exception {
String slave =
"parser grammar S;\n" +
"a : B {System.out.println(\"S.a\");} ;\n";
mkdir(tmpdir);
String outdir = tmpdir + "/out";
mkdir(outdir);
writeFile(outdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a ;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
writeFile(tmpdir, "M.g4", master);
ErrorQueue equeue = antlr("M.g4", false, "-o", outdir);
assertEquals(ErrorType.CANNOT_FIND_IMPORTED_GRAMMAR, equeue.errors.get(0).getErrorType());
}
@Test public void testOutputDirShouldNotEffectImports() throws Exception {
String slave =
"parser grammar S;\n" +
"a : B {System.out.println(\"S.a\");} ;\n";
mkdir(tmpdir);
String subdir = tmpdir + "/sub";
mkdir(subdir);
writeFile(subdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a ;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
writeFile(tmpdir, "M.g4", master);
String outdir = tmpdir + "/out";
mkdir(outdir);
ErrorQueue equeue = antlr("M.g4", false, "-o", outdir, "-lib", subdir);
assertEquals(0, equeue.size());
}
@Test public void testTokensFileInOutputDirAndImportFileInSubdir() throws Exception {
String slave =
"parser grammar S;\n" +
"a : B {System.out.println(\"S.a\");} ;\n";
mkdir(tmpdir);
String subdir = tmpdir + "/sub";
mkdir(subdir);
writeFile(subdir, "S.g4", slave);
String parser =
"parser grammar MParser;\n" +
"import S;\n" +
"options {tokenVocab=MLexer;}\n" +
"s : a ;\n";
writeFile(tmpdir, "MParser.g4", parser);
String lexer =
"lexer grammar MLexer;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
writeFile(tmpdir, "MLexer.g4", lexer);
String outdir = tmpdir + "/out";
mkdir(outdir);
ErrorQueue equeue = antlr("MLexer.g4", false, "-o", outdir);
assertEquals(0, equeue.size());
equeue = antlr("MParser.g4", false, "-o", outdir, "-lib", subdir);
assertEquals(0, equeue.size());
}
@Test public void testDelegatorInvokesDelegateRule() throws Exception {
String slave =
"parser grammar S;\n" +
"a : B {System.out.println(\"S.a\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a ;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "b", debug);
assertEquals("S.a\n", found);
}
@Test public void testBringInLiteralsFromDelegate() throws Exception {
String slave =
"parser grammar S;\n" +
"a : '=' 'a' {System.out.println(\"S.a\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "=a", debug);
assertEquals("S.a\n", found);
}
@Test public void testDelegatorInvokesDelegateRuleWithArgs() throws Exception {
// must generate something like:
// public int a(int x) throws RecognitionException { return gS.a(x); }
// in M.
String slave =
"parser grammar S;\n" +
"a[int x] returns [int y] : B {System.out.print(\"S.a\"); $y=1000;} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : label=a[3] {System.out.println($label.y);} ;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "b", debug);
assertEquals("S.a1000\n", found);
}
@Test public void testDelegatorInvokesDelegateRuleWithReturnStruct() throws Exception {
// must generate something like:
// public int a(int x) throws RecognitionException { return gS.a(x); }
// in M.
String slave =
"parser grammar S;\n" +
"a : B {System.out.print(\"S.a\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a {System.out.println($a.text);} ;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "b", debug);
assertEquals("S.ab\n", found);
}
@Test public void testDelegatorAccessesDelegateMembers() throws Exception {
String slave =
"parser grammar S;\n" +
"@parser::members {\n" +
" public void foo() {System.out.println(\"foo\");}\n" +
"}\n" +
"a : B ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" + // uses no rules from the import
"import S;\n" +
"s : 'b' {foo();} ;\n" + // gS is import pointer
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "b", debug);
assertEquals("foo\n", found);
}
@Test public void testDelegatorInvokesFirstVersionOfDelegateRule() throws Exception {
String slave =
"parser grammar S;\n" +
"a : b {System.out.println(\"S.a\");} ;\n" +
"b : B ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String slave2 =
"parser grammar T;\n" +
"a : B {System.out.println(\"T.a\");} ;\n"; // hidden by S.a
writeFile(tmpdir, "T.g4", slave2);
String master =
"grammar M;\n" +
"import S,T;\n" +
"s : a ;\n" +
"B : 'b' ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "b", debug);
assertEquals("S.a\n", found);
}
@Test public void testDelegatesSeeSameTokenType() throws Exception {
String slave =
"parser grammar S;\n" + // A, B, C token type order
"tokens { A, B, C }\n" +
"x : A {System.out.println(\"S.x\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String slave2 =
"parser grammar T;\n" +
"tokens { C, B, A }\n" + // reverse order
"y : A {System.out.println(\"T.y\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "T.g4", slave2);
// The lexer will create rules to match letters a, b, c.
// The associated token types A, B, C must have the same value
// and all import'd parsers. Since ANTLR regenerates all imports
// for use with the delegator M, it can generate the same token type
// mapping in each parser:
// public static final int C=6;
// public static final int EOF=-1;
// public static final int B=5;
// public static final int WS=7;
// public static final int A=4;
String master =
"grammar M;\n" +
"import S,T;\n" +
"s : x y ;\n" + // matches AA, which should be "aa"
"B : 'b' ;\n" + // another order: B, A, C
"A : 'a' ;\n" +
"C : 'c' ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "aa", debug);
assertEquals("S.x\n" +
"T.y\n", found);
}
@Test public void testDelegatesSeeSameTokenType2() throws Exception {
ErrorQueue equeue = new ErrorQueue();
String slave =
"parser grammar S;\n" + // A, B, C token type order
"tokens { A, B, C }\n" +
"x : A {System.out.println(\"S.x\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String slave2 =
"parser grammar T;\n" +
"tokens { C, B, A }\n" + // reverse order
"y : A {System.out.println(\"T.y\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "T.g4", slave2);
String master =
"grammar M;\n" +
"import S,T;\n" +
"s : x y ;\n" + // matches AA, which should be "aa"
"B : 'b' ;\n" + // another order: B, A, C
"A : 'a' ;\n" +
"C : 'c' ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
writeFile(tmpdir, "M.g4", master);
Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue);
String expectedTokenIDToTypeMap = "{EOF=-1, B=1, A=2, C=3, WS=4}";
String expectedStringLiteralToTypeMap = "{'a'=2, 'b'=1, 'c'=3}";
String expectedTypeToTokenList = "[B, A, C, WS]";
assertEquals(expectedTokenIDToTypeMap, g.tokenNameToTypeMap.toString());
assertEquals(expectedStringLiteralToTypeMap, sort(g.stringLiteralToTypeMap).toString());
assertEquals(expectedTypeToTokenList, realElements(g.typeToTokenList).toString());
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "aa", debug);
assertEquals("S.x\n" +
"T.y\n", found);
}
@Test public void testCombinedImportsCombined() throws Exception {
ErrorQueue equeue = new ErrorQueue();
String slave =
"grammar S;\n" + // A, B, C token type order
"tokens { A, B, C }\n" +
"x : 'x' INT {System.out.println(\"S.x\");} ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : x INT ;\n";
writeFile(tmpdir, "M.g4", master);
Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue);
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "x 34 9", debug);
assertEquals("S.x\n", found);
}
@Test public void testImportedTokenVocabIgnoredWithWarning() throws Exception {
ErrorQueue equeue = new ErrorQueue();
String slave =
"parser grammar S;\n" +
"options {tokenVocab=whatever;}\n" +
"tokens { A }\n" +
"x : A {System.out.println(\"S.x\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : x ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
writeFile(tmpdir, "M.g4", master);
Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue);
Object expectedArg = "S";
ErrorType expectedMsgID = ErrorType.OPTIONS_IN_DELEGATE;
GrammarSemanticsMessage expectedMessage =
new GrammarSemanticsMessage(expectedMsgID, g.fileName, null, expectedArg);
checkGrammarSemanticsWarning(equeue, expectedMessage);
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
assertEquals("unexpected warnings: "+equeue, 1, equeue.warnings.size());
}
@Test public void testSyntaxErrorsInImportsNotThrownOut() throws Exception {
ErrorQueue equeue = new ErrorQueue();
String slave =
"parser grammar S;\n" +
"options {toke\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : x ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
writeFile(tmpdir, "M.g4", master);
Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue);
assertEquals(ErrorType.SYNTAX_ERROR, equeue.errors.get(0).getErrorType());
}
@Test public void testDelegatorRuleOverridesDelegate() throws Exception {
String slave =
"parser grammar S;\n" +
"a : b {System.out.println(\"S.a\");} ;\n" +
"b : B ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"b : 'b'|'c' ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"a", "c", debug);
assertEquals("S.a\n", found);
}
@Test public void testDelegatorRuleOverridesLookaheadInDelegate() throws Exception {
String slave =
"parser grammar JavaDecl;\n" +
"type : 'int' ;\n" +
"decl : type ID ';'\n" +
" | type ID init ';' {System.out.println(\"JavaDecl: \"+$text);}\n" +
" ;\n" +
"init : '=' INT ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "JavaDecl.g4", slave);
String master =
"grammar Java;\n" +
"import JavaDecl;\n" +
"prog : decl ;\n" +
"type : 'int' | 'float' ;\n" +
"\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
// for float to work in decl, type must be overridden
String found = execParser("Java.g4", master, "JavaParser", "JavaLexer",
"prog", "float x = 3;", debug);
assertEquals("JavaDecl: floatx=3;\n", found);
}
@Test public void testDelegatorRuleOverridesDelegates() throws Exception {
String slave =
"parser grammar S;\n" +
"a : b {System.out.println(\"S.a\");} ;\n" +
"b : 'b' ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String slave2 =
"parser grammar T;\n" +
"tokens { A }\n" +
"b : 'b' {System.out.println(\"T.b\");} ;\n";
writeFile(tmpdir, "T.g4", slave2);
String master =
"grammar M;\n" +
"import S, T;\n" +
"b : 'b'|'c' {System.out.println(\"M.b\");}|B|A ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"a", "c", debug);
assertEquals("M.b\n" +
"S.a\n", found);
}
// LEXER INHERITANCE
@Test public void testLexerDelegatorInvokesDelegateRule() throws Exception {
String slave =
"lexer grammar S;\n" +
"A : 'a' {System.out.println(\"S.A\");} ;\n" +
"C : 'c' ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"lexer grammar M;\n" +
"import S;\n" +
"B : 'b' ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String expecting =
"S.A\n" +
"[@0,0:0='a',<3>,1:0]\n" +
"[@1,1:1='b',<1>,1:1]\n" +
"[@2,2:2='c',<4>,1:2]\n" +
"[@3,3:2='<EOF>',<-1>,1:3]\n";
String found = execLexer("M.g4", master, "M", "abc", debug);
assertEquals(expecting, found);
}
@Test public void testLexerDelegatorRuleOverridesDelegate() throws Exception {
String slave =
"lexer grammar S;\n" +
"A : 'a' {System.out.println(\"S.A\");} ;\n" +
"B : 'b' {System.out.println(\"S.B\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"lexer grammar M;\n" +
"import S;\n" +
"A : 'a' B {System.out.println(\"M.A\");} ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execLexer("M.g4", master, "M", "ab", debug);
assertEquals("M.A\n" +
"[@0,0:1='ab',<1>,1:0]\n" +
"[@1,2:1='<EOF>',<-1>,1:2]\n", found);
}
@Test public void testKeywordVSIDOrder() throws Exception {
// rules in lexer are imported at END so rules in master override
// *and* get priority over imported rules. So importing ID doesn't
// mess up keywords in master grammar
ErrorQueue equeue = new ErrorQueue();
String slave =
"lexer grammar S;\n" +
"ID : 'a'..'z'+ ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"a : A {System.out.println(\"M.a: \"+$A);} ;\n" +
"A : 'abc' {System.out.println(\"M.A\");} ;\n" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"a", "abc", debug);
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
assertEquals("unexpected warnings: "+equeue, 0, equeue.warnings.size());
assertEquals("M.A\n" +
"M.a: [@0,0:2='abc',<1>,1:0]\n", found);
}
// Make sure that M can import S that imports T.
@Test public void test3LevelImport() throws Exception {
ErrorQueue equeue = new ErrorQueue();
String slave =
"parser grammar T;\n" +
"a : T ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "T.g4", slave);
String slave2 =
"parser grammar S;\n" +
"import T;\n" +
"a : S ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave2);
String master =
"grammar M;\n" +
"import S;\n" +
"a : M ;\n" ;
writeFile(tmpdir, "M.g4", master);
Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue);
String expectedTokenIDToTypeMap = "{EOF=-1, M=1}"; // S and T aren't imported; overridden
String expectedStringLiteralToTypeMap = "{}";
String expectedTypeToTokenList = "[M]";
assertEquals(expectedTokenIDToTypeMap,
g.tokenNameToTypeMap.toString());
assertEquals(expectedStringLiteralToTypeMap, g.stringLiteralToTypeMap.toString());
assertEquals(expectedTypeToTokenList,
realElements(g.typeToTokenList).toString());
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
boolean ok =
rawGenerateAndBuildRecognizer("M.g4", master, "MParser", null);
boolean expecting = true; // should be ok
assertEquals(expecting, ok);
}
@Test public void testBigTreeOfImports() throws Exception {
ErrorQueue equeue = new ErrorQueue();
String slave =
"parser grammar T;\n" +
"tokens{T}\n" +
"x : T ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "T.g4", slave);
slave =
"parser grammar S;\n" +
"import T;\n" +
"tokens{S}\n" +
"y : S ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
slave =
"parser grammar C;\n" +
"tokens{C}\n" +
"i : C ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "C.g4", slave);
slave =
"parser grammar B;\n" +
"tokens{B}\n" +
"j : B ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "B.g4", slave);
slave =
"parser grammar A;\n" +
"import B,C;\n" +
"tokens{A}\n" +
"k : A ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "A.g4", slave);
String master =
"grammar M;\n" +
"import S,A;\n" +
"tokens{M}\n" +
"a : M ;\n" ;
writeFile(tmpdir, "M.g4", master);
Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue);
assertEquals("[]", equeue.errors.toString());
assertEquals("[]", equeue.warnings.toString());
String expectedTokenIDToTypeMap = "{EOF=-1, M=1, S=2, T=3, A=4, B=5, C=6}";
String expectedStringLiteralToTypeMap = "{}";
String expectedTypeToTokenList = "[M, S, T, A, B, C]";
assertEquals(expectedTokenIDToTypeMap,
g.tokenNameToTypeMap.toString());
assertEquals(expectedStringLiteralToTypeMap, g.stringLiteralToTypeMap.toString());
assertEquals(expectedTypeToTokenList,
realElements(g.typeToTokenList).toString());
boolean ok =
rawGenerateAndBuildRecognizer("M.g4", master, "MParser", null);
boolean expecting = true; // should be ok
assertEquals(expecting, ok);
}
@Test public void testRulesVisibleThroughMultilevelImport() throws Exception {
ErrorQueue equeue = new ErrorQueue();
String slave =
"parser grammar T;\n" +
"x : T ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "T.g4", slave);
String slave2 =
"parser grammar S;\n" + // A, B, C token type order
"import T;\n" +
"a : S ;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave2);
String master =
"grammar M;\n" +
"import S;\n" +
"a : M x ;\n" ; // x MUST BE VISIBLE TO M
writeFile(tmpdir, "M.g4", master);
Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue);
String expectedTokenIDToTypeMap = "{EOF=-1, M=1, T=2}";
String expectedStringLiteralToTypeMap = "{}";
String expectedTypeToTokenList = "[M, T]";
assertEquals(expectedTokenIDToTypeMap,
g.tokenNameToTypeMap.toString());
assertEquals(expectedStringLiteralToTypeMap, g.stringLiteralToTypeMap.toString());
assertEquals(expectedTypeToTokenList,
realElements(g.typeToTokenList).toString());
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
}
@Test public void testNestedComposite() throws Exception {
// Wasn't compiling. http://www.antlr.org/jira/browse/ANTLR-438
ErrorQueue equeue = new ErrorQueue();
String gstr =
"lexer grammar L;\n" +
"T1: '1';\n" +
"T2: '2';\n" +
"T3: '3';\n" +
"T4: '4';\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "L.g4", gstr);
gstr =
"parser grammar G1;\n" +
"s: a | b;\n" +
"a: T1;\n" +
"b: T2;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "G1.g4", gstr);
gstr =
"parser grammar G2;\n" +
"import G1;\n" +
"a: T3;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "G2.g4", gstr);
String G3str =
"grammar G3;\n" +
"import G2;\n" +
"b: T4;\n" ;
mkdir(tmpdir);
writeFile(tmpdir, "G3.g4", G3str);
Grammar g = new Grammar(tmpdir+"/G3.g4", G3str, equeue);
String expectedTokenIDToTypeMap = "{EOF=-1, T4=1, T3=2}";
String expectedStringLiteralToTypeMap = "{}";
String expectedTypeToTokenList = "[T4, T3]";
assertEquals(expectedTokenIDToTypeMap,
g.tokenNameToTypeMap.toString());
assertEquals(expectedStringLiteralToTypeMap, g.stringLiteralToTypeMap.toString());
assertEquals(expectedTypeToTokenList,
realElements(g.typeToTokenList).toString());
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
boolean ok =
rawGenerateAndBuildRecognizer("G3.g4", G3str, "G3Parser", null);
boolean expecting = true; // should be ok
assertEquals(expecting, ok);
}
@Test public void testHeadersPropogatedCorrectlyToImportedGrammars() throws Exception {
String slave =
"parser grammar S;\n" +
"a : B {System.out.print(\"S.a\");} ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"@header{package mypackage;}\n" +
"s : a ;\n" +
"B : 'b' ;" + // defines B from inherited token space
"WS : (' '|'\\n') -> skip ;\n" ;
ErrorQueue equeue = antlr("M.g4", master, false);
int expecting = 0; // should be ok
assertEquals(expecting, equeue.errors.size());
}
@Test public void testImportedRuleWithAction() throws Exception {
// wasn't terminating. @after was injected into M as if it were @members
String slave =
"parser grammar S;\n" +
"a @after {int x;} : B ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a ;\n" +
"B : 'b' ;" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "b", debug);
assertEquals("", found);
}
@Test public void testImportedGrammarWithEmptyOptions() throws Exception {
String slave =
"parser grammar S;\n" +
"options {}\n" +
"a : B ;\n";
mkdir(tmpdir);
writeFile(tmpdir, "S.g4", slave);
String master =
"grammar M;\n" +
"import S;\n" +
"s : a ;\n" +
"B : 'b' ;" +
"WS : (' '|'\\n') -> skip ;\n" ;
String found = execParser("M.g4", master, "MParser", "MLexer",
"s", "b", debug);
assertEquals("", found);
}
/**
* This is a regression test for antlr/antlr4#248 "Including grammar with
* only fragments breaks generated lexer".
* https://github.com/antlr/antlr4/issues/248
*/
@Test public void testImportLexerWithOnlyFragmentRules() {
String slave =
"lexer grammar Unicode;\n" +
"\n" +
"fragment\n" +
"UNICODE_CLASS_Zs : '\\u0020' | '\\u00A0' | '\\u1680' | '\\u180E'\n" +
" | '\\u2000'..'\\u200A'\n" +
" | '\\u202F' | '\\u205F' | '\\u3000'\n" +
" ;\n";
String master =
"grammar Test;\n" +
"import Unicode;\n" +
"\n" +
"program : 'test' 'test' ;\n" +
"\n" +
"WS : (UNICODE_CLASS_Zs)+ -> skip;\n";
mkdir(tmpdir);
writeFile(tmpdir, "Unicode.g4", slave);
String found = execParser("Test.g4", master, "TestParser", "TestLexer", "program", "test test", debug);
assertEquals("", found);
assertNull(stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#670 "exception when importing
* grammar".
* https://github.com/antlr/antlr4/issues/670
*/
@Test
public void testImportLargeGrammar() throws Exception {
String slave = load("Java.g4", "UTF-8");
String master =
"grammar NewJava;\n" +
"import Java;\n";
System.out.println("dir "+tmpdir);
mkdir(tmpdir);
writeFile(tmpdir, "Java.g4", slave);
String found = execParser("NewJava.g4", master, "NewJavaParser", "NewJavaLexer", "compilationUnit", "package Foo;", debug);
assertEquals("", found);
assertNull(stderrDuringParse);
}
}

View File

@ -1,356 +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;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/*
cover these cases:
dead end
single alt
single alt + preds
conflict
conflict + preds
*/
public class TestFullContextParsing extends BaseTest {
@Test public void testAmbigYieldsCtxSensitiveDFA() {
String grammar =
"grammar T;\n"+
"s" +
"@after {dumpDFA();}\n" +
" : ID | ID {;} ;\n" +
"ID : 'a'..'z'+ ;\n"+
"WS : (' '|'\\t'|'\\n')+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"abc", true);
String expecting =
"Decision 0:\n" +
"s0-ID->:s1^=>1\n"; // ctx sensitive
assertEquals(expecting, result);
assertEquals("line 1:0 reportAttemptingFullContext d=0 (s), input='abc'\n",
this.stderrDuringParse);
}
public String testCtxSensitiveDFA(String input) {
String grammar =
"grammar T;\n"+
"s @after {dumpDFA();}\n" +
" : '$' a | '@' b ;\n" +
"a : e ID ;\n" +
"b : e INT ID ;\n" +
"e : INT | ;\n" +
"ID : 'a'..'z'+ ;\n"+
"INT : '0'..'9'+ ;\n"+
"WS : (' '|'\\t'|'\\n')+ -> skip ;\n";
return execParser("T.g4", grammar, "TParser", "TLexer", "s", input, true);
}
@Test
public void testCtxSensitiveDFA1() {
String result = testCtxSensitiveDFA("$ 34 abc");
String expecting =
"Decision 1:\n" +
"s0-INT->s1\n" +
"s1-ID->:s2^=>1\n";
assertEquals(expecting, result);
assertEquals("line 1:5 reportAttemptingFullContext d=1 (e), input='34abc'\n" +
"line 1:2 reportContextSensitivity d=1 (e), input='34'\n",
this.stderrDuringParse);
}
@Test
public void testCtxSensitiveDFA2() {
String result = testCtxSensitiveDFA("@ 34 abc");
String expecting =
"Decision 1:\n" +
"s0-INT->s1\n" +
"s1-ID->:s2^=>1\n";
assertEquals(expecting, result);
assertEquals("line 1:5 reportAttemptingFullContext d=1 (e), input='34abc'\n" +
"line 1:5 reportContextSensitivity d=1 (e), input='34abc'\n",
this.stderrDuringParse);
}
@Test public void testCtxSensitiveDFATwoDiffInput() {
String grammar =
"grammar T;\n"+
"s @after {dumpDFA();}\n" +
" : ('$' a | '@' b)+ ;\n" +
"a : e ID ;\n" +
"b : e INT ID ;\n" +
"e : INT | ;\n" +
"ID : 'a'..'z'+ ;\n"+
"INT : '0'..'9'+ ;\n"+
"WS : (' '|'\\t'|'\\n')+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"$ 34 abc @ 34 abc", true);
String expecting =
"Decision 2:\n" +
"s0-INT->s1\n" +
"s1-ID->:s2^=>1\n";
assertEquals(expecting, result);
assertEquals("line 1:5 reportAttemptingFullContext d=2 (e), input='34abc'\n" +
"line 1:2 reportContextSensitivity d=2 (e), input='34'\n" +
"line 1:14 reportAttemptingFullContext d=2 (e), input='34abc'\n" +
"line 1:14 reportContextSensitivity d=2 (e), input='34abc'\n",
this.stderrDuringParse);
}
@Test
public void testSLLSeesEOFInLLGrammar() {
String grammar =
"grammar T;\n"+
"s @after {dumpDFA();}\n" +
" : a ;\n" +
"a : e ID ;\n" +
"b : e INT ID ;\n" +
"e : INT | ;\n" +
"ID : 'a'..'z'+ ;\n"+
"INT : '0'..'9'+ ;\n"+
"WS : (' '|'\\t'|'\\n')+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"34 abc", true);
String expecting =
"Decision 0:\n" +
"s0-INT->s1\n" +
"s1-ID->:s2^=>1\n"; // Must point at accept state
assertEquals(expecting, result);
assertEquals("line 1:3 reportAttemptingFullContext d=0 (e), input='34abc'\n" +
"line 1:0 reportContextSensitivity d=0 (e), input='34'\n",
this.stderrDuringParse);
}
@Test public void testFullContextIF_THEN_ELSEParse() {
String grammar =
"grammar T;\n"+
"s" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
"@after {dumpDFA();}\n" +
" : '{' stat* '}'" +
" ;\n" +
"stat: 'if' ID 'then' stat ('else' ID)?\n" +
" | 'return'\n" +
" ;" +
"ID : 'a'..'z'+ ;\n"+
"WS : (' '|'\\t'|'\\n')+ -> skip ;\n";
String input = "{ if x then return }";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
input, true);
String expecting =
"Decision 1:\n" +
"s0-'}'->:s1=>2\n";
assertEquals(expecting, result);
assertEquals(null, this.stderrDuringParse);
input = "{ if x then return else foo }";
result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
input, true);
expecting =
"Decision 1:\n" +
"s0-'else'->:s1^=>1\n";
assertEquals(expecting, result);
// Technically, this input sequence is not ambiguous because else
// uniquely predicts going into the optional subrule. else cannot
// be matched by exiting stat since that would only match '}' or
// the start of a stat. But, we are using the theory that
// SLL(1)=LL(1) and so we are avoiding full context parsing
// by declaring all else clause parsing to be ambiguous.
assertEquals("line 1:19 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 1:19 reportContextSensitivity d=1 (stat), input='else'\n",
this.stderrDuringParse);
input =
"{ if x then if y then return else foo }";
result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
input, true);
expecting =
"Decision 1:\n" +
"s0-'}'->:s2=>2\n" +
"s0-'else'->:s1^=>1\n";
assertEquals(expecting, result);
assertEquals("line 1:29 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 1:38 reportAmbiguity d=1 (stat): ambigAlts={1, 2}, input='elsefoo}'\n",
this.stderrDuringParse);
// should not be ambiguous because the second 'else bar' clearly
// indicates that the first else should match to the innermost if.
// LL_EXACT_AMBIG_DETECTION makes us keep going to resolve
input =
"{ if x then if y then return else foo else bar }";
result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
input, true);
expecting =
"Decision 1:\n" +
"s0-'else'->:s1^=>1\n";
assertEquals(expecting, result);
assertEquals("line 1:29 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 1:38 reportContextSensitivity d=1 (stat), input='elsefooelse'\n" +
"line 1:38 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 1:38 reportContextSensitivity d=1 (stat), input='else'\n",
this.stderrDuringParse);
input =
"{ if x then return else foo\n" +
"if x then if y then return else foo }";
result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
input, true);
expecting =
"Decision 1:\n" +
"s0-'}'->:s2=>2\n" +
"s0-'else'->:s1^=>1\n";
assertEquals(expecting, result);
assertEquals("line 1:19 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 1:19 reportContextSensitivity d=1 (stat), input='else'\n" +
"line 2:27 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 2:36 reportAmbiguity d=1 (stat): ambigAlts={1, 2}, input='elsefoo}'\n",
this.stderrDuringParse);
input =
"{ if x then return else foo\n" +
"if x then if y then return else foo }";
result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
input, true);
expecting =
"Decision 1:\n" +
"s0-'}'->:s2=>2\n" +
"s0-'else'->:s1^=>1\n";
assertEquals(expecting, result);
assertEquals("line 1:19 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 1:19 reportContextSensitivity d=1 (stat), input='else'\n" +
"line 2:27 reportAttemptingFullContext d=1 (stat), input='else'\n" +
"line 2:36 reportAmbiguity d=1 (stat): ambigAlts={1, 2}, input='elsefoo}'\n",
this.stderrDuringParse);
}
/**
* Tests predictions for the following case involving closures.
* http://www.antlr.org/wiki/display/~admin/2011/12/29/Flaw+in+ANTLR+v3+LL(*)+analysis+algorithm
*/
@Test
public void testLoopsSimulateTailRecursion() throws Exception {
String grammar =
"grammar T;\n" +
"prog\n" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
" : expr_or_assign*;\n" +
"expr_or_assign\n" +
" : expr '++' {System.out.println(\"fail.\");}\n" +
" | expr {System.out.println(\"pass: \"+$expr.text);}\n" +
" ;\n" +
"expr: expr_primary ('<-' ID)? ;\n" +
"expr_primary\n" +
" : '(' ID ')'\n" +
" | ID '(' ID ')'\n" +
" | ID\n" +
" ;\n" +
"ID : [a-z]+ ;\n" +
"";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "prog", "a(i)<-x", true);
assertEquals("pass: a(i)<-x\n", found);
String expecting =
"line 1:3 reportAttemptingFullContext d=3 (expr_primary), input='a(i)'\n" +
"line 1:7 reportAmbiguity d=3 (expr_primary): ambigAlts={2, 3}, input='a(i)<-x'\n";
assertEquals(expecting, this.stderrDuringParse);
}
@Test
public void testAmbiguityNoLoop() throws Exception {
// simpler version of testLoopsSimulateTailRecursion, no loops
String grammar =
"grammar T;\n" +
"prog\n" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
" : expr expr {System.out.println(\"alt 1\");}\n" +
" | expr\n" +
" ;\n" +
"expr: '@'\n" +
" | ID '@'\n" +
" | ID\n" +
" ;\n" +
"ID : [a-z]+ ;\n" +
"WS : [ \\r\\n\\t]+ -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "prog", "a@", true);
assertEquals("alt 1\n", found);
String expecting =
"line 1:2 reportAttemptingFullContext d=0 (prog), input='a@'\n" +
"line 1:2 reportAmbiguity d=0 (prog): ambigAlts={1, 2}, input='a@'\n" +
"line 1:2 reportAttemptingFullContext d=1 (expr), input='a@'\n" +
"line 1:2 reportContextSensitivity d=1 (expr), input='a@'\n";
assertEquals(expecting, this.stderrDuringParse);
}
@Test
public void testExprAmbiguity() throws Exception {
// translated left-recursive expr rule to test ambig detection
String grammar =
"grammar T;\n" +
"s\n" +
"@init {_interp.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);}\n" +
" : expr[0] {System.out.println($expr.ctx.toStringTree(this));} ;\n" +
"\n" +
"expr[int _p]\n" +
" : ID\n" +
" ( {5 >= $_p}? '*' expr[6]\n" +
" | {4 >= $_p}? '+' expr[5]\n" +
" )*\n" +
" ;\n" +
"\n" +
"ID : [a-zA-Z]+ ; // match identifiers\n" +
"WS : [ \\t\\r\\n]+ -> skip ; // toss out whitespace\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a+b", true);
assertEquals("(expr a + (expr b))\n", found);
String expecting =
"line 1:1 reportAttemptingFullContext d=1 (expr), input='+'\n" +
"line 1:2 reportContextSensitivity d=1 (expr), input='+b'\n";
assertEquals(expecting, this.stderrDuringParse);
found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a+b*c", true);
assertEquals("(expr a + (expr b * (expr c)))\n", found);
expecting =
"line 1:1 reportAttemptingFullContext d=1 (expr), input='+'\n" +
"line 1:2 reportContextSensitivity d=1 (expr), input='+b'\n" +
"line 1:3 reportAttemptingFullContext d=1 (expr), input='*'\n" +
"line 1:5 reportAmbiguity d=1 (expr): ambigAlts={1, 2}, input='*c'\n";
assertEquals(expecting, this.stderrDuringParse);
}
}

View File

@ -1,732 +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;
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" +
"s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" +
"a : a ID\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String expected =
"error(" + ErrorType.NO_NON_LR_ALTS.code + "): T.g4:3:0: left recursive rule a must contain an alternative which is not left recursive\n";
testErrors(new String[] { grammar, expected }, false);
}
@Test public void testCheckForLeftRecursiveEmptyFollow() throws Exception {
String grammar =
"grammar T;\n" +
"s @after {System.out.println($ctx.toStringTree(this));} : a ;\n" +
"a : a ID?\n" +
" | ID\n" +
" ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String expected =
"error(" + ErrorType.EPSILON_LR_FOLLOW.code + "): T.g4:3:0: left recursive rule a contains a left recursive alternative which can be followed by the empty string\n";
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);
}
}
}

View File

@ -1,213 +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;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestLexerErrors extends BaseTest {
// TEST DETECTION
@Test public void testInvalidCharAtStart() throws Exception {
String grammar =
"lexer grammar L;\n" +
"A : 'a' 'b' ;\n";
String tokens = execLexer("L.g4", grammar, "L", "x");
String expectingTokens =
"[@0,1:0='<EOF>',<-1>,1:1]\n";
assertEquals(expectingTokens, tokens);
String expectingError = "line 1:0 token recognition error at: 'x'\n";
String error = stderrDuringParse;
assertEquals(expectingError, error);
}
@Test
public void testStringsEmbeddedInActions() {
String grammar =
"lexer grammar Actions;\n"
+ "ACTION2 : '[' (STRING | ~'\"')*? ']';\n"
+ "STRING : '\"' ('\\\"' | .)*? '\"';\n"
+ "WS : [ \\t\\r\\n]+ -> skip;\n";
String tokens = execLexer("Actions.g4", grammar, "Actions", "[\"foo\"]");
String expectingTokens =
"[@0,0:6='[\"foo\"]',<1>,1:0]\n" +
"[@1,7:6='<EOF>',<-1>,1:7]\n";
assertEquals(expectingTokens, tokens);
assertNull(stderrDuringParse);
tokens = execLexer("Actions.g4", grammar, "Actions", "[\"foo]");
expectingTokens =
"[@0,6:5='<EOF>',<-1>,1:6]\n";
assertEquals(expectingTokens, tokens);
assertEquals("line 1:0 token recognition error at: '[\"foo]'\n", stderrDuringParse);
}
@Test public void testEnforcedGreedyNestedBrances() {
String grammar =
"lexer grammar R;\n"
+ "ACTION : '{' (ACTION | ~[{}])* '}';\n"
+ "WS : [ \\r\\n\\t]+ -> skip;\n";
String tokens = execLexer("R.g4", grammar, "R", "{ { } }");
String expectingTokens =
"[@0,0:6='{ { } }',<1>,1:0]\n" +
"[@1,7:6='<EOF>',<-1>,1:7]\n";
assertEquals(expectingTokens, tokens);
assertEquals(null, stderrDuringParse);
tokens = execLexer("R.g4", grammar, "R", "{ { }");
expectingTokens =
"[@0,5:4='<EOF>',<-1>,1:5]\n";
assertEquals(expectingTokens, tokens);
assertEquals("line 1:0 token recognition error at: '{ { }'\n", stderrDuringParse);
}
@Test public void testInvalidCharAtStartAfterDFACache() throws Exception {
String grammar =
"lexer grammar L;\n" +
"A : 'a' 'b' ;\n";
String tokens = execLexer("L.g4", grammar, "L", "abx");
String expectingTokens =
"[@0,0:1='ab',<1>,1:0]\n" +
"[@1,3:2='<EOF>',<-1>,1:3]\n";
assertEquals(expectingTokens, tokens);
String expectingError = "line 1:2 token recognition error at: 'x'\n";
String error = stderrDuringParse;
assertEquals(expectingError, error);
}
@Test public void testInvalidCharInToken() throws Exception {
String grammar =
"lexer grammar L;\n" +
"A : 'a' 'b' ;\n";
String tokens = execLexer("L.g4", grammar, "L", "ax");
String expectingTokens =
"[@0,2:1='<EOF>',<-1>,1:2]\n";
assertEquals(expectingTokens, tokens);
String expectingError = "line 1:0 token recognition error at: 'ax'\n";
String error = stderrDuringParse;
assertEquals(expectingError, error);
}
@Test public void testInvalidCharInTokenAfterDFACache() throws Exception {
String grammar =
"lexer grammar L;\n" +
"A : 'a' 'b' ;\n";
String tokens = execLexer("L.g4", grammar, "L", "abax");
String expectingTokens =
"[@0,0:1='ab',<1>,1:0]\n" +
"[@1,4:3='<EOF>',<-1>,1:4]\n";
assertEquals(expectingTokens, tokens);
String expectingError = "line 1:2 token recognition error at: 'ax'\n";
String error = stderrDuringParse;
assertEquals(expectingError, error);
}
@Test public void testDFAToATNThatFailsBackToDFA() throws Exception {
String grammar =
"lexer grammar L;\n" +
"A : 'ab' ;\n"+
"B : 'abc' ;\n";
// The first ab caches the DFA then abx goes through the DFA but
// into the ATN for the x, which fails. Must go back into DFA
// and return to previous dfa accept state
String tokens = execLexer("L.g4", grammar, "L", "ababx");
String expectingTokens =
"[@0,0:1='ab',<1>,1:0]\n" +
"[@1,2:3='ab',<1>,1:2]\n" +
"[@2,5:4='<EOF>',<-1>,1:5]\n";
assertEquals(expectingTokens, tokens);
String expectingError = "line 1:4 token recognition error at: 'x'\n";
String error = stderrDuringParse;
assertEquals(expectingError, error);
}
@Test public void testDFAToATNThatMatchesThenFailsInATN() throws Exception {
String grammar =
"lexer grammar L;\n" +
"A : 'ab' ;\n"+
"B : 'abc' ;\n"+
"C : 'abcd' ;\n";
// The first ab caches the DFA then abx goes through the DFA but
// into the ATN for the c. It marks that hasn't except state
// and then keeps going in the ATN. It fails on the x, but
// uses the previous accepted in the ATN not DFA
String tokens = execLexer("L.g4", grammar, "L", "ababcx");
String expectingTokens =
"[@0,0:1='ab',<1>,1:0]\n" +
"[@1,2:4='abc',<2>,1:2]\n" +
"[@2,6:5='<EOF>',<-1>,1:6]\n";
assertEquals(expectingTokens, tokens);
String expectingError = "line 1:5 token recognition error at: 'x'\n";
String error = stderrDuringParse;
assertEquals(expectingError, error);
}
@Test public void testErrorInMiddle() throws Exception {
String grammar =
"lexer grammar L;\n" +
"A : 'abc' ;\n";
String tokens = execLexer("L.g4", grammar, "L", "abx");
String expectingTokens =
"[@0,3:2='<EOF>',<-1>,1:3]\n";
assertEquals(expectingTokens, tokens);
String expectingError = "line 1:0 token recognition error at: 'abx'\n";
String error = stderrDuringParse;
assertEquals(expectingError, error);
}
// TEST RECOVERY
/**
* This is a regression test for #45 "NullPointerException in LexerATNSimulator.execDFA".
* https://github.com/antlr/antlr4/issues/46
*/
@Test
public void testLexerExecDFA() throws Exception {
String grammar =
"grammar T;\n" +
"start : ID ':' expr;\n" +
"expr : primary expr? {} | expr '->' ID;\n" +
"primary : ID;\n" +
"ID : [a-z]+;\n" +
"\n";
String result = execLexer("T.g4", grammar, "TLexer", "x : x", false);
String expecting =
"[@0,0:0='x',<3>,1:0]\n" +
"[@1,2:2=':',<1>,1:2]\n" +
"[@2,4:4='x',<3>,1:4]\n" +
"[@3,5:4='<EOF>',<-1>,1:5]\n";
assertEquals(expecting, result);
assertEquals("line 1:1 token recognition error at: ' '\n" +
"line 1:3 token recognition error at: ' '\n",
this.stderrDuringParse);
}
}

View File

@ -1,690 +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;
import org.antlr.v4.runtime.misc.Nullable;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class TestLexerExec extends BaseTest {
@Test public void testQuoteTranslation() throws Exception {
String grammar =
"lexer grammar L;\n"+
"QUOTE : '\"' ;\n"; // make sure this compiles
String found = execLexer("L.g4", grammar, "L", "\"");
String expecting =
"[@0,0:0='\"',<1>,1:0]\n" +
"[@1,1:0='<EOF>',<-1>,1:1]\n";
assertEquals(expecting, found);
}
@Test public void testRefToRuleDoesNotSetTokenNorEmitAnother() throws Exception {
String grammar =
"lexer grammar L;\n"+
"A : '-' I ;\n" +
"I : '0'..'9'+ ;\n"+
"WS : (' '|'\\n') -> skip ;";
String found = execLexer("L.g4", grammar, "L", "34 -21 3");
String expecting =
"[@0,0:1='34',<2>,1:0]\n" +
"[@1,3:5='-21',<1>,1:3]\n" +
"[@2,7:7='3',<2>,1:7]\n" +
"[@3,8:7='<EOF>',<-1>,1:8]\n"; // EOF has no length so range is 8:7 not 8:8
assertEquals(expecting, found);
}
@Test public void testSlashes() throws Exception {
String grammar =
"lexer grammar L;\n"+
"Backslash : '\\\\';\n" +
"Slash : '/';\n" +
"Vee : '\\\\/';\n" +
"Wedge : '/\\\\';\n"+
"WS : [ \\t] -> skip;";
String found = execLexer("L.g4", grammar, "L", "\\ / \\/ /\\");
String expecting =
"[@0,0:0='\\',<1>,1:0]\n" +
"[@1,2:2='/',<2>,1:2]\n" +
"[@2,4:5='\\/',<3>,1:4]\n" +
"[@3,7:8='/\\',<4>,1:7]\n" +
"[@4,9:8='<EOF>',<-1>,1:9]\n";
assertEquals(expecting, found);
}
/**
* This is a regression test for antlr/antlr4#224: "Parentheses without
* quantifier in lexer rules have unclear effect".
* https://github.com/antlr/antlr4/issues/224
*/
@Test public void testParentheses() {
String grammar =
"lexer grammar Demo;\n" +
"\n" +
"START_BLOCK: '-.-.-';\n" +
"\n" +
"ID : (LETTER SEPARATOR) (LETTER SEPARATOR)+;\n" +
"fragment LETTER: L_A|L_K;\n" +
"fragment L_A: '.-';\n" +
"fragment L_K: '-.-';\n" +
"\n" +
"SEPARATOR: '!';\n";
String found = execLexer("Demo.g4", grammar, "Demo", "-.-.-!");
String expecting =
"[@0,0:4='-.-.-',<1>,1:0]\n" +
"[@1,5:5='!',<3>,1:5]\n" +
"[@2,6:5='<EOF>',<-1>,1:6]\n";
assertEquals(expecting, found);
}
@Test
public void testNonGreedyTermination() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "STRING : '\"' ('\"\"' | .)*? '\"';";
String found = execLexer("L.g4", grammar, "L", "\"hi\"\"mom\"");
assertEquals(
"[@0,0:3='\"hi\"',<1>,1:0]\n" +
"[@1,4:8='\"mom\"',<1>,1:4]\n" +
"[@2,9:8='<EOF>',<-1>,1:9]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testNonGreedyTermination2() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "STRING : '\"' ('\"\"' | .)+? '\"';";
String found = execLexer("L.g4", grammar, "L", "\"\"\"mom\"");
assertEquals(
"[@0,0:6='\"\"\"mom\"',<1>,1:0]\n" +
"[@1,7:6='<EOF>',<-1>,1:7]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testGreedyOptional() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "CMT : '//' .*? '\\n' CMT?;\n"
+ "WS : (' '|'\\t')+;";
String found = execLexer("L.g4", grammar, "L", "//blah\n//blah\n");
assertEquals(
"[@0,0:13='//blah\\n//blah\\n',<1>,1:0]\n" +
"[@1,14:13='<EOF>',<-1>,3:0]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testNonGreedyOptional() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "CMT : '//' .*? '\\n' CMT??;\n"
+ "WS : (' '|'\\t')+;";
String found = execLexer("L.g4", grammar, "L", "//blah\n//blah\n");
assertEquals(
"[@0,0:6='//blah\\n',<1>,1:0]\n" +
"[@1,7:13='//blah\\n',<1>,2:0]\n" +
"[@2,14:13='<EOF>',<-1>,3:0]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testGreedyClosure() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "CMT : '//' .*? '\\n' CMT*;\n"
+ "WS : (' '|'\\t')+;";
String found = execLexer("L.g4", grammar, "L", "//blah\n//blah\n");
assertEquals(
"[@0,0:13='//blah\\n//blah\\n',<1>,1:0]\n" +
"[@1,14:13='<EOF>',<-1>,3:0]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testNonGreedyClosure() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "CMT : '//' .*? '\\n' CMT*?;\n"
+ "WS : (' '|'\\t')+;";
String found = execLexer("L.g4", grammar, "L", "//blah\n//blah\n");
assertEquals(
"[@0,0:6='//blah\\n',<1>,1:0]\n" +
"[@1,7:13='//blah\\n',<1>,2:0]\n" +
"[@2,14:13='<EOF>',<-1>,3:0]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testGreedyPositiveClosure() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "CMT : ('//' .*? '\\n')+;\n"
+ "WS : (' '|'\\t')+;";
String found = execLexer("L.g4", grammar, "L", "//blah\n//blah\n");
assertEquals(
"[@0,0:13='//blah\\n//blah\\n',<1>,1:0]\n" +
"[@1,14:13='<EOF>',<-1>,3:0]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testNonGreedyPositiveClosure() throws Exception {
String grammar =
"lexer grammar L;\n"
+ "CMT : ('//' .*? '\\n')+?;\n"
+ "WS : (' '|'\\t')+;";
String found = execLexer("L.g4", grammar, "L", "//blah\n//blah\n");
assertEquals(
"[@0,0:6='//blah\\n',<1>,1:0]\n" +
"[@1,7:13='//blah\\n',<1>,2:0]\n" +
"[@2,14:13='<EOF>',<-1>,3:0]\n", found);
assertNull(stderrDuringParse);
}
@Test
public void testRecursiveLexerRuleRefWithWildcardStar1() throws Exception {
String grammar =
"lexer grammar L;\n"+
"CMT : '/*' (CMT | .)*? '*/' ;\n" +
"WS : (' '|'\\n')+ ;\n"
/*+ "ANY : .;"*/;
String expecting =
"[@0,0:8='/* ick */',<1>,1:0]\n" +
"[@1,9:9='\\n',<2>,1:9]\n" +
"[@2,10:34='/* /* */\\n/* /*nested*/ */',<1>,2:0]\n" +
"[@3,35:35='\\n',<2>,3:16]\n" +
"[@4,36:35='<EOF>',<-1>,4:0]\n";
// stuff on end of comment matches another rule
String found = execLexer("L.g4", grammar, "L",
"/* ick */\n" +
"/* /* */\n" +
"/* /*nested*/ */\n");
assertEquals(expecting, found);
assertNull(stderrDuringParse);
}
@Test
public void testRecursiveLexerRuleRefWithWildcardStar2() throws Exception {
String grammar =
"lexer grammar L;\n"+
"CMT : '/*' (CMT | .)*? '*/' ;\n" +
"WS : (' '|'\\n')+ ;\n"
/*+ "ANY : .;"*/;
// stuff on end of comment doesn't match another rule
String expecting =
"[@0,0:8='/* ick */',<1>,1:0]\n" +
"[@1,10:10='\\n',<2>,1:10]\n" +
"[@2,11:36='/* /* */x\\n/* /*nested*/ */',<1>,2:0]\n" +
"[@3,38:38='\\n',<2>,3:17]\n" +
"[@4,39:38='<EOF>',<-1>,4:0]\n";
String found = execLexer("L.g4", grammar, "L",
"/* ick */x\n" +
"/* /* */x\n" +
"/* /*nested*/ */x\n");
assertEquals(expecting, found);
assertEquals(
"line 1:9 token recognition error at: 'x'\n" +
"line 3:16 token recognition error at: 'x'\n", stderrDuringParse);
}
@Test
public void testRecursiveLexerRuleRefWithWildcardPlus1() throws Exception {
String grammar =
"lexer grammar L;\n"+
"CMT : '/*' (CMT | .)+? '*/' ;\n" +
"WS : (' '|'\\n')+ ;\n"
/*+ "ANY : .;"*/;
String expecting =
"[@0,0:8='/* ick */',<1>,1:0]\n" +
"[@1,9:9='\\n',<2>,1:9]\n" +
"[@2,10:34='/* /* */\\n/* /*nested*/ */',<1>,2:0]\n" +
"[@3,35:35='\\n',<2>,3:16]\n" +
"[@4,36:35='<EOF>',<-1>,4:0]\n";
// stuff on end of comment matches another rule
String found = execLexer("L.g4", grammar, "L",
"/* ick */\n" +
"/* /* */\n" +
"/* /*nested*/ */\n");
assertEquals(expecting, found);
assertNull(stderrDuringParse);
}
@Test
public void testRecursiveLexerRuleRefWithWildcardPlus2() throws Exception {
String grammar =
"lexer grammar L;\n"+
"CMT : '/*' (CMT | .)+? '*/' ;\n" +
"WS : (' '|'\\n')+ ;\n"
/*+ "ANY : .;"*/;
// stuff on end of comment doesn't match another rule
String expecting =
"[@0,0:8='/* ick */',<1>,1:0]\n" +
"[@1,10:10='\\n',<2>,1:10]\n" +
"[@2,11:36='/* /* */x\\n/* /*nested*/ */',<1>,2:0]\n" +
"[@3,38:38='\\n',<2>,3:17]\n" +
"[@4,39:38='<EOF>',<-1>,4:0]\n";
String found = execLexer("L.g4", grammar, "L",
"/* ick */x\n" +
"/* /* */x\n" +
"/* /*nested*/ */x\n");
assertEquals(expecting, found);
assertEquals(
"line 1:9 token recognition error at: 'x'\n" +
"line 3:16 token recognition error at: 'x'\n", stderrDuringParse);
}
@Test public void testActionPlacement() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : ({System.out.println(\"stuff fail: \" + getText());} 'a' | {System.out.println(\"stuff0: \" + getText());} 'a' {System.out.println(\"stuff1: \" + getText());} 'b' {System.out.println(\"stuff2: \" + getText());}) {System.out.println(getText());} ;\n"+
"WS : (' '|'\\n') -> skip ;\n" +
"J : .;\n";
String found = execLexer("L.g4", grammar, "L", "ab");
String expecting =
"stuff0: \n" +
"stuff1: a\n" +
"stuff2: ab\n" +
"ab\n" +
"[@0,0:1='ab',<1>,1:0]\n" +
"[@1,2:1='<EOF>',<-1>,1:2]\n";
assertEquals(expecting, found);
}
@Test public void testGreedyConfigs() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : ('a' | 'ab') {System.out.println(getText());} ;\n"+
"WS : (' '|'\\n') -> skip ;\n" +
"J : .;\n";
String found = execLexer("L.g4", grammar, "L", "ab");
String expecting =
"ab\n" +
"[@0,0:1='ab',<1>,1:0]\n" +
"[@1,2:1='<EOF>',<-1>,1:2]\n";
assertEquals(expecting, found);
}
@Test public void testNonGreedyConfigs() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : .*? ('a' | 'ab') {System.out.println(getText());} ;\n"+
"WS : (' '|'\\n') -> skip ;\n" +
"J : . {System.out.println(getText());};\n";
String found = execLexer("L.g4", grammar, "L", "ab");
String expecting =
"a\n" +
"b\n" +
"[@0,0:0='a',<1>,1:0]\n" +
"[@1,1:1='b',<3>,1:1]\n" +
"[@2,2:1='<EOF>',<-1>,1:2]\n";
assertEquals(expecting, found);
}
@Test public void testKeywordID() throws Exception {
String grammar =
"lexer grammar L;\n"+
"KEND : 'end' ;\n" + // has priority
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n')+ ;";
String found = execLexer("L.g4", grammar, "L", "end eend ending a");
String expecting =
"[@0,0:2='end',<1>,1:0]\n" +
"[@1,3:3=' ',<3>,1:3]\n" +
"[@2,4:7='eend',<2>,1:4]\n" +
"[@3,8:8=' ',<3>,1:8]\n" +
"[@4,9:14='ending',<2>,1:9]\n" +
"[@5,15:15=' ',<3>,1:15]\n" +
"[@6,16:16='a',<2>,1:16]\n" +
"[@7,17:16='<EOF>',<-1>,1:17]\n";
assertEquals(expecting, found);
}
@Test public void testHexVsID() throws Exception {
String grammar =
"lexer grammar L;\n"+
"HexLiteral : '0' ('x'|'X') HexDigit+ ;\n"+
"DecimalLiteral : ('0' | '1'..'9' '0'..'9'*) ;\n" +
"FloatingPointLiteral : ('0x' | '0X') HexDigit* ('.' HexDigit*)? ;\n" +
"DOT : '.' ;\n" +
"ID : 'a'..'z'+ ;\n" +
"fragment HexDigit : ('0'..'9'|'a'..'f'|'A'..'F') ;\n" +
"WS : (' '|'\\n')+ ;";
String found = execLexer("L.g4", grammar, "L", "x 0 1 a.b a.l");
String expecting =
"[@0,0:0='x',<5>,1:0]\n" +
"[@1,1:1=' ',<6>,1:1]\n" +
"[@2,2:2='0',<2>,1:2]\n" +
"[@3,3:3=' ',<6>,1:3]\n" +
"[@4,4:4='1',<2>,1:4]\n" +
"[@5,5:5=' ',<6>,1:5]\n" +
"[@6,6:6='a',<5>,1:6]\n" +
"[@7,7:7='.',<4>,1:7]\n" +
"[@8,8:8='b',<5>,1:8]\n" +
"[@9,9:9=' ',<6>,1:9]\n" +
"[@10,10:10='a',<5>,1:10]\n" +
"[@11,11:11='.',<4>,1:11]\n" +
"[@12,12:12='l',<5>,1:12]\n" +
"[@13,13:12='<EOF>',<-1>,1:13]\n";
assertEquals(expecting, found);
}
// must get DONE EOF
@Test public void testEOFByItself() throws Exception {
String grammar =
"lexer grammar L;\n" +
"DONE : EOF ;\n" +
"A : 'a';\n";
String found = execLexer("L.g4", grammar, "L", "");
String expecting =
"[@0,0:-1='<EOF>',<1>,1:0]\n" +
"[@1,0:-1='<EOF>',<-1>,1:0]\n";
assertEquals(expecting, found);
}
@Test public void testEOFSuffixInFirstRule() throws Exception {
String grammar =
"lexer grammar L;\n"+
"A : 'a' EOF ;\n"+
"B : 'a';\n"+
"C : 'c';\n";
String found = execLexer("L.g4", grammar, "L", "");
String expecting =
"[@0,0:-1='<EOF>',<-1>,1:0]\n";
assertEquals(expecting, found);
found = execLexer("L.g4", grammar, "L", "a");
expecting =
"[@0,0:0='a',<1>,1:0]\n" +
"[@1,1:0='<EOF>',<-1>,1:1]\n";
assertEquals(expecting, found);
}
@Test public void testCharSet() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : '0'..'9'+ {System.out.println(\"I\");} ;\n"+
"WS : [ \\n\\u000D] -> skip ;";
String found = execLexer("L.g4", grammar, "L", "34\r\n 34");
String expecting =
"I\n" +
"I\n" +
"[@0,0:1='34',<1>,1:0]\n" +
"[@1,5:6='34',<1>,2:1]\n" +
"[@2,7:6='<EOF>',<-1>,2:3]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetPlus() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : '0'..'9'+ {System.out.println(\"I\");} ;\n"+
"WS : [ \\n\\u000D]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "34\r\n 34");
String expecting =
"I\n" +
"I\n" +
"[@0,0:1='34',<1>,1:0]\n" +
"[@1,5:6='34',<1>,2:1]\n" +
"[@2,7:6='<EOF>',<-1>,2:3]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetNot() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : ~[ab \\n] ~[ \\ncd]* {System.out.println(\"I\");} ;\n"+
"WS : [ \\n\\u000D]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "xaf");
String expecting =
"I\n" +
"[@0,0:2='xaf',<1>,1:0]\n" +
"[@1,3:2='<EOF>',<-1>,1:3]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetInSet() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : (~[ab \\n]|'a') {System.out.println(\"I\");} ;\n"+
"WS : [ \\n\\u000D]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "a x");
String expecting =
"I\n" +
"I\n" +
"[@0,0:0='a',<1>,1:0]\n" +
"[@1,2:2='x',<1>,1:2]\n" +
"[@2,3:2='<EOF>',<-1>,1:3]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetRange() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : [0-9]+ {System.out.println(\"I\");} ;\n"+
"ID : [a-zA-Z] [a-zA-Z0-9]* {System.out.println(\"ID\");} ;\n"+
"WS : [ \\n\\u0009\\r]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "34\r 34 a2 abc \n ");
String expecting =
"I\n" +
"I\n" +
"ID\n" +
"ID\n" +
"[@0,0:1='34',<1>,1:0]\n" +
"[@1,4:5='34',<1>,1:4]\n" +
"[@2,7:8='a2',<2>,1:7]\n" +
"[@3,10:12='abc',<2>,1:10]\n" +
"[@4,18:17='<EOF>',<-1>,2:3]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetWithMissingEndRange() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : [0-]+ {System.out.println(\"I\");} ;\n"+
"WS : [ \\n\\u000D]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "00\r\n");
String expecting =
"I\n" +
"[@0,0:1='00',<1>,1:0]\n" +
"[@1,4:3='<EOF>',<-1>,2:0]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetWithMissingEscapeChar() throws Exception {
String grammar =
"lexer grammar L;\n"+
"I : [0-9]+ {System.out.println(\"I\");} ;\n"+
"WS : [ \\u]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "34 ");
String expecting =
"I\n" +
"[@0,0:1='34',<1>,1:0]\n" +
"[@1,3:2='<EOF>',<-1>,1:3]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetWithEscapedChar() throws Exception {
String grammar =
"lexer grammar L;\n"+
"DASHBRACK : [\\-\\]]+ {System.out.println(\"DASHBRACK\");} ;\n"+
"WS : [ \\u]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "- ] ");
String expecting =
"DASHBRACK\n" +
"DASHBRACK\n" +
"[@0,0:0='-',<1>,1:0]\n" +
"[@1,2:2=']',<1>,1:2]\n" +
"[@2,4:3='<EOF>',<-1>,1:4]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetWithReversedRange() throws Exception {
String grammar =
"lexer grammar L;\n"+
"A : [z-a9]+ {System.out.println(\"A\");} ;\n"+
"WS : [ \\u]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "9");
String expecting =
"A\n" +
"[@0,0:0='9',<1>,1:0]\n" +
"[@1,1:0='<EOF>',<-1>,1:1]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetWithQuote() throws Exception {
String grammar =
"lexer grammar L;\n"+
"A : [\"a-z]+ {System.out.println(\"A\");} ;\n"+
"WS : [ \\n\\t]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "b\"a");
String expecting =
"A\n" +
"[@0,0:2='b\"a',<1>,1:0]\n" +
"[@1,3:2='<EOF>',<-1>,1:3]\n";
assertEquals(expecting, found);
}
@Test public void testCharSetWithQuote2() throws Exception {
String grammar =
"lexer grammar L;\n"+
"A : [\"\\\\ab]+ {System.out.println(\"A\");} ;\n"+
"WS : [ \\n\\t]+ -> skip ;";
String found = execLexer("L.g4", grammar, "L", "b\"\\a");
String expecting =
"A\n" +
"[@0,0:3='b\"\\a',<1>,1:0]\n" +
"[@1,4:3='<EOF>',<-1>,1:4]\n";
assertEquals(expecting, found);
}
@Test
public void testPositionAdjustingLexer() throws Exception {
String grammar = load("PositionAdjustingLexer.g4", null);
String input =
"tokens\n" +
"tokens {\n" +
"notLabel\n" +
"label1 =\n" +
"label2 +=\n" +
"notLabel\n";
String found = execLexer("PositionAdjustingLexer.g4", grammar, "PositionAdjustingLexer", input);
final int TOKENS = 4;
final int LABEL = 5;
final int IDENTIFIER = 6;
String expecting =
"[@0,0:5='tokens',<" + IDENTIFIER + ">,1:0]\n" +
"[@1,7:12='tokens',<" + TOKENS + ">,2:0]\n" +
"[@2,14:14='{',<3>,2:7]\n" +
"[@3,16:23='notLabel',<" + IDENTIFIER + ">,3:0]\n" +
"[@4,25:30='label1',<" + LABEL + ">,4:0]\n" +
"[@5,32:32='=',<1>,4:7]\n" +
"[@6,34:39='label2',<" + LABEL + ">,5:0]\n" +
"[@7,41:42='+=',<2>,5:7]\n" +
"[@8,44:51='notLabel',<" + IDENTIFIER + ">,6:0]\n" +
"[@9,53:52='<EOF>',<-1>,7:0]\n";
assertEquals(expecting, found);
}
/**
* This is a regression test for antlr/antlr4#76 "Serialized ATN strings
* should be split when longer than 2^16 bytes (class file limitation)"
* https://github.com/antlr/antlr4/issues/76
*/
@Test
public void testLargeLexer() throws Exception {
StringBuilder grammar = new StringBuilder();
grammar.append("lexer grammar L;\n");
grammar.append("WS : [ \\t\\r\\n]+ -> skip;\n");
for (int i = 0; i < 4000; i++) {
grammar.append("KW").append(i).append(" : 'KW' '").append(i).append("';\n");
}
String input = "KW400";
String found = execLexer("L.g4", grammar.toString(), "L", input);
String expecting =
"[@0,0:4='KW400',<402>,1:0]\n" +
"[@1,5:4='<EOF>',<-1>,1:5]\n";
assertEquals(expecting, found);
}
/**
* This is a regression test for antlr/antlr4#687 "Empty zero-length tokens
* cannot have lexer commands" and antlr/antlr4#688 "Lexer cannot match
* zero-length tokens"
* https://github.com/antlr/antlr4/issues/687
* https://github.com/antlr/antlr4/issues/688
*/
@Test public void testZeroLengthToken() throws Exception {
String grammar =
"lexer grammar L;\n"+
"\n" +
"BeginString\n" +
" : '\\'' -> more, pushMode(StringMode)\n" +
" ;\n" +
"\n" +
"mode StringMode;\n" +
"\n" +
" StringMode_X : 'x' -> more;\n" +
" StringMode_Done : -> more, mode(EndStringMode);\n" +
"\n" +
"mode EndStringMode; \n" +
"\n" +
" EndString : '\\'' -> popMode;\n";
String found = execLexer("L.g4", grammar, "L", "'xxx'");
String expecting =
"[@0,0:4=''xxx'',<1>,1:0]\n" +
"[@1,5:4='<EOF>',<-1>,1:5]\n";
assertEquals(expecting, found);
}
}

View File

@ -1,226 +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;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestListeners extends BaseTest {
@Test public void testBasic() throws Exception {
String grammar =
"grammar T;\n" +
"@header {import org.antlr.v4.runtime.tree.*;}\n"+
"@parser::members {\n" +
"public static class LeafListener extends TBaseListener {\n" +
" public void visitTerminal(TerminalNode node) {\n" +
" System.out.println(node.getSymbol().getText());\n" +
" }\n" +
" }}\n" +
"s\n" +
"@after {" +
" System.out.println($r.ctx.toStringTree(this));" +
" ParseTreeWalker walker = new ParseTreeWalker();\n" +
" walker.walk(new LeafListener(), $r.ctx);" +
"}\n" +
" : r=a ;\n" +
"a : INT INT" +
" | ID" +
" ;\n" +
"MULT: '*' ;\n" +
"ADD : '+' ;\n" +
"INT : [0-9]+ ;\n" +
"ID : [a-z]+ ;\n" +
"WS : [ \\t\\n]+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "1 2", false);
String expecting = "(a 1 2)\n" +
"1\n" +
"2\n";
assertEquals(expecting, result);
}
@Test public void testTokenGetters() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {\n" +
"public static class LeafListener extends TBaseListener {\n" +
" public void exitA(TParser.AContext ctx) {\n" +
" if (ctx.getChildCount()==2) System.out.printf(\"%s %s %s\",ctx.INT(0).getSymbol().getText(),ctx.INT(1).getSymbol().getText(),ctx.INT());\n" +
" else System.out.println(ctx.ID().getSymbol());\n" +
" }\n" +
" }}\n" +
"s\n" +
"@after {" +
" System.out.println($r.ctx.toStringTree(this));" +
" ParseTreeWalker walker = new ParseTreeWalker();\n" +
" walker.walk(new LeafListener(), $r.ctx);" +
"}\n" +
" : r=a ;\n" +
"a : INT INT" +
" | ID" +
" ;\n" +
"MULT: '*' ;\n" +
"ADD : '+' ;\n" +
"INT : [0-9]+ ;\n" +
"ID : [a-z]+ ;\n" +
"WS : [ \\t\\n]+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "1 2", false);
String expecting =
"(a 1 2)\n" +
"1 2 [1, 2]\n";
assertEquals(expecting, result);
result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "abc", false);
expecting = "(a abc)\n" +
"[@0,0:2='abc',<4>,1:0]\n";
assertEquals(expecting, result);
}
@Test public void testRuleGetters() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {\n" +
"public static class LeafListener extends TBaseListener {\n" +
" public void exitA(TParser.AContext ctx) {\n" +
" if (ctx.getChildCount()==2) {\n" +
" System.out.printf(\"%s %s %s\",ctx.b(0).start.getText(),\n" +
" ctx.b(1).start.getText(),ctx.b().get(0).start.getText());\n" +
" }\n" +
" else System.out.println(ctx.b(0).start.getText());\n" +
" }\n" +
" }}\n" +
"s\n" +
"@after {" +
" System.out.println($r.ctx.toStringTree(this));" +
" ParseTreeWalker walker = new ParseTreeWalker();\n" +
" walker.walk(new LeafListener(), $r.ctx);" +
"}\n" +
" : r=a ;\n" +
"a : b b" + // forces list
" | b" + // a list still
" ;\n" +
"b : ID | INT ;\n" +
"MULT: '*' ;\n" +
"ADD : '+' ;\n" +
"INT : [0-9]+ ;\n" +
"ID : [a-z]+ ;\n" +
"WS : [ \\t\\n]+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "1 2", false);
String expecting = "(a (b 1) (b 2))\n" +
"1 2 1\n";
assertEquals(expecting, result);
result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "abc", false);
expecting = "(a (b abc))\n" +
"abc\n";
assertEquals(expecting, result);
}
@Test public void testLR() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {\n" +
"public static class LeafListener extends TBaseListener {\n" +
" public void exitE(TParser.EContext ctx) {\n" +
" if (ctx.getChildCount()==3) {\n" +
" System.out.printf(\"%s %s %s\\n\",ctx.e(0).start.getText(),\n" +
" ctx.e(1).start.getText()," +
" ctx.e().get(0).start.getText());\n" +
" }\n" +
" else System.out.println(ctx.INT().getSymbol().getText());\n" +
" }\n" +
" }" +
"}\n" +
"s\n" +
"@after {" +
" System.out.println($r.ctx.toStringTree(this));" +
" ParseTreeWalker walker = new ParseTreeWalker();\n" +
" walker.walk(new LeafListener(), $r.ctx);" +
"}\n" +
" : r=e ;\n" +
"e : e op='*' e\n" +
" | e op='+' e\n" +
" | INT\n" +
" ;\n" +
"MULT: '*' ;\n" +
"ADD : '+' ;\n" +
"INT : [0-9]+ ;\n" +
"WS : [ \\t\\n]+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "1+2*3", false);
String expecting =
"(e (e 1) + (e (e 2) * (e 3)))\n" +
"1\n" +
"2\n" +
"3\n" +
"2 3 2\n" +
"1 2 1\n";
assertEquals(expecting, result);
}
@Test public void testLRWithLabels() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members {\n" +
" public static class LeafListener extends TBaseListener {\n" +
" public void exitCall(TParser.CallContext ctx) {\n" +
" System.out.printf(\"%s %s\",ctx.e().start.getText(),\n" +
" ctx.eList());\n" +
" }\n" +
" public void exitInt(TParser.IntContext ctx) {\n" +
" System.out.println(ctx.INT().getSymbol().getText());\n" +
" }\n" +
" }\n" +
"}\n" +
"s\n" +
"@after {" +
" System.out.println($r.ctx.toStringTree(this));" +
" ParseTreeWalker walker = new ParseTreeWalker();\n" +
" walker.walk(new LeafListener(), $r.ctx);" +
"}\n" +
" : r=e ;\n" +
"e : e '(' eList ')' # Call\n" +
" | INT # Int\n" +
" ; \n" +
"eList : e (',' e)* ;\n" +
"MULT: '*' ;\n" +
"ADD : '+' ;\n" +
"INT : [0-9]+ ;\n" +
"WS : [ \\t\\n]+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "1(2,3)", false);
String expecting =
"(e (e 1) ( (eList (e 2) , (e 3)) ))\n" +
"1\n" +
"2\n" +
"3\n" +
"1 [13 6]\n";
assertEquals(expecting, result);
}
}

View File

@ -1,383 +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;
import org.antlr.v4.runtime.atn.ATNSerializer;
import org.junit.Test;
import static org.junit.Assert.*;
/** test runtime parse errors */
public class TestParseErrors extends BaseTest {
@Test public void testTokenMismatch() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aa", false);
String expecting = "line 1:1 mismatched input 'a' expecting 'b'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testSingleTokenDeletion() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aab", false);
String expecting = "line 1:1 extraneous input 'a' expecting 'b'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testSingleTokenDeletionExpectingSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' ('b'|'c') ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aab", false);
String expecting = "line 1:1 extraneous input 'a' expecting {'b', 'c'}\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testSingleTokenInsertion() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b' 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ac", false);
String expecting = "line 1:1 missing 'b' at 'c'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testConjuringUpToken() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' x='b' {System.out.println(\"conjured=\"+$x);} 'c' ;";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ac", false);
String expecting = "conjured=[@-1,-1:-1='<missing 'b'>',<2>,1:1]\n";
assertEquals(expecting, result);
}
@Test public void testSingleSetInsertion() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' ('b'|'c') 'd' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ad", false);
String expecting = "line 1:1 missing {'b', 'c'} at 'd'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testConjuringUpTokenFromSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' x=('b'|'c') {System.out.println(\"conjured=\"+$x);} 'd' ;";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ad", false);
String expecting = "conjured=[@-1,-1:-1='<missing 'b'>',<2>,1:1]\n";
assertEquals(expecting, result);
}
@Test public void testLL2() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b'" +
" | 'a' 'c'" +
";\n" +
"q : 'e' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ae", false);
String expecting = "line 1:1 no viable alternative at input 'ae'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testLL3() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b'* 'c'" +
" | 'a' 'b' 'd'" +
" ;\n" +
"q : 'e' ;\n";
System.out.println(grammar);
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "abe", false);
String expecting = "line 1:2 no viable alternative at input 'abe'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testLLStar() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a'+ 'b'" +
" | 'a'+ 'c'" +
";\n" +
"q : 'e' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aaae", false);
String expecting = "line 1:3 no viable alternative at input 'aaae'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testSingleTokenDeletionBeforeLoop() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b'*;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aabc", false);
String expecting = "line 1:1 extraneous input 'a' expecting {<EOF>, 'b'}\n" +
"line 1:3 token recognition error at: 'c'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testMultiTokenDeletionBeforeLoop() throws Exception {
// can only delete 1 before loop
String grammar =
"grammar T;\n" +
"a : 'a' 'b'* 'c';";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aacabc", false);
String expecting =
"line 1:1 extraneous input 'a' expecting {'b', 'c'}\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testSingleTokenDeletionDuringLoop() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b'* 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ababbc", false);
String expecting = "line 1:2 extraneous input 'a' expecting {'b', 'c'}\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testMultiTokenDeletionDuringLoop() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' 'b'* 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "abaaababc", false);
String expecting =
"line 1:2 extraneous input 'a' expecting {'b', 'c'}\n" +
"line 1:6 extraneous input 'a' expecting {'b', 'c'}\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
// ------
@Test public void testSingleTokenDeletionBeforeLoop2() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' ('b'|'z'{;})*;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aabc", false);
String expecting = "line 1:1 extraneous input 'a' expecting {<EOF>, 'b', 'z'}\n" +
"line 1:3 token recognition error at: 'c'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testMultiTokenDeletionBeforeLoop2() throws Exception {
// can only delete 1 before loop
String grammar =
"grammar T;\n" +
"a : 'a' ('b'|'z'{;})* 'c';";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "aacabc", false);
String expecting =
"line 1:1 extraneous input 'a' expecting {'b', 'z', 'c'}\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testSingleTokenDeletionDuringLoop2() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' ('b'|'z'{;})* 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "ababbc", false);
String expecting = "line 1:2 extraneous input 'a' expecting {'b', 'z', 'c'}\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testMultiTokenDeletionDuringLoop2() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'a' ('b'|'z'{;})* 'c' ;";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", "abaaababc", false);
String expecting =
"line 1:2 extraneous input 'a' expecting {'b', 'z', 'c'}\n" +
"line 1:6 extraneous input 'a' expecting {'b', 'z', 'c'}\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
@Test public void testLL1ErrorInfo() throws Exception {
String grammar =
"grammar T;\n" +
"start : animal (AND acClass)? service EOF;\n" +
"animal : (DOG | CAT );\n" +
"service : (HARDWARE | SOFTWARE) ;\n" +
"AND : 'and';\n" +
"DOG : 'dog';\n" +
"CAT : 'cat';\n" +
"HARDWARE: 'hardware';\n" +
"SOFTWARE: 'software';\n" +
"WS : ' ' -> skip ;" +
"acClass\n" +
"@init\n" +
"{ System.out.println(getExpectedTokens().toString(tokenNames)); }\n" +
" : ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "start", "dog and software", false);
String expecting = "{'hardware', 'software'}\n";
assertEquals(expecting, result);
}
/**
* This is a regression test for #6 "NullPointerException in getMissingSymbol".
* https://github.com/antlr/antlr4/issues/6
*/
@Test
public void testInvalidEmptyInput() throws Exception {
String grammar =
"grammar T;\n" +
"start : ID+;\n" +
"ID : [a-z]+;\n" +
"\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "start", "", true);
String expecting = "";
assertEquals(expecting, result);
assertEquals("line 1:0 missing ID at '<EOF>'\n", this.stderrDuringParse);
}
/**
* Regression test for "Getter for context is not a list when it should be".
* https://github.com/antlr/antlr4/issues/19
*/
@Test
public void testContextListGetters() throws Exception {
String grammar =
"grammar T;\n" +
"@parser::members{\n" +
" void foo() {\n" +
" SContext s = null;\n" +
" List<? extends AContext> a = s.a();\n" +
" List<? extends BContext> b = s.b();\n" +
" }\n" +
"}\n" +
"s : (a | b)+;\n" +
"a : 'a' {System.out.print('a');};\n" +
"b : 'b' {System.out.print('b');};\n" +
"";
String result = execParser("T.g", grammar, "TParser", "TLexer", "s", "abab", true);
String expecting = "abab\n";
assertEquals(expecting, result);
assertNull(this.stderrDuringParse);
}
/**
* This is a regression test for #26 "an exception upon simple rule with double recursion in an alternative".
* https://github.com/antlr/antlr4/issues/26
*/
void testDuplicatedLeftRecursiveCall(String input) throws Exception {
String grammar =
"grammar T;\n" +
"start : expr EOF;\n" +
"expr : 'x'\n" +
" | expr expr\n" +
" ;\n" +
"\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "start", input, true);
assertEquals("", result);
assertNull(this.stderrDuringParse);
}
@Test
public void testDuplicatedLeftRecursiveCall1() throws Exception {
testDuplicatedLeftRecursiveCall("x");
}
@Test
public void testDuplicatedLeftRecursiveCall2() throws Exception {
testDuplicatedLeftRecursiveCall("xx");
}
@Test
public void testDuplicatedLeftRecursiveCall3() throws Exception {
testDuplicatedLeftRecursiveCall("xxx");
}
@Test
public void testDuplicatedLeftRecursiveCall4() throws Exception {
testDuplicatedLeftRecursiveCall("xxxx");
}
/**
* This is a regression test for #45 "NullPointerException in ATNConfig.hashCode".
* https://github.com/antlr/antlr4/issues/45
* <p/>
* The original cause of this issue was an error in the tool's ATN state optimization,
* which is now detected early in {@link ATNSerializer} by ensuring that all
* serialized transitions point to states which were not removed.
*/
@Test
public void testInvalidATNStateRemoval() throws Exception {
String grammar =
"grammar T;\n" +
"start : ID ':' expr;\n" +
"expr : primary expr? {} | expr '->' ID;\n" +
"primary : ID;\n" +
"ID : [a-z]+;\n" +
"\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "start", "x:x", true);
String expecting = "";
assertEquals(expecting, result);
assertNull(this.stderrDuringParse);
}
@Test public void testNoViableAltAvoidance() throws Exception {
// "a." matches 'a' to rule e but then realizes '.' won't match.
// previously would cause noviablealt. now prediction pretends to
// have "a' predict 2nd alt of e. Will get syntax error later so
// let it get farther.
String grammar =
"grammar T;\n" +
"s : e '!' ;\n" +
"e : 'a' 'b'\n" +
" | 'a'\n" +
" ;\n" +
"DOT : '.' ;\n" +
"WS : [ \\t\\r\\n]+ -> skip;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a.", false);
String expecting =
"line 1:1 mismatched input '.' expecting '!'\n";
String result = stderrDuringParse;
assertEquals(expecting, result);
}
}

View File

@ -1,154 +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;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestParseTrees extends BaseTest {
@Test public void testTokenAndRuleContextString() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" :r=a ;\n" +
"a : 'x' {System.out.println(getRuleInvocationStack());} ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "x", false);
String expecting = "[a, s]\n(a x)\n";
assertEquals(expecting, result);
}
@Test public void testToken2() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" :r=a ;\n" +
"a : 'x' 'y'\n" +
" ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "xy", false);
String expecting = "(a x y)\n";
assertEquals(expecting, result);
}
@Test public void test2Alts() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" :r=a ;\n" +
"a : 'x' | 'y'\n" +
" ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "y", false);
String expecting = "(a y)\n";
assertEquals(expecting, result);
}
@Test public void test2AltLoop() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" :r=a ;\n" +
"a : ('x' | 'y')* 'z'\n" +
" ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "xyyxyxz", false);
String expecting = "(a x y y x y x z)\n";
assertEquals(expecting, result);
}
@Test public void testRuleRef() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" : r=a ;\n" +
"a : b 'x'\n" +
" ;\n" +
"b : 'y' ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "yx", false);
String expecting = "(a (b y) x)\n";
assertEquals(expecting, result);
}
// ERRORS
@Test public void testExtraToken() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" : r=a ;\n" +
"a : 'x' 'y'\n" +
" ;\n" +
"Z : 'z'; \n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "xzy", false);
String expecting = "(a x z y)\n"; // ERRORs not shown. z is colored red in tree view
assertEquals(expecting, result);
}
@Test public void testNoViableAlt() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" : r=a ;\n" +
"a : 'x' | 'y'\n" +
" ;\n" +
"Z : 'z'; \n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "z", false);
String expecting = "(a z)\n";
assertEquals(expecting, result);
}
@Test public void testSync() throws Exception {
String grammar =
"grammar T;\n" +
"s\n" +
"@init {setBuildParseTree(true);}\n" +
"@after {System.out.println($r.ctx.toStringTree(this));}\n" +
" : r=a ;\n" +
"a : 'x' 'y'* '!'\n" +
" ;\n" +
"Z : 'z'; \n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s", "xzyy!", false);
String expecting = "(a x z y y !)\n";
assertEquals(expecting, result);
}
}

View File

@ -1,597 +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;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/** Test parser execution.
*
* For the non-greedy stuff, the rule is that .* or any other non-greedy loop
* (any + or * loop that has an alternative with '.' in it is automatically
* non-greedy) never sees past the end of the rule containing that loop.
* There is no automatic way to detect when the exit branch of a non-greedy
* loop has seen enough input to determine how much the loop should consume
* yet still allow matching the entire input. Of course, this is extremely
* inefficient, particularly for things like
*
* block : '{' (block|.)* '}' ;
*
* that need only see one symbol to know when it hits a '}'. So, I
* came up with a practical solution. During prediction, the ATN
* simulator never fall off the end of a rule to compute the global
* FOLLOW. Instead, we terminate the loop, choosing the exit branch.
* Otherwise, we predict to reenter the loop. For example, input
* "{ foo }" will allow the loop to match foo, but that's it. During
* prediction, the ATN simulator will see that '}' reaches the end of a
* rule that contains a non-greedy loop and stop prediction. It will choose
* the exit branch of the inner loop. So, the way in which you construct
* the rule containing a non-greedy loop dictates how far it will scan ahead.
* Include everything after the non-greedy loop that you know it must scan
* in order to properly make a prediction decision. these beasts are tricky,
* so be careful. don't liberally sprinkle them around your code.
*
* To simulate filter mode, use ( .* (pattern1|pattern2|...) )*
*
* Nongreedy loops match as much input as possible while still allowing
* the remaining input to match.
*/
public class TestParserExec extends BaseTest {
@Test public void testLabels() throws Exception {
String grammar =
"grammar T;\n" +
"a : b1=b b2+=b* b3+=';' ;\n" +
"b : id=ID val+=INT*;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"abc 34;", false);
assertEquals("", found);
assertEquals(null, stderrDuringParse);
}
/**
* This is a regression test for #270 "Fix operator += applied to a set of
* tokens".
* https://github.com/antlr/antlr4/issues/270
*/
@Test public void testListLabelOnSet() {
String grammar =
"grammar T;\n" +
"a : b b* ';' ;\n" +
"b : ID val+=(INT | FLOAT)*;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"FLOAT : [0-9]+ '.' [0-9]+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"abc 34;", false);
assertEquals("", found);
assertEquals(null, stderrDuringParse);
}
@Test public void testBasic() throws Exception {
String grammar =
"grammar T;\n" +
"a : ID INT {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"abc 34", false);
assertEquals("abc34\n", found);
}
@Test public void testAorB() throws Exception {
String grammar =
"grammar T;\n" +
"a : ID {System.out.println(\" alt 1\");}" +
" | INT {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", "a",
"34", false);
assertEquals("alt 2\n", found);
}
@Test public void testAPlus() throws Exception {
String grammar =
"grammar T;\n" +
"a : ID+ {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a b c", false);
assertEquals("abc\n", found);
}
// force complex decision
@Test public void testAorAPlus() throws Exception {
String grammar =
"grammar T;\n" +
"a : (ID|ID)+ {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a b c", false);
assertEquals("abc\n", found);
}
private static final String ifIfElseGrammarFormat =
"grammar T;\n" +
"start : statement+ ;\n" +
"statement : 'x' | ifStatement;\n" +
"ifStatement : 'if' 'y' statement %s {System.out.println($text);};\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> channel(HIDDEN);\n";
@Test public void testIfIfElseGreedyBinding1() throws Exception {
final String input = "if y if y x else x";
final String expectedInnerBound = "if y x else x\nif y if y x else x\n";
String grammar = String.format(ifIfElseGrammarFormat, "('else' statement)?");
String found = execParser("T.g4", grammar, "TParser", "TLexer", "start", input, false);
assertEquals(expectedInnerBound, found);
}
@Test public void testIfIfElseGreedyBinding2() throws Exception {
final String input = "if y if y x else x";
final String expectedInnerBound = "if y x else x\nif y if y x else x\n";
String grammar = String.format(ifIfElseGrammarFormat, "('else' statement|)");
String found = execParser("T.g4", grammar, "TParser", "TLexer", "start", input, false);
assertEquals(expectedInnerBound, found);
}
@Test public void testIfIfElseNonGreedyBinding() throws Exception {
final String input = "if y if y x else x";
final String expectedOuterBound = "if y x\nif y if y x else x\n";
String grammar = String.format(ifIfElseGrammarFormat, "('else' statement)??");
String found = execParser("T.g4", grammar, "TParser", "TLexer", "start", input, false);
assertEquals(expectedOuterBound, found);
grammar = String.format(ifIfElseGrammarFormat, "(|'else' statement)");
found = execParser("T.g4", grammar, "TParser", "TLexer", "start", input, false);
assertEquals(expectedOuterBound, found);
}
@Test public void testAStar() throws Exception {
String grammar =
"grammar T;\n" +
"a : ID* {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"", false);
assertEquals("\n", found);
found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a b c", false);
assertEquals("abc\n", found);
}
@Test public void testLL1OptionalBlock() throws Exception {
String grammar =
"grammar T;\n" +
"a : (ID|{}INT)? {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"", false);
assertEquals("\n", found);
found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a", false);
assertEquals("a\n", found);
}
// force complex decision
@Test public void testAorAStar() throws Exception {
String grammar =
"grammar T;\n" +
"a : (ID|ID)* {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"", false);
assertEquals("\n", found);
found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a b c", false);
assertEquals("abc\n", found);
}
@Test public void testAorBPlus() throws Exception {
String grammar =
"grammar T;\n" +
"a : (ID|INT{;})+ {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a 34 c", false);
assertEquals("a34c\n", found);
}
@Test public void testAorBStar() throws Exception {
String grammar =
"grammar T;\n" +
"a : (ID|INT{;})* {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"", false);
assertEquals("\n", found);
found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a 34 c", false);
assertEquals("a34c\n", found);
}
/**
* This test is meant to detect regressions of bug antlr/antlr4#41.
* https://github.com/antlr/antlr4/issues/41
*/
@Test
public void testOptional1() throws Exception {
String grammar =
"grammar T;\n" +
"stat : ifstat | 'x';\n" +
"ifstat : 'if' stat ('else' stat)?;\n" +
"WS : [ \\n\\t]+ -> skip ;"
;
String found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "x", false);
assertEquals("", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testOptional2() throws Exception {
String grammar =
"grammar T;\n" +
"stat : ifstat | 'x';\n" +
"ifstat : 'if' stat ('else' stat)?;\n" +
"WS : [ \\n\\t]+ -> skip ;"
;
String found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "if x else x", false);
assertEquals("", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testOptional3() throws Exception {
String grammar =
"grammar T;\n" +
"stat : ifstat | 'x';\n" +
"ifstat : 'if' stat ('else' stat)?;\n" +
"WS : [ \\n\\t]+ -> skip ;"
;
String found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "if x", false);
assertEquals("", found);
assertNull(this.stderrDuringParse);
}
@Test
public void testOptional4() throws Exception {
String grammar =
"grammar T;\n" +
"stat : ifstat | 'x';\n" +
"ifstat : 'if' stat ('else' stat)?;\n" +
"WS : [ \\n\\t]+ -> skip ;"
;
String found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "if if x else x", false);
assertEquals("", found);
assertNull(this.stderrDuringParse);
}
/**
* This test is meant to test the expected solution to antlr/antlr4#42.
* https://github.com/antlr/antlr4/issues/42
*/
@Test
public void testPredicatedIfIfElse() throws Exception {
String grammar =
"grammar T;\n" +
"s : stmt EOF ;\n" +
"stmt : ifStmt | ID;\n" +
"ifStmt : 'if' ID stmt ('else' stmt | {_input.LA(1) != ELSE}?);\n" +
"ELSE : 'else';\n" +
"ID : [a-zA-Z]+;\n" +
"WS : [ \\n\\t]+ -> skip;\n"
;
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"if x if x a else b", true);
String expecting = "";
assertEquals(expecting, found);
assertNull(this.stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#118.
* https://github.com/antlr/antlr4/issues/118
*/
@Ignore("Performance impact of passing this test may not be worthwhile")
@Test public void testStartRuleWithoutEOF() {
String grammar =
"grammar T;\n"+
"s @after {dumpDFA();}\n" +
" : ID | ID INT ID ;\n" +
"ID : 'a'..'z'+ ;\n"+
"INT : '0'..'9'+ ;\n"+
"WS : (' '|'\\t'|'\\n')+ -> skip ;\n";
String result = execParser("T.g4", grammar, "TParser", "TLexer", "s",
"abc 34", true);
String expecting =
"Decision 0:\n" +
"s0-ID->s1\n" +
"s1-INT->s2\n" +
"s2-EOF->:s3=>1\n"; // Must point at accept state
assertEquals(expecting, result);
assertNull(this.stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#195 "label 'label' type
* mismatch with previous definition: TOKEN_LABEL!=RULE_LABEL"
* https://github.com/antlr/antlr4/issues/195
*/
@Test public void testLabelAliasingAcrossLabeledAlternatives() throws Exception {
String grammar =
"grammar T;\n" +
"start : a* EOF;\n" +
"a\n" +
" : label=subrule {System.out.println($label.text);} #One\n" +
" | label='y' {System.out.println($label.text);} #Two\n" +
" ;\n" +
"subrule : 'x';\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "start",
"xy", false);
assertEquals("x\ny\n", found);
}
/**
* This is a regression test for antlr/antlr4#334 "BailErrorStrategy: bails
* out on proper input".
* https://github.com/antlr/antlr4/issues/334
*/
@Test public void testPredictionIssue334() {
String grammar =
"grammar T;\n" +
"\n" +
"file @init{setErrorHandler(new BailErrorStrategy());} \n" +
"@after {System.out.println($ctx.toStringTree(this));}\n" +
" : item (SEMICOLON item)* SEMICOLON? EOF ;\n" +
"item : A B?;\n" +
"\n" +
"\n" +
"\n" +
"SEMICOLON: ';';\n" +
"\n" +
"A : 'a'|'A';\n" +
"B : 'b'|'B';\n" +
"\n" +
"WS : [ \\r\\t\\n]+ -> skip;\n";
String input = "a";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "file", input, false);
assertEquals("(file (item a) <EOF>)\n", found);
assertNull(stderrDuringParse);
}
/**
* This is a regressino test for antlr/antlr4#299 "Repeating subtree not
* accessible in visitor".
* https://github.com/antlr/antlr4/issues/299
*/
@Test public void testListLabelForClosureContext() throws Exception {
String grammar =
"grammar T;\n" +
"ifStatement\n" +
"@after { List<? extends ElseIfStatementContext> items = $ctx.elseIfStatement(); }\n" +
" : 'if' expression\n" +
" ( ( 'then'\n" +
" executableStatement*\n" +
" elseIfStatement* // <--- problem is here\n" +
" elseStatement?\n" +
" 'end' 'if'\n" +
" ) | executableStatement )\n" +
" ;\n" +
"\n" +
"elseIfStatement\n" +
" : 'else' 'if' expression 'then' executableStatement*\n" +
" ;\n"
+ "expression : 'a' ;\n"
+ "executableStatement : 'a' ;\n"
+ "elseStatement : 'a' ;\n";
String input = "a";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "expression", input, false);
assertEquals("", found);
assertNull(stderrDuringParse);
}
/**
* This test ensures that {@link ParserATNSimulator} produces a correct
* result when the grammar contains multiple explicit references to
* {@code EOF} inside of parser rules.
*/
@Test
public void testMultipleEOFHandling() throws Exception {
String grammar =
"grammar T;\n" +
"prog : ('x' | 'x' 'y') EOF EOF;\n";
String input = "x";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "prog", input, false);
assertEquals("", found);
assertNull(stderrDuringParse);
}
/**
* This test ensures that {@link ParserATNSimulator} does not produce a
* {@link StackOverflowError} when it encounters an {@code EOF} transition
* inside a closure.
*/
@Test
public void testEOFInClosure() throws Exception {
String grammar =
"grammar T;\n" +
"prog : stat EOF;\n" +
"stat : 'x' ('y' | EOF)*?;\n";
String input = "x";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "prog", input, false);
assertEquals("", found);
assertNull(stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#561 "Issue with parser
* generation in 4.2.2"
* https://github.com/antlr/antlr4/issues/561
*/
@Test public void testReferenceToATN() throws Exception {
String grammar =
"grammar T;\n" +
"a : (ID|ATN)* ATN? {System.out.println($text);} ;\n" +
"ID : 'a'..'z'+ ;\n" +
"ATN : '0'..'9'+;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"", false);
assertEquals("\n", found);
found = execParser("T.g4", grammar, "TParser", "TLexer", "a",
"a 34 c", false);
assertEquals("a34c\n", found);
}
/**
* This is a regression test for antlr/antlr4#588 "ClassCastException during
* semantic predicate handling".
* https://github.com/antlr/antlr4/issues/588
*/
@Test public void testFailedPredicateExceptionState() throws Exception {
String grammar = load("Psl.g4", "UTF-8");
String found = execParser("Psl.g4", grammar, "PslParser", "PslLexer", "floating_constant", " . 234", false);
assertEquals("", found);
assertEquals("line 1:6 rule floating_constant DEC:A floating-point constant cannot have internal white space\n", stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#563 "Inconsistent token
* handling in ANTLR4".
* https://github.com/antlr/antlr4/issues/563
*/
@Test public void testAlternateQuotes() throws Exception {
String lexerGrammar =
"lexer grammar ModeTagsLexer;\n" +
"\n" +
"// Default mode rules (the SEA)\n" +
"OPEN : '«' -> mode(ISLAND) ; // switch to ISLAND mode\n" +
"TEXT : ~'«'+ ; // clump all text together\n" +
"\n" +
"mode ISLAND;\n" +
"CLOSE : '»' -> mode(DEFAULT_MODE) ; // back to SEA mode \n" +
"SLASH : '/' ;\n" +
"ID : [a-zA-Z]+ ; // match/send ID in tag to parser\n";
String parserGrammar =
"parser grammar ModeTagsParser;\n" +
"\n" +
"options { tokenVocab=ModeTagsLexer; } // use tokens from ModeTagsLexer.g4\n" +
"\n" +
"file: (tag | TEXT)* ;\n" +
"\n" +
"tag : '«' ID '»'\n" +
" | '«' '/' ID '»'\n" +
" ;";
boolean success = rawGenerateAndBuildRecognizer("ModeTagsLexer.g4",
lexerGrammar,
null,
"ModeTagsLexer");
assertTrue(success);
String found = execParser("ModeTagsParser.g4", parserGrammar, "ModeTagsParser", "ModeTagsLexer", "file", "", false);
assertEquals("", found);
assertNull(stderrDuringParse);
}
/**
* This is a regression test for antlr/antlr4#672 "Initialization failed in
* locals".
* https://github.com/antlr/antlr4/issues/672
*/
@Test public void testAttributeValueInitialization() throws Exception {
String grammar =
"grammar Data; \n" +
"\n" +
"file : group+ EOF; \n" +
"\n" +
"group: INT sequence {System.out.println($sequence.values.size());} ; \n" +
"\n" +
"sequence returns [List<Integer> values = new ArrayList<Integer>()] \n" +
" locals[List<Integer> localValues = new ArrayList<Integer>()]\n" +
" : (INT {$localValues.add($INT.int);})* {$values.addAll($localValues);}\n" +
"; \n" +
"\n" +
"INT : [0-9]+ ; // match integers \n" +
"WS : [ \\t\\n\\r]+ -> skip ; // toss out all whitespace\n";
String input = "2 9 10 3 1 2 3";
String found = execParser("Data.g4", grammar, "DataParser", "DataLexer", "file", input, false);
assertEquals("6\n", found);
assertNull(stderrDuringParse);
}
}

View File

@ -1,183 +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;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestSemPredEvalLexer extends BaseTest {
@Test public void testDisableRule() throws Exception {
String grammar =
"lexer grammar L;\n"+
"E1 : 'enum' {false}? ;\n" +
"E2 : 'enum' {true}? ;\n" + // winner not E1 or ID
"ID : 'a'..'z'+ ;\n"+
"WS : (' '|'\\n') -> skip ;";
String found = execLexer("L.g4", grammar, "L", "enum abc", true);
String expecting =
"[@0,0:3='enum',<2>,1:0]\n" +
"[@1,5:7='abc',<3>,1:5]\n" +
"[@2,8:7='<EOF>',<-1>,1:8]\n" +
"s0-' '->:s5=>4\n" +
"s0-'a'->:s6=>3\n" +
"s0-'e'->:s1=>3\n" +
":s1=>3-'n'->:s2=>3\n" +
":s2=>3-'u'->:s3=>3\n" +
":s6=>3-'b'->:s6=>3\n" +
":s6=>3-'c'->:s6=>3\n";
assertEquals(expecting, found);
}
@Test public void testIDvsEnum() throws Exception {
String grammar =
"lexer grammar L;\n"+
"ENUM : 'enum' {false}? ;\n" +
"ID : 'a'..'z'+ ;\n"+
"WS : (' '|'\\n') -> skip ;";
String found = execLexer("L.g4", grammar, "L", "enum abc enum", true);
String expecting =
"[@0,0:3='enum',<2>,1:0]\n" +
"[@1,5:7='abc',<2>,1:5]\n" +
"[@2,9:12='enum',<2>,1:9]\n" +
"[@3,13:12='<EOF>',<-1>,1:13]\n" +
"s0-' '->:s5=>3\n" +
"s0-'a'->:s4=>2\n" +
"s0-'e'->:s1=>2\n" +
":s1=>2-'n'->:s2=>2\n" +
":s2=>2-'u'->:s3=>2\n" +
":s4=>2-'b'->:s4=>2\n" +
":s4=>2-'c'->:s4=>2\n"; // no 'm'-> transition...conflicts with pred
assertEquals(expecting, found);
}
@Test public void testIDnotEnum() throws Exception {
String grammar =
"lexer grammar L;\n"+
"ENUM : [a-z]+ {false}? ;\n" +
"ID : [a-z]+ ;\n"+
"WS : (' '|'\\n') -> skip ;";
String found = execLexer("L.g4", grammar, "L", "enum abc enum", true);
String expecting =
"[@0,0:3='enum',<2>,1:0]\n" +
"[@1,5:7='abc',<2>,1:5]\n" +
"[@2,9:12='enum',<2>,1:9]\n" +
"[@3,13:12='<EOF>',<-1>,1:13]\n" +
"s0-' '->:s2=>3\n"; // no edges in DFA for enum/id. all paths lead to pred.
assertEquals(expecting, found);
}
@Test public void testEnumNotID() throws Exception {
String grammar =
"lexer grammar L;\n"+
"ENUM : [a-z]+ {getText().equals(\"enum\")}? ;\n" +
"ID : [a-z]+ ;\n"+
"WS : (' '|'\\n') -> skip ;";
String found = execLexer("L.g4", grammar, "L", "enum abc enum", true);
String expecting =
"[@0,0:3='enum',<1>,1:0]\n" +
"[@1,5:7='abc',<2>,1:5]\n" +
"[@2,9:12='enum',<1>,1:9]\n" +
"[@3,13:12='<EOF>',<-1>,1:13]\n" +
"s0-' '->:s3=>3\n"; // no edges in DFA for enum/id. all paths lead to pred.
assertEquals(expecting, found);
}
@Test public void testIndent() throws Exception {
String grammar =
"lexer grammar L;\n"+
"ID : [a-z]+ ;\n"+
"INDENT : [ \\t]+ {_tokenStartCharPositionInLine==0}? \n" +
" {System.out.println(\"INDENT\");} ;"+
"NL : '\\n' ;"+
"WS : [ \\t]+ ;";
String found = execLexer("L.g4", grammar, "L", "abc\n def \n", true);
String expecting =
"INDENT\n" + // action output
"[@0,0:2='abc',<1>,1:0]\n" + // ID
"[@1,3:3='\\n',<3>,1:3]\n" + // NL
"[@2,4:5=' ',<2>,2:0]\n" + // INDENT
"[@3,6:8='def',<1>,2:2]\n" + // ID
"[@4,9:10=' ',<4>,2:5]\n" + // WS
"[@5,11:11='\\n',<3>,2:7]\n" +
"[@6,12:11='<EOF>',<-1>,3:0]\n" +
"s0-'\n" +
"'->:s2=>3\n" +
"s0-'a'->:s1=>1\n" +
"s0-'d'->:s1=>1\n" +
":s1=>1-'b'->:s1=>1\n" +
":s1=>1-'c'->:s1=>1\n" +
":s1=>1-'e'->:s1=>1\n" +
":s1=>1-'f'->:s1=>1\n";
assertEquals(expecting, found);
}
@Test public void testLexerInputPositionSensitivePredicates() throws Exception {
String grammar =
"lexer grammar L;\n"+
"WORD1 : ID1+ {System.out.println(getText());} ;\n"+
"WORD2 : ID2+ {System.out.println(getText());} ;\n"+
"fragment ID1 : {getCharPositionInLine()<2}? [a-zA-Z];\n"+
"fragment ID2 : {getCharPositionInLine()>=2}? [a-zA-Z];\n"+
"WS : (' '|'\\n') -> skip;\n";
String found = execLexer("L.g4", grammar, "L", "a cde\nabcde\n");
String expecting =
"a\n" +
"cde\n" +
"ab\n" +
"cde\n" +
"[@0,0:0='a',<1>,1:0]\n" +
"[@1,2:4='cde',<2>,1:2]\n" +
"[@2,6:7='ab',<1>,2:0]\n" +
"[@3,8:10='cde',<2>,2:2]\n" +
"[@4,12:11='<EOF>',<-1>,3:0]\n";
assertEquals(expecting, found);
}
@Test public void testPredicatedKeywords() {
String grammar =
"lexer grammar A;" +
"ENUM : [a-z]+ {getText().equals(\"enum\")}? {System.out.println(\"enum!\");} ;\n" +
"ID : [a-z]+ {System.out.println(\"ID \"+getText());} ;\n" +
"WS : [ \\n] -> skip ;";
String found = execLexer("A.g4", grammar, "A", "enum enu a");
String expecting =
"enum!\n" +
"ID enu\n" +
"ID a\n" +
"[@0,0:3='enum',<1>,1:0]\n" +
"[@1,5:7='enu',<2>,1:5]\n" +
"[@2,9:9='a',<2>,1:9]\n" +
"[@3,10:9='<EOF>',<-1>,1:10]\n";
assertEquals(expecting, found);
}
}

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;
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:0 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);
}
}

View File

@ -1,283 +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;
import org.antlr.v4.tool.ErrorType;
import org.junit.Test;
import static org.junit.Assert.*;
/** Test the set stuff in lexer and parser */
public class TestSets extends BaseTest {
protected boolean debug = false;
/** Public default constructor used by TestRig */
public TestSets() {
}
@Test public void testSeqDoesNotBecomeSet() throws Exception {
// this must return A not I to the parser; calling a nonfragment rule
// from a nonfragment rule does not set the overall token.
String grammar =
"grammar P;\n" +
"a : C {System.out.println(_input.getText());} ;\n" +
"fragment A : '1' | '2';\n" +
"fragment B : '3' '4';\n" +
"C : A | B;\n";
String found = execParser("P.g4", grammar, "PParser", "PLexer",
"a", "34", debug);
assertEquals("34\n", found);
}
@Test public void testParserSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : t=('x'|'y') {System.out.println($t.text);} ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x", debug);
assertEquals("x\n", found);
}
@Test public void testParserNotSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : t=~('x'|'y') 'z' {System.out.println($t.text);} ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "zz", debug);
assertEquals("z\n", found);
}
@Test public void testParserNotToken() throws Exception {
String grammar =
"grammar T;\n" +
"a : ~'x' 'z' {System.out.println(_input.getText());} ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "zz", debug);
assertEquals("zz\n", found);
}
@Test public void testParserNotTokenWithLabel() throws Exception {
String grammar =
"grammar T;\n" +
"a : t=~'x' 'z' {System.out.println($t.text);} ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "zz", debug);
assertEquals("z\n", found);
}
@Test public void testRuleAsSet() throws Exception {
String grammar =
"grammar T;\n" +
"a @after {System.out.println(_input.getText());} : 'a' | 'b' |'c' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "b", debug);
assertEquals("b\n", found);
}
@Test public void testNotChar() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ~'b' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x", debug);
assertEquals("x\n", found);
}
@Test public void testOptionalSingleElement() throws Exception {
String grammar =
"grammar T;\n" +
"a : A? 'c' {System.out.println(_input.getText());} ;\n" +
"A : 'b' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "bc", debug);
assertEquals("bc\n", found);
}
@Test public void testOptionalLexerSingleElement() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println(_input.getText());} ;\n" +
"A : 'b'? 'c' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "bc", debug);
assertEquals("bc\n", found);
}
@Test public void testStarLexerSingleElement() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println(_input.getText());} ;\n" +
"A : 'b'* 'c' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "bbbbc", debug);
assertEquals("bbbbc\n", found);
found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "c", debug);
assertEquals("c\n", found);
}
@Test public void testPlusLexerSingleElement() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println(_input.getText());} ;\n" +
"A : 'b'+ 'c' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "bbbbc", debug);
assertEquals("bbbbc\n", found);
}
@Test public void testOptionalSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : ('a'|'b')? 'c' {System.out.println(_input.getText());} ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "ac", debug);
assertEquals("ac\n", found);
}
@Test public void testStarSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : ('a'|'b')* 'c' {System.out.println(_input.getText());} ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "abaac", debug);
assertEquals("abaac\n", found);
}
@Test public void testPlusSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : ('a'|'b')+ 'c' {System.out.println(_input.getText());} ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "abaac", debug);
assertEquals("abaac\n", found);
}
@Test public void testLexerOptionalSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println(_input.getText());} ;\n" +
"A : ('a'|'b')? 'c' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "ac", debug);
assertEquals("ac\n", found);
}
@Test public void testLexerStarSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println(_input.getText());} ;\n" +
"A : ('a'|'b')* 'c' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "abaac", debug);
assertEquals("abaac\n", found);
}
@Test public void testLexerPlusSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println(_input.getText());} ;\n" +
"A : ('a'|'b')+ 'c' ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "abaac", debug);
assertEquals("abaac\n", found);
}
@Test public void testNotCharSet() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ~('b'|'c') ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x", debug);
assertEquals("x\n", found);
}
@Test public void testNotCharSetWithLabel() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : h=~('b'|'c') ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x", debug);
assertEquals("x\n", found);
}
@Test public void testNotCharSetWithRuleRef() throws Exception {
// might be a useful feature to add someday
String[] pair = new String[] {
"grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ~('a'|B) ;\n" +
"B : 'b' ;\n",
"error(" + ErrorType.UNSUPPORTED_REFERENCE_IN_LEXER_SET.code + "): T.g4:3:10: rule reference B is not currently supported in a set\n"
};
super.testErrors(pair, true);
}
@Test public void testNotCharSetWithString() throws Exception {
// might be a useful feature to add someday
String[] pair = new String[] {
"grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ~('a'|'aa') ;\n" +
"B : 'b' ;\n",
"error(" + ErrorType.INVALID_LITERAL_IN_LEXER_SET.code + "): T.g4:3:10: multi-character literals are not allowed in lexer sets: 'aa'\n"
};
super.testErrors(pair, true);
}
@Test public void testNotCharSetWithRuleRef3() throws Exception {
String grammar =
"grammar T;\n" +
"a : A {System.out.println($A.text);} ;\n" +
"A : ('a'|B) ;\n" + // this doesn't collapse to set but works
"fragment\n" +
"B : ~('a'|'c') ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "x", debug);
assertEquals("x\n", found);
}
@Test public void testCharSetLiteral() throws Exception {
String grammar =
"grammar T;\n" +
"a : (A {System.out.println($A.text);})+ ;\n" +
"A : [AaBb] ;\n" +
"WS : (' '|'\\n')+ -> skip ;\n";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"a", "A a B b", debug);
assertEquals("A\n" +
"a\n" +
"B\n" +
"b\n", found);
}
}

View File

@ -0,0 +1,12 @@
package org.antlr.v4.test.rt.gen;
public class AbstractParserTestMethod extends TestMethod {
public String startRule;
public AbstractParserTestMethod(String name, String grammarName, String startRule) {
super(name, grammarName, null, null, null, null);
this.startRule = startRule;
}
}

View File

@ -0,0 +1,35 @@
package org.antlr.v4.test.rt.gen;
import java.io.File;
import org.stringtemplate.v4.STGroup;
public class CompositeLexerTestMethod extends LexerTestMethod {
public Grammar[] slaveGrammars;
public CompositeLexerTestMethod(String name, String grammarName,
String input, String expectedOutput,
String expectedErrors, String ... slaves) {
super(name, grammarName, input, expectedOutput, expectedErrors, null);
this.slaveGrammars = new Grammar[slaves.length];
for(int i=0;i<slaves.length;i++)
this.slaveGrammars[i] = new Grammar(name + "_" + slaves[i], slaves[i]);
}
@Override
public void loadGrammars(File grammarDir, String testFileName) throws Exception {
for(Grammar slave : slaveGrammars)
slave.load(new File(grammarDir, testFileName));
super.loadGrammars(grammarDir, testFileName);
}
@Override
public void generateGrammars(STGroup group) {
for(Grammar slave : slaveGrammars)
slave.generate(group);
super.generateGrammars(group);
}
}

View File

@ -0,0 +1,36 @@
package org.antlr.v4.test.rt.gen;
import java.io.File;
import org.stringtemplate.v4.STGroup;
public class CompositeParserTestMethod extends ParserTestMethod {
public Grammar[] slaveGrammars;
public boolean slaveIsLexer = false;
public CompositeParserTestMethod(String name, String grammarName,
String startRule, String input, String expectedOutput,
String expectedErrors, String ... slaves) {
super(name, grammarName, startRule, input, expectedOutput, expectedErrors);
this.slaveGrammars = new Grammar[slaves.length];
for(int i=0;i<slaves.length;i++)
this.slaveGrammars[i] = new Grammar(name + "_" + slaves[i], slaves[i]);
}
@Override
public void loadGrammars(File grammarDir, String testFileName) throws Exception {
for(Grammar slave : slaveGrammars)
slave.load(new File(grammarDir, testFileName));
super.loadGrammars(grammarDir, testFileName);
}
@Override
public void generateGrammars(STGroup group) {
for(Grammar slave : slaveGrammars)
slave.generate(group);
super.generateGrammars(group);
}
}

View File

@ -0,0 +1,25 @@
package org.antlr.v4.test.rt.gen;
import java.io.File;
import org.stringtemplate.v4.STGroup;
public class ConcreteParserTestMethod extends TestMethod {
public String baseName;
public ConcreteParserTestMethod(String name, String input, String expectedOutput,
String expectedErrors, Integer index) {
super(name, null, input, expectedOutput, expectedErrors, index);
this.baseName = name;
}
@Override
public void loadGrammars(File grammarDir, String testFileName) throws Exception {
}
@Override
public void generateGrammars(STGroup group) {
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
package org.antlr.v4.test.rt.gen;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
public class Grammar {
public String fileName;
public String grammarName;
public String[] lines;
public ST template;
public Grammar(String fileName, String grammarName) {
this.fileName = fileName;
this.grammarName = grammarName;
}
public void load(File grammarDir) throws Exception {
template = loadGrammar(grammarDir, fileName);
}
protected ST loadGrammar(File grammarDir, String grammarFileName) throws Exception {
File file = new File(grammarDir, grammarFileName + ".st");
InputStream input = new FileInputStream(file);
try {
byte[] data = new byte[(int)file.length()];
int next = 0;
while(input.available()>0) {
int read = input.read(data, next, data.length - next);
next += read;
}
String s = new String(data);
return new ST(s);
} finally {
input.close();
}
}
public void generate(STGroup group) {
template.add("grammarName", grammarName);
template.groupThatCreatedThisInstance = group; // so templates get interpreted
lines = template.render().split("\n");
for(int i=0;i<lines.length;i++)
lines[i] = Generator.escape(lines[i]);
}
}

View File

@ -0,0 +1,17 @@
package org.antlr.v4.test.rt.gen;
public class LexerTestMethod extends TestMethod {
public String[] outputLines;
public boolean lexerOnly = true;
public boolean showDFA = false;
public LexerTestMethod(String name, String grammarName, String input,
String expectedOutput, String expectedErrors, Integer index) {
super(name, grammarName, input, expectedOutput, expectedErrors, index);
outputLines = expectedOutput.split("\n");
for(int i=0;i<outputLines.length;i++)
outputLines[i] = Generator.escape(outputLines[i]);
}
}

View File

@ -0,0 +1,13 @@
package org.antlr.v4.test.rt.gen;
public class ParserTestMethod extends TestMethod {
public String startRule;
public ParserTestMethod(String name, String grammarName, String startRule,
String input, String expectedOutput, String expectedErrors) {
super(name, grammarName, input, expectedOutput, expectedErrors, null);
this.startRule = startRule;
}
}

View File

@ -0,0 +1,101 @@
package org.antlr.v4.test.rt.gen;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
public class TestFile {
List<TestMethod> unitTests = new ArrayList<TestMethod>();
public String name;
public List<String> tests = new ArrayList<String>();
public boolean importErrorQueue = false;
public boolean importGrammar = false;
public TestFile(String name) {
this.name = name;
}
public String getName() {
return name;
}
public ParserTestMethod addParserTest(File grammarDir, String name, String grammarName, String methodName,
String input, String expectedOutput, String expectedErrors) throws Exception {
ParserTestMethod tm = new ParserTestMethod(name, grammarName, methodName, input, expectedOutput, expectedErrors);
tm.loadGrammars(grammarDir, this.name);
unitTests.add(tm);
return tm;
}
public AbstractParserTestMethod addParserTests(File grammarDir, String name, String grammarName, String methodName,
String ... inputsAndOuputs) throws Exception {
AbstractParserTestMethod tm = new AbstractParserTestMethod(name, grammarName, methodName);
tm.loadGrammars(grammarDir, this.name);
unitTests.add(tm);
for(int i=0; i<inputsAndOuputs.length; i+=2) {
ConcreteParserTestMethod cm = new ConcreteParserTestMethod(name,
inputsAndOuputs[i], inputsAndOuputs[i+1], null,
1 + (i/2));
unitTests.add(cm);
}
return tm;
}
public AbstractParserTestMethod addParserTestsWithErrors(File grammarDir, String name, String grammarName, String methodName,
String ... inputsOuputsAndErrors) throws Exception {
AbstractParserTestMethod tm = new AbstractParserTestMethod(name, grammarName, methodName);
tm.loadGrammars(grammarDir, this.name);
unitTests.add(tm);
for(int i=0; i<inputsOuputsAndErrors.length; i+=3) {
ConcreteParserTestMethod cm = new ConcreteParserTestMethod(name,
inputsOuputsAndErrors[i], inputsOuputsAndErrors[i+1], inputsOuputsAndErrors[i+2],
1 + (i/3));
unitTests.add(cm);
}
return tm;
}
public CompositeParserTestMethod addCompositeParserTest(File grammarDir, String name, String grammarName, String methodName,
String input, String expectedOutput, String expectedErrors, String ... slaves) throws Exception {
CompositeParserTestMethod tm = new CompositeParserTestMethod(name, grammarName, methodName, input, expectedOutput, expectedErrors, slaves);
tm.loadGrammars(grammarDir, this.name);
unitTests.add(tm);
return tm;
}
public LexerTestMethod addLexerTest(File grammarDir, String name, String grammarName,
String input, String expectedOutput, String expectedErrors) throws Exception {
return addLexerTest(grammarDir, name, grammarName, input, expectedOutput, expectedErrors, null);
}
public LexerTestMethod addLexerTest(File grammarDir, String name, String grammarName,
String input, String expectedOutput, String expectedErrors, Integer index) throws Exception {
LexerTestMethod tm = new LexerTestMethod(name, grammarName, input, expectedOutput, expectedErrors, index);
tm.loadGrammars(grammarDir, this.name);
unitTests.add(tm);
return tm;
}
public CompositeLexerTestMethod addCompositeLexerTest(File grammarDir, String name, String grammarName,
String input, String expectedOutput, String expectedErrors, String ... slaves) throws Exception {
CompositeLexerTestMethod tm = new CompositeLexerTestMethod(name, grammarName, input, expectedOutput, expectedErrors, slaves);
tm.loadGrammars(grammarDir, this.name);
unitTests.add(tm);
return tm;
}
public void generateUnitTests(STGroup group) {
for(TestMethod tm : unitTests) {
tm.generateGrammars(group);
String name = tm.getClass().getSimpleName();
ST template = group.getInstanceOf(name);
template.add("test", tm);
tests.add(template.render());
}
}
}

View File

@ -0,0 +1,34 @@
package org.antlr.v4.test.rt.gen;
import java.io.File;
import org.stringtemplate.v4.STGroup;
public abstract class TestMethod {
public String name;
public Grammar grammar;
public String afterGrammar;
public String input;
public String expectedOutput;
public String expectedErrors;
public boolean debug = false;
protected TestMethod(String name, String grammarName, String input,
String expectedOutput, String expectedErrors, Integer index) {
this.name = name + (index==null ? "" : "_" + index);
this.grammar = new Grammar(name, grammarName);
this.input = Generator.escape(input);
this.expectedOutput = Generator.escape(expectedOutput);
this.expectedErrors = Generator.escape(expectedErrors);
}
public void loadGrammars(File grammarDir, String testFileName) throws Exception {
grammar.load(new File(grammarDir, testFileName));
}
public void generateGrammars(STGroup group) {
grammar.generate(group);
}
}

View File

@ -0,0 +1,4 @@
lexer grammar M;
import S;
B : 'b';
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,3 @@
lexer grammar S;
A : 'a' {<writeln("\"S.A\"")>};
C : 'c' ;

View File

@ -0,0 +1,4 @@
lexer grammar M;
import S;
A : 'a' B {<writeln("\"M.A\"")>};
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,3 @@
lexer grammar S;
A : 'a' {<writeln("\"S.A\"")>};
B : 'b' {<writeln("\"S.B\"")>};

View File

@ -0,0 +1,4 @@
grammar M;
import S;
s : a ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,2 @@
parser grammar S;
a : '=' 'a' {<write("\"S.a\"")>};

View File

@ -0,0 +1,3 @@
grammar M;
import S;
s : x INT;

View File

@ -0,0 +1,5 @@
parser grammar S;
tokens { A, B, C }
x : 'x' INT {<writeln("\"S.x\"")>};
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,17 @@
// The lexer will create rules to match letters a, b, c.
// The associated token types A, B, C must have the same value
// and all import'd parsers. Since ANTLR regenerates all imports
// for use with the delegator M, it can generate the same token type
// mapping in each parser:
// public static final int C=6;
// public static final int EOF=-1;
// public static final int B=5;
// public static final int WS=7;
// public static final int A=4;
grammar M;
import S,T;
s : x y ; // matches AA, which should be 'aa'
B : 'b' ; // another order: B, A, C
A : 'a' ;
C : 'c' ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,3 @@
parser grammar S;
tokens { A, B, C }
x : A {<writeln("\"S.x\"")>};

View File

@ -0,0 +1,3 @@
parser grammar S;
tokens { C, B, A } // reverse order
y : A {<writeln("\"T.y\"")>};

View File

@ -0,0 +1,4 @@
grammar M; // uses no rules from the import
import S;
s : 'b'{<Invoke_foo()>}; // gS is import pointer
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,5 @@
parser grammar S;
@members {
<Declare_foo()>
}
a : B;

View File

@ -0,0 +1,5 @@
grammar M;
import S;
s : a ;
B : 'b' ; // defines B from inherited token space
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,5 @@
grammar M;
import S;
s : label=a[3] {<writeln("$label.y")>} ;
B : 'b' ; // defines B from inherited token space
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,2 @@
parser grammar S;
a[int x] returns [int y] : B {<write("\"S.a\"")>;$y=1000;};

View File

@ -0,0 +1,5 @@
grammar M;
import S;
s : a {<write("$a.text")>} ;
B : 'b' ; // defines B from inherited token space
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,2 @@
parser grammar S;
a : B {<write("\"S.a\"")>};

View File

@ -0,0 +1,2 @@
parser grammar S;
a : B {<writeln("\"S.a\"")>};

View File

@ -0,0 +1,5 @@
grammar M;
import S,T;
s : a ;
B : 'b' ; // defines B from inherited token space
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,3 @@
parser grammar S;
a : B {<writeln("\"S.a\"")>};
b : B;

View File

@ -0,0 +1,2 @@
parser grammar T;
a : B {<writeln("\"T.a\"")>};

View File

@ -0,0 +1,4 @@
grammar M;
import S;
b : 'b'|'c';
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,3 @@
parser grammar S;
a : b {<write("\"S.a\"")>};
b : B ;

View File

@ -0,0 +1,4 @@
grammar M;
import S, T;
b : 'b'|'c' {<writeln("\"M.b\"")>}|B|A;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,4 @@
parser grammar S;
a : b {<writeln("\"S.a\"")>};
b : 'b' ;

View File

@ -0,0 +1,3 @@
parser grammar S;
tokens { A }
b : 'b' {<writeln("\"T.b\"")>};

View File

@ -0,0 +1,7 @@
grammar M;
import S;
prog : decl ;
type_ : 'int' | 'float' ;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip;

View File

@ -0,0 +1,5 @@
parser grammar S;
type_ : 'int' ;
decl : type_ ID ';'
| type_ ID init ';' {<write("\"Decl: \" + $text")>};
init : '=' INT;

View File

@ -0,0 +1,4 @@
grammar M;
import S;
program : 'test' 'test';
WS : (UNICODE_CLASS_Zs)+ -> skip;

View File

@ -0,0 +1,6 @@
lexer grammar S;
fragment
UNICODE_CLASS_Zs : '\u0020' | '\u00A0' | '\u1680' | '\u180E'
| '\u2000'..'\u200A'
| '\u202F' | '\u205F' | '\u3000'
;

View File

@ -0,0 +1,5 @@
grammar M;
import S;
s : a;
B : 'b';
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,3 @@
parser grammar S;
options {}
a : B;

View File

@ -0,0 +1,5 @@
grammar M;
import S;
s : a;
B : 'b';
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,2 @@
parser grammar S;
a @after {} : B;

View File

@ -0,0 +1,5 @@
grammar M;
import S;
a : A {<Append("\"M.a: \"","$A"):writeln()>};
A : 'abc' {<writeln("\"M.A\"")>};
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,2 @@
lexer grammar S;
ID : 'a'..'z'+;

View File

@ -0,0 +1,5 @@
grammar <grammarName>;
s @after {<DumpDFA()>}
: ID | ID {} ;
ID : 'a'..'z'+;
WS : (' '|'\t'|'\n')+ -> skip ;

View File

@ -0,0 +1,12 @@
grammar <grammarName>;
prog
@init {<LL_EXACT_AMBIG_DETECTION()>}
: expr expr {<writeln("\"alt 1\"")>}
| expr
;
expr: '@'
| ID '@'
| ID
;
ID : [a-z]+ ;
WS : [ \r\n\t]+ -> skip ;

View File

@ -0,0 +1,9 @@
grammar <grammarName>;
s @after {<DumpDFA()>}
: '$' a | '@' b ;
a : e ID ;
b : e INT ID ;
e : INT | ;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;
WS : (' '|'\t'|'\n')+ -> skip ;

View File

@ -0,0 +1,9 @@
grammar <grammarName>;
s @after {<DumpDFA()>}
: ('$' a | '@' b)+ ;
a : e ID ;
b : e INT ID ;
e : INT | ;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;
WS : (' '|'\t'|'\n')+ -> skip ;

View File

@ -0,0 +1,13 @@
grammar <grammarName>;
s
@init {<LL_EXACT_AMBIG_DETECTION()>}
: expr[0] {<ToStringTree("$expr.ctx"):writeln()>};
expr[int _p]
: ID
(
{5 >= $_p}? '*' expr[6]
| {4 >= $_p}? '+' expr[5]
)*
;
ID : [a-zA-Z]+ ;
WS : [ \r\n\t]+ -> skip ;

View File

@ -0,0 +1,10 @@
grammar <grammarName>;
s
@init {<LL_EXACT_AMBIG_DETECTION()>}
@after {<DumpDFA()>}
: '{' stat* '}' ;
stat: 'if' ID 'then' stat ('else' ID)?
| 'return'
;
ID : 'a'..'z'+ ;
WS : (' '|'\t'|'\n')+ -> skip ;

View File

@ -0,0 +1,15 @@
grammar <grammarName>;
prog
@init {<LL_EXACT_AMBIG_DETECTION()>}
: expr_or_assign*;
expr_or_assign
: expr '++' {<writeln("\"fail.\"")>}
| expr {<writeln("\"pass: \"+$expr.text")>}
;
expr: expr_primary ('\<-' ID)?;
expr_primary
: '(' ID ')'
| ID '(' ID ')'
| ID
;
ID : [a-z]+ ;

View File

@ -0,0 +1,9 @@
grammar <grammarName>;
s @after {<DumpDFA()>}
: a;
a : e ID ;
b : e INT ID ;
e : INT | ;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;
WS : (' '|'\t'|'\n')+ -> skip ;

View File

@ -0,0 +1,21 @@
grammar <grammarName>;
prog: stat ;
stat: expr NEWLINE # printExpr
| ID '=' expr NEWLINE # assign
| NEWLINE # blank
;
expr: expr ('*'|'/') expr # MulDiv
| expr ('+'|'-') expr # AddSub
| INT # int
| ID # id
| '(' expr ')' # parens
;
MUL : '*' ; // assigns token name to '*' used above in grammar
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
ID : [a-zA-Z]+ ; // match identifiers
INT : [0-9]+ ; // match integers
NEWLINE:'\r'? '\n' ; // return newlines to parser (is end-statement signal)
WS : [ \t]+ -> skip ; // toss out whitespace

View File

@ -0,0 +1,14 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : declarator EOF ; // must indicate EOF can follow
declarator
: declarator '[' e ']'
| declarator '[' ']'
| declarator '(' ')'
| '*' declarator // binds less tight than suffixes
| '(' declarator ')'
| ID
;
e : INT ;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,6 @@
grammar <grammarName>;
a @after {<ToStringTree("$ctx"):writeln()>} : a ID
| ID
;
ID : 'a'..'z'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,13 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : e EOF ; // must indicate EOF can follow
e : e '.' ID
| e '.' 'this'
| '-' e
| e '*' e
| e ('+'|'-') e
| INT
| ID
;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,56 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : e EOF ; // must indicate EOF can follow
expressionList
: e (',' e)*
;
e : '(' e ')'
| 'this'
| 'super'
| INT
| ID
| type_ '.' 'class'
| e '.' ID
| e '.' 'this'
| e '.' 'super' '(' expressionList? ')'
| e '.' 'new' ID '(' expressionList? ')'
| 'new' type_ ( '(' expressionList? ')' | ('[' e ']')+)
| e '[' e ']'
| '(' type_ ')' e
| e ('++' | '--')
| e '(' expressionList? ')'
| ('+'|'-'|'++'|'--') e
| ('~'|'!') e
| e ('*'|'/'|'%') e
| e ('+'|'-') e
| e ('\<\<' | '>>>' | '>>') e
| e ('\<=' | '>=' | '>' | '\<') e
| e 'instanceof' e
| e ('==' | '!=') e
| e '&' e
|\<assoc=right> e '^' e
| e '|' e
| e '&&' e
| e '||' e
| e '?' e ':' e
|\<assoc=right>
e ('='
|'+='
|'-='
|'*='
|'/='
|'&='
|'|='
|'^='
|'>>='
|'>>>='
|'\<\<='
|'%=') e
;
type_: ID
| ID '[' ']'
| 'int'
| 'int' '[' ']'
;
ID : ('a'..'z'|'A'..'Z'|'_'|'$')+;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

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,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

@ -0,0 +1,16 @@
grammar <grammarName>;
s : e {<writeln("$e.v")>};
e returns [int v]
: 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 {<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'+ ;
INC : '++' ;
DEC : '--' ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,6 @@
grammar <grammarName>;
prog
@after {<ToStringTree("$ctx"):writeln()>}
: statement* EOF {};
statement: letterA | statement letterA 'b' ;
letterA: 'a';

View File

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

View File

@ -0,0 +1,11 @@
grammar <grammarName>;
s : e {<writeln("$e.v")>};
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;}
| '(' x=e ')' {$v = $x.v;}
;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

View File

@ -0,0 +1,14 @@
grammar <grammarName>;
s : q=e {<writeln("$e.v")>};
e returns [int v]
: a=e op='*' b=e {$v = $a.v * $b.v;} # mult
| a=e '+' b=e {$v = $a.v + $b.v;} # add
| INT {$v = $INT.int;} # anInt
| '(' x=e ')' {$v = $x.v;} # parens
| x=e '++' {$v = $x.v+1;} # inc
| e '--' # dec
| ID {$v = 3;} # anID
;
ID : 'a'..'z'+ ;
INT : '0'..'9'+ ;
WS : (' '|'\n') -> skip ;

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 {<True()>}? ID
| ID
;
ID : 'a'..'z'+ ;
WS : (' '|'\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,7 @@
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : a ;
a : a ID
| 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 : e '*' e
| e '+' e
|\<assoc=right> e '?' e ':' e
|\<assoc=right> e '=' e
| 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

@ -0,0 +1,49 @@
grammar <grammarName>;
prog : expression EOF;
expression
: ID '(' expression (',' expression)* ')' # doFunction
| '(' expression ')' # doParenthesis
| '!' expression # doNot
| '-' expression # doNegate
| '+' expression # doPositiv
| expression '^' expression # doPower
| expression '*' expression # doMultipy
| expression '/' expression # doDivide
| expression '%' expression # doModulo
| expression '-' expression # doMinus
| expression '+' expression # doPlus
| expression '=' expression # doEqual
| expression '!=' expression # doNotEqual
| expression '>' expression # doGreather
| expression '>=' expression # doGreatherEqual
| expression '\<' expression # doLesser
| expression '\<=' expression # doLesserEqual
| expression K_IN '(' expression (',' expression)* ')' # doIn
| expression ( '&' | K_AND) expression # doAnd
| expression ( '|' | K_OR) expression # doOr
| '[' expression (',' expression)* ']' # newArray
| K_TRUE # newTrueBoolean
| K_FALSE # newFalseBoolean
| NUMBER # newNumber
| DATE # newDateTime
| ID # newIdentifier
| SQ_STRING # newString
| K_NULL # newNull
;
// Fragments
fragment DIGIT : '0' .. '9';
fragment UPPER : 'A' .. 'Z';
fragment LOWER : 'a' .. 'z';
fragment LETTER : LOWER | UPPER;
fragment WORD : LETTER | '_' | '$' | '#' | '.';
fragment ALPHANUM : WORD | DIGIT;
// Tokens
ID : LETTER ALPHANUM*;
NUMBER : DIGIT+ ('.' DIGIT+)? (('e'|'E')('+'|'-')? DIGIT+)?;
DATE : '\'' DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT (' ' DIGIT DIGIT ':' DIGIT DIGIT ':' DIGIT DIGIT ('.' DIGIT+)?)? '\'';
SQ_STRING : '\'' ('\'\'' | ~'\'')* '\'';
DQ_STRING : '\"' ('\\\"' | ~'\"')* '\"';
WS : [ \t\n\r]+ -> skip ;
COMMENTS : ('/*' .*? '*/' | '//' ~'\n'* '\n' ) -> skip;

View File

@ -0,0 +1,3 @@
lexer grammar <grammarName>;
A : 'ab' ;
B : 'abc' ;

View File

@ -0,0 +1,4 @@
lexer grammar <grammarName>;
A : 'ab' ;
B : 'abc' ;
C : 'abcd' ;

View File

@ -0,0 +1,3 @@
lexer grammar <grammarName>;
ACTION : '{' (ACTION | ~[{}])* '}';
WS : [ \r\n\t]+ -> skip;

View File

@ -0,0 +1,2 @@
lexer grammar <grammarName>;
A : 'abc' ;

View File

@ -0,0 +1,2 @@
lexer grammar <grammarName>;
A : 'a' 'b' ;

View File

@ -0,0 +1,2 @@
lexer grammar <grammarName>;
A : 'a' 'b' ;

View File

@ -0,0 +1,2 @@
lexer grammar <grammarName>;
A : 'a' 'b' ;

View File

@ -0,0 +1,2 @@
lexer grammar <grammarName>;
A : 'a' 'b' ;

View File

@ -0,0 +1,5 @@
grammar <grammarName>;
start : ID ':' expr;
expr : primary expr? {} | expr '->' ID;
primary : ID;
ID : [a-z]+;

View File

@ -0,0 +1,4 @@
lexer grammar <grammarName>;
ACTION2 : '[' (STRING | ~'"')*? ']';
STRING : '"' ('\\"' | .)*? '"';
WS : [ \t\r\n]+ -> skip;

View File

@ -0,0 +1,8 @@
lexer grammar <grammarName>;
I : ({<PlusText("stuff fail: "):writeln()>} 'a'
| {<PlusText("stuff0: "):writeln()>}
'a' {<PlusText("stuff1: "):writeln()>}
'b' {<PlusText("stuff2: "):writeln()>})
{<Text():writeln()>} ;
WS : (' '|'\n') -> skip ;
J : .;

Some files were not shown because too many files have changed in this diff Show More