1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2010 Terence Parr 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 package org.antlr.test; 29 30 import org.junit.Test; 31 32 /** Test hetero trees in parsers and tree parsers */ 33 public class TestHeteroAST extends BaseTest { 34 protected boolean debug = false; 35 36 // PARSERS -- AUTO AST 37 testToken()38 @Test public void testToken() throws Exception { 39 String grammar = 40 "grammar T;\n" + 41 "options {output=AST;}\n" + 42 "@members {static class V extends CommonTree {\n" + 43 " public V(Token t) { token=t;}\n" + 44 " public String toString() { return token.getText()+\"<V>\";}\n" + 45 "}\n" + 46 "}\n"+ 47 "a : ID<V> ;\n"+ 48 "ID : 'a'..'z'+ ;\n" + 49 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 50 String found = execParser("T.g", grammar, "TParser", "TLexer", 51 "a", "a", debug); 52 assertEquals("a<V>\n", found); 53 } 54 testTokenCommonTree()55 @Test public void testTokenCommonTree() throws Exception { 56 String grammar = 57 "grammar T;\n" + 58 "options {output=AST;}\n" + 59 "a : ID<CommonTree> ;\n"+ 60 "ID : 'a'..'z'+ ;\n" + 61 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 62 String found = execParser("T.g", grammar, "TParser", "TLexer", 63 "a", "a", debug); 64 assertEquals("a\n", found); 65 } 66 testTokenWithQualifiedType()67 @Test public void testTokenWithQualifiedType() throws Exception { 68 String grammar = 69 "grammar T;\n" + 70 "options {output=AST;}\n" + 71 "@members {static class V extends CommonTree {\n" + 72 " public V(Token t) { token=t;}\n" + 73 " public String toString() { return token.getText()+\"<V>\";}\n" + 74 "}\n" + 75 "}\n"+ 76 "a : ID<TParser.V> ;\n"+ // TParser.V is qualified name 77 "ID : 'a'..'z'+ ;\n" + 78 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 79 String found = execParser("T.g", grammar, "TParser", "TLexer", 80 "a", "a", debug); 81 assertEquals("a<V>\n", found); 82 } 83 testNamedType()84 @Test public void testNamedType() throws Exception { 85 String grammar = 86 "grammar T;\n" + 87 "options {output=AST;}\n" + 88 "@members {static class V extends CommonTree {\n" + 89 " public V(Token t) { token=t;}\n" + 90 " public String toString() { return token.getText()+\"<V>\";}\n" + 91 "}\n" + 92 "}\n"+ 93 "a : ID<node=V> ;\n"+ 94 "ID : 'a'..'z'+ ;\n" + 95 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 96 String found = execParser("T.g", grammar, "TParser", "TLexer", 97 "a", "a", debug); 98 assertEquals("a<V>\n", found); 99 } 100 101 testTokenWithLabel()102 @Test public void testTokenWithLabel() throws Exception { 103 String grammar = 104 "grammar T;\n" + 105 "options {output=AST;}\n" + 106 "@members {static class V extends CommonTree {\n" + 107 " public V(Token t) { token=t;}\n" + 108 " public String toString() { return token.getText()+\"<V>\";}\n" + 109 "}\n" + 110 "}\n"+ 111 "a : x=ID<V> ;\n"+ 112 "ID : 'a'..'z'+ ;\n" + 113 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 114 String found = execParser("T.g", grammar, "TParser", "TLexer", 115 "a", "a", debug); 116 assertEquals("a<V>\n", found); 117 } 118 testTokenWithListLabel()119 @Test public void testTokenWithListLabel() throws Exception { 120 String grammar = 121 "grammar T;\n" + 122 "options {output=AST;}\n" + 123 "@members {static class V extends CommonTree {\n" + 124 " public V(Token t) { token=t;}\n" + 125 " public String toString() { return token.getText()+\"<V>\";}\n" + 126 "}\n" + 127 "}\n"+ 128 "a : x+=ID<V> ;\n"+ 129 "ID : 'a'..'z'+ ;\n" + 130 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 131 String found = execParser("T.g", grammar, "TParser", "TLexer", 132 "a", "a", debug); 133 assertEquals("a<V>\n", found); 134 } 135 testTokenRoot()136 @Test public void testTokenRoot() throws Exception { 137 String grammar = 138 "grammar T;\n" + 139 "options {output=AST;}\n" + 140 "@members {static class V extends CommonTree {\n" + 141 " public V(Token t) { token=t;}\n" + 142 " public String toString() { return token.getText()+\"<V>\";}\n" + 143 "}\n" + 144 "}\n"+ 145 "a : ID<V>^ ;\n"+ 146 "ID : 'a'..'z'+ ;\n" + 147 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 148 String found = execParser("T.g", grammar, "TParser", "TLexer", 149 "a", "a", debug); 150 assertEquals("a<V>\n", found); 151 } 152 testTokenRootWithListLabel()153 @Test public void testTokenRootWithListLabel() throws Exception { 154 String grammar = 155 "grammar T;\n" + 156 "options {output=AST;}\n" + 157 "@members {static class V extends CommonTree {\n" + 158 " public V(Token t) { token=t;}\n" + 159 " public String toString() { return token.getText()+\"<V>\";}\n" + 160 "}\n" + 161 "}\n"+ 162 "a : x+=ID<V>^ ;\n"+ 163 "ID : 'a'..'z'+ ;\n" + 164 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 165 String found = execParser("T.g", grammar, "TParser", "TLexer", 166 "a", "a", debug); 167 assertEquals("a<V>\n", found); 168 } 169 testString()170 @Test public void testString() throws Exception { 171 String grammar = 172 "grammar T;\n" + 173 "options {output=AST;}\n" + 174 "@members {static class V extends CommonTree {\n" + 175 " public V(Token t) { token=t;}\n" + 176 " public String toString() { return token.getText()+\"<V>\";}\n" + 177 "}\n" + 178 "}\n"+ 179 "a : 'begin'<V> ;\n"+ 180 "ID : 'a'..'z'+ ;\n" + 181 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 182 String found = execParser("T.g", grammar, "TParser", "TLexer", 183 "a", "begin", debug); 184 assertEquals("begin<V>\n", found); 185 } 186 testStringRoot()187 @Test public void testStringRoot() throws Exception { 188 String grammar = 189 "grammar T;\n" + 190 "options {output=AST;}\n" + 191 "@members {static class V extends CommonTree {\n" + 192 " public V(Token t) { token=t;}\n" + 193 " public String toString() { return token.getText()+\"<V>\";}\n" + 194 "}\n" + 195 "}\n"+ 196 "a : 'begin'<V>^ ;\n"+ 197 "ID : 'a'..'z'+ ;\n" + 198 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 199 String found = execParser("T.g", grammar, "TParser", "TLexer", 200 "a", "begin", debug); 201 assertEquals("begin<V>\n", found); 202 } 203 204 // PARSERS -- REWRITE AST 205 testRewriteToken()206 @Test public void testRewriteToken() throws Exception { 207 String grammar = 208 "grammar T;\n" + 209 "options {output=AST;}\n" + 210 "@members {static class V extends CommonTree {\n" + 211 " public V(Token t) { token=t;}\n" + 212 " public String toString() { return token.getText()+\"<V>\";}\n" + 213 "}\n" + 214 "}\n"+ 215 "a : ID -> ID<V> ;\n"+ 216 "ID : 'a'..'z'+ ;\n" + 217 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 218 String found = execParser("T.g", grammar, "TParser", "TLexer", 219 "a", "a", debug); 220 assertEquals("a<V>\n", found); 221 } 222 testRewriteTokenWithArgs()223 @Test public void testRewriteTokenWithArgs() throws Exception { 224 // arg to ID<V>[42,19,30] means you're constructing node not associated with ID 225 // so must pass in token manually 226 String grammar = 227 "grammar T;\n" + 228 "options {output=AST;}\n" + 229 "@members {\n" + 230 "static class V extends CommonTree {\n" + 231 " public int x,y,z;\n"+ 232 " public V(int ttype, int x, int y, int z) { this.x=x; this.y=y; this.z=z; token=new CommonToken(ttype,\"\"); }\n" + 233 " public V(int ttype, Token t, int x) { token=t; this.x=x;}\n" + 234 " public String toString() { return (token!=null?token.getText():\"\")+\"<V>;\"+x+y+z;}\n" + 235 "}\n" + 236 "}\n"+ 237 "a : ID -> ID<V>[42,19,30] ID<V>[$ID,99] ;\n"+ 238 "ID : 'a'..'z'+ ;\n" + 239 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 240 String found = execParser("T.g", grammar, "TParser", "TLexer", 241 "a", "a", debug); 242 assertEquals("<V>;421930 a<V>;9900\n", found); 243 } 244 testRewriteTokenRoot()245 @Test public void testRewriteTokenRoot() throws Exception { 246 String grammar = 247 "grammar T;\n" + 248 "options {output=AST;}\n" + 249 "@members {static class V extends CommonTree {\n" + 250 " public V(Token t) { token=t;}\n" + 251 " public String toString() { return token.getText()+\"<V>\";}\n" + 252 "}\n" + 253 "}\n"+ 254 "a : ID INT -> ^(ID<V> INT) ;\n"+ 255 "ID : 'a'..'z'+ ;\n" + 256 "INT : '0'..'9'+ ;\n" + 257 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 258 String found = execParser("T.g", grammar, "TParser", "TLexer", 259 "a", "a 2", debug); 260 assertEquals("(a<V> 2)\n", found); 261 } 262 testRewriteString()263 @Test public void testRewriteString() throws Exception { 264 String grammar = 265 "grammar T;\n" + 266 "options {output=AST;}\n" + 267 "@members {static class V extends CommonTree {\n" + 268 " public V(Token t) { token=t;}\n" + 269 " public String toString() { return token.getText()+\"<V>\";}\n" + 270 "}\n" + 271 "}\n"+ 272 "a : 'begin' -> 'begin'<V> ;\n"+ 273 "ID : 'a'..'z'+ ;\n" + 274 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 275 String found = execParser("T.g", grammar, "TParser", "TLexer", 276 "a", "begin", debug); 277 assertEquals("begin<V>\n", found); 278 } 279 testRewriteStringRoot()280 @Test public void testRewriteStringRoot() throws Exception { 281 String grammar = 282 "grammar T;\n" + 283 "options {output=AST;}\n" + 284 "@members {static class V extends CommonTree {\n" + 285 " public V(Token t) { token=t;}\n" + 286 " public String toString() { return token.getText()+\"<V>\";}\n" + 287 "}\n" + 288 "}\n"+ 289 "a : 'begin' INT -> ^('begin'<V> INT) ;\n"+ 290 "ID : 'a'..'z'+ ;\n" + 291 "INT : '0'..'9'+ ;\n" + 292 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 293 String found = execParser("T.g", grammar, "TParser", "TLexer", 294 "a", "begin 2", debug); 295 assertEquals("(begin<V> 2)\n", found); 296 } 297 testRewriteRuleResults()298 @Test public void testRewriteRuleResults() throws Exception { 299 String grammar = 300 "grammar T;\n" + 301 "options {output=AST;}\n" + 302 "tokens {LIST;}\n" + 303 "@members {\n" + 304 "static class V extends CommonTree {\n" + 305 " public V(Token t) { token=t;}\n" + 306 " public String toString() { return token.getText()+\"<V>\";}\n" + 307 "}\n" + 308 "static class W extends CommonTree {\n" + 309 " public W(int tokenType, String txt) { super(new CommonToken(tokenType,txt)); }\n" + 310 " public W(Token t) { token=t;}\n" + 311 " public String toString() { return token.getText()+\"<W>\";}\n" + 312 "}\n" + 313 "}\n"+ 314 "a : id (',' id)* -> ^(LIST<W>[\"LIST\"] id+);\n" + 315 "id : ID -> ID<V>;\n"+ 316 "ID : 'a'..'z'+ ;\n" + 317 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 318 String found = execParser("T.g", grammar, "TParser", "TLexer", 319 "a", "a,b,c", debug); 320 assertEquals("(LIST<W> a<V> b<V> c<V>)\n", found); 321 } 322 testCopySemanticsWithHetero()323 @Test public void testCopySemanticsWithHetero() throws Exception { 324 String grammar = 325 "grammar T;\n" + 326 "options {output=AST;}\n" + 327 "@members {\n" + 328 "static class V extends CommonTree {\n" + 329 " public V(Token t) { token=t;}\n" + // for 'int'<V> 330 " public V(V node) { super(node); }\n\n" + // for dupNode 331 " public Tree dupNode() { return new V(this); }\n" + // for dup'ing type 332 " public String toString() { return token.getText()+\"<V>\";}\n" + 333 "}\n" + 334 "}\n" + 335 "a : type ID (',' ID)* ';' -> ^(type ID)+;\n" + 336 "type : 'int'<V> ;\n" + 337 "ID : 'a'..'z'+ ;\n" + 338 "INT : '0'..'9'+;\n" + 339 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 340 String found = execParser("T.g", grammar, "TParser", "TLexer", 341 "a", "int a, b, c;", debug); 342 assertEquals("(int<V> a) (int<V> b) (int<V> c)\n", found); 343 } 344 345 // TREE PARSERS -- REWRITE AST 346 testTreeParserRewriteFlatList()347 @Test public void testTreeParserRewriteFlatList() throws Exception { 348 String grammar = 349 "grammar T;\n" + 350 "options {output=AST;}\n" + 351 "a : ID INT;\n" + 352 "ID : 'a'..'z'+ ;\n" + 353 "INT : '0'..'9'+;\n" + 354 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 355 356 String treeGrammar = 357 "tree grammar TP;\n"+ 358 "options {output=AST; ASTLabelType=CommonTree; tokenVocab=T;}\n" + 359 "@members {\n" + 360 "static class V extends CommonTree {\n" + 361 " public V(Object t) { super((CommonTree)t); }\n" + 362 " public String toString() { return token.getText()+\"<V>\";}\n" + 363 "}\n" + 364 "static class W extends CommonTree {\n" + 365 " public W(Object t) { super((CommonTree)t); }\n" + 366 " public String toString() { return token.getText()+\"<W>\";}\n" + 367 "}\n" + 368 "}\n"+ 369 "a : ID INT -> INT<V> ID<W>\n" + 370 " ;\n"; 371 372 String found = execTreeParser("T.g", grammar, "TParser", "TP.g", 373 treeGrammar, "TP", "TLexer", "a", "a", "abc 34"); 374 assertEquals("34<V> abc<W>\n", found); 375 } 376 testTreeParserRewriteTree()377 @Test public void testTreeParserRewriteTree() throws Exception { 378 String grammar = 379 "grammar T;\n" + 380 "options {output=AST;}\n" + 381 "a : ID INT;\n" + 382 "ID : 'a'..'z'+ ;\n" + 383 "INT : '0'..'9'+;\n" + 384 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 385 386 String treeGrammar = 387 "tree grammar TP;\n"+ 388 "options {output=AST; ASTLabelType=CommonTree; tokenVocab=T;}\n" + 389 "@members {\n" + 390 "static class V extends CommonTree {\n" + 391 " public V(Object t) { super((CommonTree)t); }\n" + 392 " public String toString() { return token.getText()+\"<V>\";}\n" + 393 "}\n" + 394 "static class W extends CommonTree {\n" + 395 " public W(Object t) { super((CommonTree)t); }\n" + 396 " public String toString() { return token.getText()+\"<W>\";}\n" + 397 "}\n" + 398 "}\n"+ 399 "a : ID INT -> ^(INT<V> ID<W>)\n" + 400 " ;\n"; 401 402 String found = execTreeParser("T.g", grammar, "TParser", "TP.g", 403 treeGrammar, "TP", "TLexer", "a", "a", "abc 34"); 404 assertEquals("(34<V> abc<W>)\n", found); 405 } 406 testTreeParserRewriteImaginary()407 @Test public void testTreeParserRewriteImaginary() throws Exception { 408 String grammar = 409 "grammar T;\n" + 410 "options {output=AST;}\n" + 411 "a : ID ;\n" + 412 "ID : 'a'..'z'+ ;\n" + 413 "INT : '0'..'9'+;\n" + 414 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 415 416 String treeGrammar = 417 "tree grammar TP;\n"+ 418 "options {output=AST; ASTLabelType=CommonTree; tokenVocab=T;}\n" + 419 "tokens { ROOT; }\n" + 420 "@members {\n" + 421 "class V extends CommonTree {\n" + 422 " public V(int tokenType) { super(new CommonToken(tokenType)); }\n" + 423 " public String toString() { return tokenNames[token.getType()]+\"<V>\";}\n" + 424 "}\n" + 425 "}\n"+ 426 "a : ID -> ROOT<V> ID\n" + 427 " ;\n"; 428 429 String found = execTreeParser("T.g", grammar, "TParser", "TP.g", 430 treeGrammar, "TP", "TLexer", "a", "a", "abc"); 431 assertEquals("ROOT<V> abc\n", found); 432 } 433 testTreeParserRewriteImaginaryWithArgs()434 @Test public void testTreeParserRewriteImaginaryWithArgs() throws Exception { 435 String grammar = 436 "grammar T;\n" + 437 "options {output=AST;}\n" + 438 "a : ID ;\n" + 439 "ID : 'a'..'z'+ ;\n" + 440 "INT : '0'..'9'+;\n" + 441 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 442 443 String treeGrammar = 444 "tree grammar TP;\n"+ 445 "options {output=AST; ASTLabelType=CommonTree; tokenVocab=T;}\n" + 446 "tokens { ROOT; }\n" + 447 "@members {\n" + 448 "class V extends CommonTree {\n" + 449 " public int x;\n" + 450 " public V(int tokenType, int x) { super(new CommonToken(tokenType)); this.x=x;}\n" + 451 " public String toString() { return tokenNames[token.getType()]+\"<V>;\"+x;}\n" + 452 "}\n" + 453 "}\n"+ 454 "a : ID -> ROOT<V>[42] ID\n" + 455 " ;\n"; 456 457 String found = execTreeParser("T.g", grammar, "TParser", "TP.g", 458 treeGrammar, "TP", "TLexer", "a", "a", "abc"); 459 assertEquals("ROOT<V>;42 abc\n", found); 460 } 461 testTreeParserRewriteImaginaryRoot()462 @Test public void testTreeParserRewriteImaginaryRoot() throws Exception { 463 String grammar = 464 "grammar T;\n" + 465 "options {output=AST;}\n" + 466 "a : ID ;\n" + 467 "ID : 'a'..'z'+ ;\n" + 468 "INT : '0'..'9'+;\n" + 469 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 470 471 String treeGrammar = 472 "tree grammar TP;\n"+ 473 "options {output=AST; ASTLabelType=CommonTree; tokenVocab=T;}\n" + 474 "tokens { ROOT; }\n" + 475 "@members {\n" + 476 "class V extends CommonTree {\n" + 477 " public V(int tokenType) { super(new CommonToken(tokenType)); }\n" + 478 " public String toString() { return tokenNames[token.getType()]+\"<V>\";}\n" + 479 "}\n" + 480 "}\n"+ 481 "a : ID -> ^(ROOT<V> ID)\n" + 482 " ;\n"; 483 484 String found = execTreeParser("T.g", grammar, "TParser", "TP.g", 485 treeGrammar, "TP", "TLexer", "a", "a", "abc"); 486 assertEquals("(ROOT<V> abc)\n", found); 487 } 488 testTreeParserRewriteImaginaryFromReal()489 @Test public void testTreeParserRewriteImaginaryFromReal() throws Exception { 490 String grammar = 491 "grammar T;\n" + 492 "options {output=AST;}\n" + 493 "a : ID ;\n" + 494 "ID : 'a'..'z'+ ;\n" + 495 "INT : '0'..'9'+;\n" + 496 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 497 498 String treeGrammar = 499 "tree grammar TP;\n"+ 500 "options {output=AST; ASTLabelType=CommonTree; tokenVocab=T;}\n" + 501 "tokens { ROOT; }\n" + 502 "@members {\n" + 503 "class V extends CommonTree {\n" + 504 " public V(int tokenType) { super(new CommonToken(tokenType)); }\n" + 505 " public V(int tokenType, Object tree) { super((CommonTree)tree); token.setType(tokenType); }\n" + 506 " public String toString() { return tokenNames[token.getType()]+\"<V>@\"+token.getLine();}\n" + 507 "}\n" + 508 "}\n"+ 509 "a : ID -> ROOT<V>[$ID]\n" + 510 " ;\n"; 511 512 String found = execTreeParser("T.g", grammar, "TParser", "TP.g", 513 treeGrammar, "TP", "TLexer", "a", "a", "abc"); 514 assertEquals("ROOT<V>@1\n", found); // at line 1; shows copy of ID's stuff 515 } 516 testTreeParserAutoHeteroAST()517 @Test public void testTreeParserAutoHeteroAST() throws Exception { 518 String grammar = 519 "grammar T;\n" + 520 "options {output=AST;}\n" + 521 "a : ID ';' ;\n" + 522 "ID : 'a'..'z'+ ;\n" + 523 "INT : '0'..'9'+;\n" + 524 "WS : (' '|'\\n') {$channel=HIDDEN;} ;\n"; 525 526 String treeGrammar = 527 "tree grammar TP;\n"+ 528 "options {output=AST; ASTLabelType=CommonTree; tokenVocab=T;}\n" + 529 "tokens { ROOT; }\n" + 530 "@members {\n" + 531 "class V extends CommonTree {\n" + 532 " public V(CommonTree t) { super(t); }\n" + // NEEDS SPECIAL CTOR 533 " public String toString() { return super.toString()+\"<V>\";}\n" + 534 "}\n" + 535 "}\n"+ 536 "a : ID<V> ';'<V>\n" + 537 " ;\n"; 538 539 String found = execTreeParser("T.g", grammar, "TParser", "TP.g", 540 treeGrammar, "TP", "TLexer", "a", "a", "abc;"); 541 assertEquals("abc<V> ;<V>\n", found); 542 } 543 544 } 545