001: /*
002: [The "BSD licence"]
003: Copyright (c) 2005-2006 Terence Parr
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011: 2. Redistributions in binary form must reproduce the above copyright
012: notice, this list of conditions and the following disclaimer in the
013: documentation and/or other materials provided with the distribution.
014: 3. The name of the author may not be used to endorse or promote products
015: derived from this software without specific prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package org.antlr.test;
029:
030: public class TestSyntacticPredicateEvaluation extends BaseTest {
031: public void testTwoPredsWithNakedAlt() throws Exception {
032: String grammar = "grammar t;\n"
033: + "s : (a ';')+ ;\n"
034: + "a\n"
035: + "options {\n"
036: + " k=1;\n"
037: + "}\n"
038: + " : (b '.')=> b '.' {System.out.println(\"alt 1\");}\n"
039: + " | (b)=> b {System.out.println(\"alt 2\");}\n"
040: + " | c {System.out.println(\"alt 3\");}\n"
041: + " ;\n" + "b\n"
042: + "@init {System.out.println(\"enter b\");}\n"
043: + " : '(' 'x' ')' ;\n" + "c\n"
044: + "@init {System.out.println(\"enter c\");}\n"
045: + " : '(' c ')' | 'x' ;\n"
046: + "WS : (' '|'\\n')+ {$channel=HIDDEN;}\n" + " ;\n";
047: String found = execParser("t.g", grammar, "tParser", "tLexer",
048: "a", "(x) ;", false);
049: String expecting = "enter b\n" + "enter b\n" + "enter b\n"
050: + "alt 2\n";
051: assertEquals(expecting, found);
052:
053: found = execParser("t.g", grammar, "tParser", "tLexer", "a",
054: "(x). ;", false);
055: expecting = "enter b\n" + "enter b\n" + "alt 1\n";
056: assertEquals(expecting, found);
057:
058: found = execParser("t.g", grammar, "tParser", "tLexer", "a",
059: "((x)) ;", false);
060: expecting = "enter b\n" + "enter b\n" + "enter c\n"
061: + "enter c\n" + "enter c\n" + "alt 3\n";
062: assertEquals(expecting, found);
063: }
064:
065: public void testTwoPredsWithNakedAltNotLast() throws Exception {
066: String grammar = "grammar t;\n"
067: + "s : (a ';')+ ;\n"
068: + "a\n"
069: + "options {\n"
070: + " k=1;\n"
071: + "}\n"
072: + " : (b '.')=> b '.' {System.out.println(\"alt 1\");}\n"
073: + " | c {System.out.println(\"alt 2\");}\n"
074: + " | (b)=> b {System.out.println(\"alt 3\");}\n"
075: + " ;\n" + "b\n"
076: + "@init {System.out.println(\"enter b\");}\n"
077: + " : '(' 'x' ')' ;\n" + "c\n"
078: + "@init {System.out.println(\"enter c\");}\n"
079: + " : '(' c ')' | 'x' ;\n"
080: + "WS : (' '|'\\n')+ {$channel=HIDDEN;}\n" + " ;\n";
081: String found = execParser("t.g", grammar, "tParser", "tLexer",
082: "a", "(x) ;", false);
083: String expecting = "enter b\n" + "enter c\n" + "enter c\n"
084: + "alt 2\n";
085: assertEquals(expecting, found);
086:
087: found = execParser("t.g", grammar, "tParser", "tLexer", "a",
088: "(x). ;", false);
089: expecting = "enter b\n" + "enter b\n" + "alt 1\n";
090: assertEquals(expecting, found);
091:
092: found = execParser("t.g", grammar, "tParser", "tLexer", "a",
093: "((x)) ;", false);
094: expecting = "enter b\n" + "enter c\n" + "enter c\n"
095: + "enter c\n" + "alt 2\n";
096: assertEquals(expecting, found);
097: }
098:
099: public void testLexerPred() throws Exception {
100: String grammar = "grammar t;\n"
101: + "s : A ;\n"
102: + "A options {k=1;}\n"
103: + // force backtracking
104: " : (B '.')=>B '.' {System.out.println(\"alt1\");}\n"
105: + " | B {System.out.println(\"alt2\");}" + " ;\n"
106: + "fragment\n" + "B : 'x'+ ;\n";
107: String found = execParser("t.g", grammar, "tParser", "tLexer",
108: "s", "xxx", false);
109:
110: assertEquals("alt2\n", found);
111:
112: found = execParser("t.g", grammar, "tParser", "tLexer", "s",
113: "xxx.", false);
114:
115: assertEquals("alt1\n", found);
116: }
117:
118: public void testLexerWithPredLongerThanAlt() throws Exception {
119: String grammar = "grammar t;\n"
120: + "s : A ;\n"
121: + "A options {k=1;}\n"
122: + // force backtracking
123: " : (B '.')=>B {System.out.println(\"alt1\");}\n"
124: + " | B {System.out.println(\"alt2\");}" + " ;\n"
125: + "D : '.' {System.out.println(\"D\");} ;\n"
126: + "fragment\n" + "B : 'x'+ ;\n";
127: String found = execParser("t.g", grammar, "tParser", "tLexer",
128: "s", "xxx", false);
129:
130: assertEquals("alt2\n", found);
131:
132: found = execParser("t.g", grammar, "tParser", "tLexer", "s",
133: "xxx.", false);
134:
135: assertEquals("alt1\nD\n", found);
136: }
137:
138: public void testLexerPredCyclicPrediction() throws Exception {
139: String grammar = "grammar t;\n" + "s : A ;\n"
140: + "A : (B)=>(B|'y'+) {System.out.println(\"alt1\");}\n"
141: + " | B {System.out.println(\"alt2\");}\n"
142: + " | 'y'+ ';'" + " ;\n" + "fragment\n"
143: + "B : 'x'+ ;\n";
144: String found = execParser("t.g", grammar, "tParser", "tLexer",
145: "s", "xxx", false);
146:
147: assertEquals("alt1\n", found);
148: }
149:
150: public void testLexerPredCyclicPrediction2() throws Exception {
151: String grammar = "grammar t;\n"
152: + "s : A ;\n"
153: + "A : (B '.')=>(B|'y'+) {System.out.println(\"alt1\");}\n"
154: + " | B {System.out.println(\"alt2\");}\n"
155: + " | 'y'+ ';'" + " ;\n" + "fragment\n"
156: + "B : 'x'+ ;\n";
157: String found = execParser("t.g", grammar, "tParser", "tLexer",
158: "s", "xxx", false);
159: assertEquals("alt2\n", found);
160: }
161:
162: public void testSimpleNestedPred() throws Exception {
163: String grammar = "grammar t;\n"
164: + "s : (expr ';')+ ;\n"
165: + "expr\n"
166: + "options {\n"
167: + " k=1;\n"
168: + "}\n"
169: + "@init {System.out.println(\"enter expr \"+input.LT(1).getText());}\n"
170: + " : (atom 'x') => atom 'x'\n"
171: + " | atom\n"
172: + ";\n"
173: + "atom\n"
174: + "@init {System.out.println(\"enter atom \"+input.LT(1).getText());}\n"
175: + " : '(' expr ')'\n" + " | INT\n" + " ;\n"
176: + "INT: '0'..'9'+ ;\n"
177: + "WS : (' '|'\\n')+ {$channel=HIDDEN;}\n" + " ;\n";
178: String found = execParser("t.g", grammar, "tParser", "tLexer",
179: "s", "(34)x;", false);
180: String expecting = "enter expr (\n" + "enter atom (\n"
181: + "enter expr 34\n" + "enter atom 34\n"
182: + "enter atom 34\n" + "enter atom (\n"
183: + "enter expr 34\n" + "enter atom 34\n"
184: + "enter atom 34\n";
185: assertEquals(expecting, found);
186: }
187:
188: public void testTripleNestedPredInLexer() throws Exception {
189: String grammar = "grammar t;\n"
190: + "s : (.)+ {System.out.println(\"done\");} ;\n"
191: + "EXPR\n"
192: + "options {\n"
193: + " k=1;\n"
194: + "}\n"
195: + "@init {System.out.println(\"enter expr \"+(char)input.LT(1));}\n"
196: + " : (ATOM 'x') => ATOM 'x' {System.out.println(\"ATOM x\");}\n"
197: + " | ATOM {System.out.println(\"ATOM \"+$ATOM.text);}\n"
198: + ";\n"
199: + "fragment ATOM\n"
200: + "@init {System.out.println(\"enter atom \"+(char)input.LT(1));}\n"
201: + " : '(' EXPR ')'\n" + " | INT\n" + " ;\n"
202: + "fragment INT: '0'..'9'+ ;\n"
203: + "fragment WS : (' '|'\\n')+ \n" + " ;\n";
204: String found = execParser("t.g", grammar, "tParser", "tLexer",
205: "s", "((34)x)x", false);
206: String expecting = // has no memoization
207: "enter expr (\n" + "enter atom (\n" + "enter expr (\n"
208: + "enter atom (\n" + "enter expr 3\n"
209: + "enter atom 3\n" + "enter atom 3\n"
210: + "enter atom (\n" + "enter expr 3\n"
211: + "enter atom 3\n" + "enter atom 3\n"
212: + "enter atom (\n" + "enter expr (\n"
213: + "enter atom (\n" + "enter expr 3\n"
214: + "enter atom 3\n" + "enter atom 3\n"
215: + "enter atom (\n" + "enter expr 3\n"
216: + "enter atom 3\n" + "enter atom 3\n" + "ATOM 34\n"
217: + "ATOM x\n" + "ATOM x\n" + "done\n";
218: assertEquals(expecting, found);
219: }
220:
221: public void testTreeParserWithSynPred() throws Exception {
222: String grammar = "grammar T;\n" + "options {output=AST;}\n"
223: + "a : ID INT+ (PERIOD|SEMI);\n" + "ID : 'a'..'z'+ ;\n"
224: + "INT : '0'..'9'+;\n" + "SEMI : ';' ;\n"
225: + "PERIOD : '.' ;\n"
226: + "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
227:
228: String treeGrammar = "tree grammar TP;\n"
229: + "options {k=1; backtrack=true; ASTLabelType=CommonTree; tokenVocab=T;}\n"
230: + "a : ID INT+ PERIOD {System.out.print(\"alt 1\");}"
231: + " | ID INT+ SEMI {System.out.print(\"alt 2\");}\n"
232: + " ;\n";
233:
234: String found = execTreeParser("T.g", grammar, "TParser",
235: "TP.g", treeGrammar, "TP", "TLexer", "a", "a",
236: "a 1 2 3;");
237: assertEquals("alt 2\n", found);
238: }
239:
240: public void testTreeParserWithNestedSynPred() throws Exception {
241: String grammar = "grammar T;\n" + "options {output=AST;}\n"
242: + "a : ID INT+ (PERIOD|SEMI);\n" + "ID : 'a'..'z'+ ;\n"
243: + "INT : '0'..'9'+;\n" + "SEMI : ';' ;\n"
244: + "PERIOD : '.' ;\n"
245: + "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n";
246:
247: // backtracks in a and b due to k=1
248: String treeGrammar = "tree grammar TP;\n"
249: + "options {k=1; backtrack=true; ASTLabelType=CommonTree; tokenVocab=T;}\n"
250: + "a : ID b {System.out.print(\" a:alt 1\");}"
251: + " | ID INT+ SEMI {System.out.print(\" a:alt 2\");}\n"
252: + " ;\n"
253: + "b : INT PERIOD {System.out.print(\"b:alt 1\");}"
254: + // choose this alt for just one INT
255: " | INT+ PERIOD {System.out.print(\"b:alt 2\");}"
256: + " ;";
257:
258: String found = execTreeParser("T.g", grammar, "TParser",
259: "TP.g", treeGrammar, "TP", "TLexer", "a", "a",
260: "a 1 2 3.");
261: assertEquals("b:alt 2 a:alt 1\n", found);
262: }
263:
264: public void testSynPredWithOutputTemplate() throws Exception {
265: // really just seeing if it will compile
266: String grammar = "grammar t;\n"
267: + "options {output=template;}\n"
268: + "a\n"
269: + "options {\n"
270: + " k=1;\n"
271: + "}\n"
272: + " : ('x'+ 'y')=> 'x'+ 'y' -> template(a={$text}) <<1:<a>;>>\n"
273: + " | 'x'+ 'z' -> template(a={$text}) <<2:<a>;>>\n"
274: + " ;\n" + "WS : (' '|'\\n')+ {$channel=HIDDEN;}\n"
275: + " ;\n";
276: String found = execParser("t.g", grammar, "tParser", "tLexer",
277: "a", "xxxy", false);
278:
279: assertEquals("1:xxxy;\n", found);
280: }
281:
282: public void testSynPredWithOutputAST() throws Exception {
283: // really just seeing if it will compile
284: String grammar = "grammar t;\n" + "options {output=AST;}\n"
285: + "a\n" + "options {\n" + " k=1;\n" + "}\n"
286: + " : ('x'+ 'y')=> 'x'+ 'y'\n" + " | 'x'+ 'z'\n"
287: + " ;\n" + "WS : (' '|'\\n')+ {$channel=HIDDEN;}\n"
288: + " ;\n";
289: String found = execParser("t.g", grammar, "tParser", "tLexer",
290: "a", "xxxy", false);
291:
292: assertEquals("x x x y\n", found);
293: }
294:
295: public void testOptionalBlockWithSynPred() throws Exception {
296: String grammar = "grammar t;\n" + "\n"
297: + "a : ( (b)=> b {System.out.println(\"b\");})? b ;\n"
298: + "b : 'x' ;\n";
299: String found = execParser("t.g", grammar, "tParser", "tLexer",
300: "a", "xx", false);
301:
302: assertEquals("b\n", found);
303: }
304:
305: public void testSynPredK2() throws Exception {
306: String grammar = "grammar t;\n"
307: + "\n"
308: + "a : (b)=> b {System.out.println(\"alt1\");} | 'a' 'c' ;\n"
309: + "b : 'a' 'b' ;\n";
310: String found = execParser("t.g", grammar, "tParser", "tLexer",
311: "a", "ab", false);
312:
313: assertEquals("alt1\n", found);
314: }
315:
316: public void testSynPredKStar() throws Exception {
317: String grammar = "grammar t;\n"
318: + "\n"
319: + "a : (b)=> b {System.out.println(\"alt1\");} | 'a'+ 'c' ;\n"
320: + "b : 'a'+ 'b' ;\n";
321: String found = execParser("t.g", grammar, "tParser", "tLexer",
322: "a", "aaab", false);
323:
324: assertEquals("alt1\n", found);
325: }
326:
327: }
|