mirror of
https://github.com/marcin-szczepanski/jFuzzyLogic.git
synced 2024-11-15 04:35:28 +01:00
868 lines
29 KiB
Java
868 lines
29 KiB
Java
|
/*
|
||
|
[The "BSD licence"]
|
||
|
Copyright (c) 2005-2007 Terence Parr
|
||
|
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.test;
|
||
|
|
||
|
import org.antlr.Tool;
|
||
|
import org.antlr.tool.*;
|
||
|
|
||
|
public class TestCompositeGrammars extends BaseTest {
|
||
|
protected boolean debug = false;
|
||
|
|
||
|
public void testWildcardStillWorks() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String grammar =
|
||
|
"parser grammar S;\n" +
|
||
|
"a : B . C ;\n"; // not qualified ID
|
||
|
Grammar g = new Grammar(grammar);
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
}
|
||
|
|
||
|
public void testDelegatorInvokesDelegateRule() throws Exception {
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"a : B {System.out.println(\"S.a\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", 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.g", master, "MParser", "MLexer",
|
||
|
"s", "b", debug);
|
||
|
assertEquals("S.a\n", found);
|
||
|
}
|
||
|
|
||
|
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.g", 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.g", master, "MParser", "MLexer",
|
||
|
"s", "b", debug);
|
||
|
assertEquals("S.a1000\n", found);
|
||
|
}
|
||
|
|
||
|
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.g", 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.g", master, "MParser", "MLexer",
|
||
|
"s", "b", debug);
|
||
|
assertEquals("S.ab\n", found);
|
||
|
}
|
||
|
|
||
|
public void testDelegatorAccessesDelegateMembers() throws Exception {
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"@members {\n" +
|
||
|
" public void foo() {System.out.println(\"foo\");}\n" +
|
||
|
"}\n" +
|
||
|
"a : B ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String master =
|
||
|
"grammar M;\n" + // uses no rules from the import
|
||
|
"import S;\n" +
|
||
|
"s : 'b' {gS.foo();} ;\n" + // gS is import pointer
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
String found = execParser("M.g", master, "MParser", "MLexer",
|
||
|
"s", "b", debug);
|
||
|
assertEquals("foo\n", found);
|
||
|
}
|
||
|
|
||
|
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.g", slave);
|
||
|
String slave2 =
|
||
|
"parser grammar T;\n" +
|
||
|
"a : B {System.out.println(\"T.a\");} ;\n"; // hidden by S.a
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "T.g", slave2);
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S,T;\n" +
|
||
|
"s : a ;\n" +
|
||
|
"B : 'b' ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
String found = execParser("M.g", master, "MParser", "MLexer",
|
||
|
"s", "b", debug);
|
||
|
assertEquals("S.a\n", found);
|
||
|
}
|
||
|
|
||
|
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.g", 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.g", 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.g", master, "MParser", "MLexer",
|
||
|
"s", "aa", debug);
|
||
|
assertEquals("S.x\n" +
|
||
|
"T.y\n", found);
|
||
|
}
|
||
|
|
||
|
public void testDelegatesSeeSameTokenType2() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
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.g", 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.g", 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.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
String expectedTokenIDToTypeMap = "[A=4, B=5, C=6, WS=7]";
|
||
|
String expectedStringLiteralToTypeMap = "{}";
|
||
|
String expectedTypeToTokenList = "[A, B, C, WS]";
|
||
|
|
||
|
assertEquals(expectedTokenIDToTypeMap,
|
||
|
realElements(g.composite.tokenIDToTypeMap).toString());
|
||
|
assertEquals(expectedStringLiteralToTypeMap, g.composite.stringLiteralToTypeMap.toString());
|
||
|
assertEquals(expectedTypeToTokenList,
|
||
|
realElements(g.composite.typeToTokenList).toString());
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
}
|
||
|
|
||
|
public void testCombinedImportsCombined() throws Exception {
|
||
|
// for now, we don't allow combined to import combined
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
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.g", slave);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"s : x INT ;\n";
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 1, equeue.errors.size());
|
||
|
String expectedError = "error(161): /tmp/antlr3/M.g:2:8: combined grammar M cannot import combined grammar S";
|
||
|
assertEquals("unexpected errors: "+equeue, expectedError, equeue.errors.get(0).toString().replaceFirst("\\-[0-9]+","3"));
|
||
|
}
|
||
|
|
||
|
public void testSameStringTwoNames() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"tokens { A='a'; }\n" +
|
||
|
"x : A {System.out.println(\"S.x\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String slave2 =
|
||
|
"parser grammar T;\n" +
|
||
|
"tokens { X='a'; }\n" +
|
||
|
"y : X {System.out.println(\"T.y\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "T.g", slave2);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S,T;\n" +
|
||
|
"s : x y ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
String expectedTokenIDToTypeMap = "[A=4, WS=6, X=5]";
|
||
|
String expectedStringLiteralToTypeMap = "{'a'=4}";
|
||
|
String expectedTypeToTokenList = "[A, X, WS]";
|
||
|
|
||
|
assertEquals(expectedTokenIDToTypeMap,
|
||
|
realElements(g.composite.tokenIDToTypeMap).toString());
|
||
|
assertEquals(expectedStringLiteralToTypeMap, g.composite.stringLiteralToTypeMap.toString());
|
||
|
assertEquals(expectedTypeToTokenList,
|
||
|
realElements(g.composite.typeToTokenList).toString());
|
||
|
|
||
|
Object expectedArg = "X='a'";
|
||
|
Object expectedArg2 = "A";
|
||
|
int expectedMsgID = ErrorManager.MSG_TOKEN_ALIAS_CONFLICT;
|
||
|
GrammarSemanticsMessage expectedMessage =
|
||
|
new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
|
||
|
checkGrammarSemanticsError(equeue, expectedMessage);
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 1, equeue.errors.size());
|
||
|
|
||
|
String expectedError =
|
||
|
"error(158): T.g:2:10: cannot alias X='a'; string already assigned to A";
|
||
|
assertEquals(expectedError, equeue.errors.get(0).toString());
|
||
|
}
|
||
|
|
||
|
public void testSameNameTwoStrings() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"tokens { A='a'; }\n" +
|
||
|
"x : A {System.out.println(\"S.x\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String slave2 =
|
||
|
"parser grammar T;\n" +
|
||
|
"tokens { A='x'; }\n" +
|
||
|
"y : A {System.out.println(\"T.y\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "T.g", slave2);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S,T;\n" +
|
||
|
"s : x y ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
String expectedTokenIDToTypeMap = "[A=4, T__6=6, WS=5]";
|
||
|
String expectedStringLiteralToTypeMap = "{'x'=6, 'a'=4}";
|
||
|
String expectedTypeToTokenList = "[A, WS, T__6]";
|
||
|
|
||
|
assertEquals(expectedTokenIDToTypeMap,
|
||
|
realElements(g.composite.tokenIDToTypeMap).toString());
|
||
|
assertEquals(expectedStringLiteralToTypeMap, g.composite.stringLiteralToTypeMap.toString());
|
||
|
assertEquals(expectedTypeToTokenList,
|
||
|
realElements(g.composite.typeToTokenList).toString());
|
||
|
|
||
|
Object expectedArg = "A='x'";
|
||
|
Object expectedArg2 = "'a'";
|
||
|
int expectedMsgID = ErrorManager.MSG_TOKEN_ALIAS_REASSIGNMENT;
|
||
|
GrammarSemanticsMessage expectedMessage =
|
||
|
new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg, expectedArg2);
|
||
|
checkGrammarSemanticsError(equeue, expectedMessage);
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 1, equeue.errors.size());
|
||
|
|
||
|
String expectedError =
|
||
|
"error(159): T.g:2:10: cannot alias A='x'; token name already assigned to 'a'";
|
||
|
assertEquals(expectedError, equeue.errors.get(0).toString());
|
||
|
}
|
||
|
|
||
|
public void testImportedTokenVocabIgnoredWithWarning() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"options {tokenVocab=whatever;}\n" +
|
||
|
"tokens { A='a'; }\n" +
|
||
|
"x : A {System.out.println(\"S.x\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"s : x ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
Object expectedArg = "S";
|
||
|
int expectedMsgID = ErrorManager.MSG_TOKEN_VOCAB_IN_DELEGATE;
|
||
|
GrammarSemanticsMessage expectedMessage =
|
||
|
new GrammarSemanticsMessage(expectedMsgID, g, null, expectedArg);
|
||
|
checkGrammarSemanticsWarning(equeue, expectedMessage);
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
assertEquals("unexpected errors: "+equeue, 1, equeue.warnings.size());
|
||
|
|
||
|
String expectedError =
|
||
|
"warning(160): S.g:2:10: tokenVocab option ignored in imported grammar S";
|
||
|
assertEquals(expectedError, equeue.warnings.get(0).toString());
|
||
|
}
|
||
|
|
||
|
public void testImportedTokenVocabWorksInRoot() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"tokens { A='a'; }\n" +
|
||
|
"x : A {System.out.println(\"S.x\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
|
||
|
String tokens =
|
||
|
"A=99\n";
|
||
|
writeFile(tmpdir, "Test.tokens", tokens);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"options {tokenVocab=Test;}\n" +
|
||
|
"import S;\n" +
|
||
|
"s : x ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
String expectedTokenIDToTypeMap = "[A=99, WS=101]";
|
||
|
String expectedStringLiteralToTypeMap = "{'a'=100}";
|
||
|
String expectedTypeToTokenList = "[A, 'a', WS]";
|
||
|
|
||
|
assertEquals(expectedTokenIDToTypeMap,
|
||
|
realElements(g.composite.tokenIDToTypeMap).toString());
|
||
|
assertEquals(expectedStringLiteralToTypeMap, g.composite.stringLiteralToTypeMap.toString());
|
||
|
assertEquals(expectedTypeToTokenList,
|
||
|
realElements(g.composite.typeToTokenList).toString());
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
}
|
||
|
|
||
|
public void testSyntaxErrorsInImportsNotThrownOut() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"options {toke\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"s : x ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
// whole bunch of errors from bad S.g file
|
||
|
assertEquals("unexpected errors: "+equeue, 5, equeue.errors.size());
|
||
|
}
|
||
|
|
||
|
public void testSyntaxErrorsInImportsNotThrownOut2() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
": A {System.out.println(\"S.x\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"s : x ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
|
||
|
// whole bunch of errors from bad S.g file
|
||
|
assertEquals("unexpected errors: "+equeue, 3, equeue.errors.size());
|
||
|
}
|
||
|
|
||
|
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.g", slave);
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"b : 'b'|'c' ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
String found = execParser("M.g", master, "MParser", "MLexer",
|
||
|
"a", "c", debug);
|
||
|
assertEquals("S.a\n", found);
|
||
|
}
|
||
|
|
||
|
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: \"+$decl.text);}\n" +
|
||
|
" ;\n" +
|
||
|
"init : '=' INT ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "JavaDecl.g", 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.g", master, "JavaParser", "JavaLexer",
|
||
|
"prog", "float x = 3;", debug);
|
||
|
assertEquals("JavaDecl: floatx=3;\n", found);
|
||
|
}
|
||
|
|
||
|
// LEXER INHERITANCE
|
||
|
|
||
|
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.g", slave);
|
||
|
String master =
|
||
|
"lexer grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"B : 'b' ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
String found = execLexer("M.g", master, "M", "abc", debug);
|
||
|
assertEquals("S.A\nabc\n", found);
|
||
|
}
|
||
|
|
||
|
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.g", 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.g", master, "M", "ab", debug);
|
||
|
assertEquals("S.B\n" +
|
||
|
"M.A\n" +
|
||
|
"ab\n", found);
|
||
|
}
|
||
|
|
||
|
public void testLexerDelegatorRuleOverridesDelegateLeavingNoRules() throws Exception {
|
||
|
// M.Tokens has nothing to predict tokens from S. Should
|
||
|
// not include S.Tokens alt in this case?
|
||
|
String slave =
|
||
|
"lexer grammar S;\n" +
|
||
|
"A : 'a' {System.out.println(\"S.A\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String master =
|
||
|
"lexer grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"A : 'a' {System.out.println(\"M.A\");} ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
writeFile(tmpdir, "/M.g", master);
|
||
|
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
composite.assignTokenTypes();
|
||
|
composite.defineGrammarSymbols();
|
||
|
composite.createNFAs();
|
||
|
g.createLookaheadDFAs(false);
|
||
|
|
||
|
// predict only alts from M not S
|
||
|
String expectingDFA =
|
||
|
".s0-'a'->.s1\n" +
|
||
|
".s0-{'\\n', ' '}->:s3=>2\n" +
|
||
|
".s1-<EOT>->:s2=>1\n";
|
||
|
org.antlr.analysis.DFA dfa = g.getLookaheadDFA(1);
|
||
|
FASerializer serializer = new FASerializer(g);
|
||
|
String result = serializer.serialize(dfa.startState);
|
||
|
assertEquals(expectingDFA, result);
|
||
|
|
||
|
// must not be a "unreachable alt: Tokens" error
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
}
|
||
|
|
||
|
public void testInvalidImportMechanism() throws Exception {
|
||
|
// M.Tokens has nothing to predict tokens from S. Should
|
||
|
// not include S.Tokens alt in this case?
|
||
|
String slave =
|
||
|
"lexer grammar S;\n" +
|
||
|
"A : 'a' {System.out.println(\"S.A\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String master =
|
||
|
"tree grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"a : A ;";
|
||
|
writeFile(tmpdir, "/M.g", master);
|
||
|
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 1, equeue.errors.size());
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.warnings.size());
|
||
|
|
||
|
String expectedError =
|
||
|
"error(161): /tmp/antlr3/M.g:2:8: tree grammar M cannot import lexer grammar S";
|
||
|
assertEquals(expectedError, equeue.errors.get(0).toString().replaceFirst("\\-[0-9]+","3"));
|
||
|
}
|
||
|
|
||
|
public void testSyntacticPredicateRulesAreNotInherited() throws Exception {
|
||
|
// if this compiles, it means that synpred1_S is defined in S.java
|
||
|
// but not MParser.java. MParser has its own synpred1_M which must
|
||
|
// be separate to compile.
|
||
|
String slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"a : 'a' {System.out.println(\"S.a1\");}\n" +
|
||
|
" | 'a' {System.out.println(\"S.a2\");}\n" +
|
||
|
" ;\n" +
|
||
|
"b : 'x' | 'y' {;} ;\n"; // preds generated but not need in DFA here
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"options {backtrack=true;}\n" +
|
||
|
"import S;\n" +
|
||
|
"start : a b ;\n" +
|
||
|
"nonsense : 'q' | 'q' {;} ;" + // forces def of preds here in M
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
String found = execParser("M.g", master, "MParser", "MLexer",
|
||
|
"start", "ax", debug);
|
||
|
assertEquals("S.a1\n", found);
|
||
|
}
|
||
|
|
||
|
public void testKeywordVSIDGivesNoWarning() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"lexer grammar S;\n" +
|
||
|
"A : 'abc' {System.out.println(\"S.A\");} ;\n" +
|
||
|
"ID : 'a'..'z'+ ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"a : A {System.out.println(\"M.a\");} ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
String found = execParser("M.g", master, "MParser", "MLexer",
|
||
|
"a", "abc", debug);
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
assertEquals("unexpected warnings: "+equeue, 0, equeue.warnings.size());
|
||
|
|
||
|
assertEquals("S.A\nM.a\n", found);
|
||
|
}
|
||
|
|
||
|
public void testWarningForUndefinedToken() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"lexer grammar S;\n" +
|
||
|
"A : 'abc' {System.out.println(\"S.A\");} ;\n";
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"a : ABC A {System.out.println(\"M.a\");} ;\n" +
|
||
|
"WS : (' '|'\\n') {skip();} ;\n" ;
|
||
|
// A is defined in S but M should still see it and not give warning.
|
||
|
// only problem is ABC.
|
||
|
|
||
|
rawGenerateAndBuildRecognizer("M.g", master, "MParser", "MLexer", debug);
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
assertEquals("unexpected warnings: "+equeue, 1, equeue.warnings.size());
|
||
|
|
||
|
String expectedError =
|
||
|
"warning(105): /tmp/antlr3/M.g:3:5: no lexer rule corresponding to token: ABC";
|
||
|
assertEquals(expectedError, equeue.warnings.get(0).toString().replaceFirst("\\-[0-9]+","3"));
|
||
|
}
|
||
|
|
||
|
/** Make sure that M can import S that imports T. */
|
||
|
public void test3LevelImport() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar T;\n" +
|
||
|
"a : T ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "T.g", slave);
|
||
|
String slave2 =
|
||
|
"parser grammar S;\n" + // A, B, C token type order
|
||
|
"import T;\n" +
|
||
|
"a : S ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave2);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"a : M ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
g.composite.defineGrammarSymbols();
|
||
|
|
||
|
String expectedTokenIDToTypeMap = "[M=6, S=5, T=4]";
|
||
|
String expectedStringLiteralToTypeMap = "{}";
|
||
|
String expectedTypeToTokenList = "[T, S, M]";
|
||
|
|
||
|
assertEquals(expectedTokenIDToTypeMap,
|
||
|
realElements(g.composite.tokenIDToTypeMap).toString());
|
||
|
assertEquals(expectedStringLiteralToTypeMap, g.composite.stringLiteralToTypeMap.toString());
|
||
|
assertEquals(expectedTypeToTokenList,
|
||
|
realElements(g.composite.typeToTokenList).toString());
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
|
||
|
boolean ok =
|
||
|
rawGenerateAndBuildRecognizer("M.g", master, "MParser", null, false);
|
||
|
boolean expecting = true; // should be ok
|
||
|
assertEquals(expecting, ok);
|
||
|
}
|
||
|
|
||
|
public void testBigTreeOfImports() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar T;\n" +
|
||
|
"x : T ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "T.g", slave);
|
||
|
slave =
|
||
|
"parser grammar S;\n" +
|
||
|
"import T;\n" +
|
||
|
"y : S ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave);
|
||
|
|
||
|
slave =
|
||
|
"parser grammar C;\n" +
|
||
|
"i : C ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "C.g", slave);
|
||
|
slave =
|
||
|
"parser grammar B;\n" +
|
||
|
"j : B ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "B.g", slave);
|
||
|
slave =
|
||
|
"parser grammar A;\n" +
|
||
|
"import B,C;\n" +
|
||
|
"k : A ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "A.g", slave);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S,A;\n" +
|
||
|
"a : M ;\n" ;
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
g.composite.defineGrammarSymbols();
|
||
|
|
||
|
String expectedTokenIDToTypeMap = "[A=8, B=6, C=7, M=9, S=5, T=4]";
|
||
|
String expectedStringLiteralToTypeMap = "{}";
|
||
|
String expectedTypeToTokenList = "[T, S, B, C, A, M]";
|
||
|
|
||
|
assertEquals(expectedTokenIDToTypeMap,
|
||
|
realElements(g.composite.tokenIDToTypeMap).toString());
|
||
|
assertEquals(expectedStringLiteralToTypeMap, g.composite.stringLiteralToTypeMap.toString());
|
||
|
assertEquals(expectedTypeToTokenList,
|
||
|
realElements(g.composite.typeToTokenList).toString());
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
|
||
|
boolean ok =
|
||
|
rawGenerateAndBuildRecognizer("M.g", master, "MParser", null, false);
|
||
|
boolean expecting = true; // should be ok
|
||
|
assertEquals(expecting, ok);
|
||
|
}
|
||
|
|
||
|
public void testRulesVisibleThroughMultilevelImport() throws Exception {
|
||
|
ErrorQueue equeue = new ErrorQueue();
|
||
|
ErrorManager.setErrorListener(equeue);
|
||
|
String slave =
|
||
|
"parser grammar T;\n" +
|
||
|
"x : T ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "T.g", slave);
|
||
|
String slave2 =
|
||
|
"parser grammar S;\n" + // A, B, C token type order
|
||
|
"import T;\n" +
|
||
|
"a : S ;\n" ;
|
||
|
mkdir(tmpdir);
|
||
|
writeFile(tmpdir, "S.g", slave2);
|
||
|
|
||
|
String master =
|
||
|
"grammar M;\n" +
|
||
|
"import S;\n" +
|
||
|
"a : M x ;\n" ; // x MUST BE VISIBLE TO M
|
||
|
writeFile(tmpdir, "M.g", master);
|
||
|
Tool antlr = newTool(new String[] {"-lib", tmpdir});
|
||
|
CompositeGrammar composite = new CompositeGrammar();
|
||
|
Grammar g = new Grammar(antlr,tmpdir+"/M.g",composite);
|
||
|
composite.setDelegationRoot(g);
|
||
|
g.parseAndBuildAST();
|
||
|
g.composite.assignTokenTypes();
|
||
|
g.composite.defineGrammarSymbols();
|
||
|
|
||
|
String expectedTokenIDToTypeMap = "[M=6, S=5, T=4]";
|
||
|
String expectedStringLiteralToTypeMap = "{}";
|
||
|
String expectedTypeToTokenList = "[T, S, M]";
|
||
|
|
||
|
assertEquals(expectedTokenIDToTypeMap,
|
||
|
realElements(g.composite.tokenIDToTypeMap).toString());
|
||
|
assertEquals(expectedStringLiteralToTypeMap, g.composite.stringLiteralToTypeMap.toString());
|
||
|
assertEquals(expectedTypeToTokenList,
|
||
|
realElements(g.composite.typeToTokenList).toString());
|
||
|
|
||
|
assertEquals("unexpected errors: "+equeue, 0, equeue.errors.size());
|
||
|
}
|
||
|
|
||
|
}
|