| 1 2 package org.apache.velocity.runtime.parser; 3 4 import java.io.*; 5 import java.util.*; 6 7 import org.apache.velocity.runtime.RuntimeServices; 8 import org.apache.velocity.runtime.parser.node.*; 9 import org.apache.velocity.runtime.directive.Directive; 10 import org.apache.velocity.runtime.directive.Macro; 11 import org.apache.velocity.runtime.directive.MacroParseException; 12 import org.apache.velocity.util.StringUtils; 13 14 27 public class Parserimplements ParserTreeConstants, ParserConstants { 28 protected JJTParserState jjtree = new JJTParserState(); 31 private Hashtable directives = new Hashtable(0); 32 33 36 String currentTemplateName = ""; 37 38 VelocityCharStream velcharstream = null; 39 40 private RuntimeServices rsvc = null; 41 42 49 public Parser( RuntimeServices rs) 50 { 51 54 55 this( new VelocityCharStream( 56 new ByteArrayInputStream("\n".getBytes()), 1, 1 )); 57 58 61 velcharstream = new VelocityCharStream( 62 new ByteArrayInputStream("\n".getBytes()), 1, 1 ); 63 64 67 rsvc = rs; 68 } 69 70 79 public SimpleNode parse( Reader reader, String templateName ) 80 throws ParseException 81 { 82 SimpleNode sn = null; 83 84 currentTemplateName = templateName; 85 86 try 87 { 88 token_source.clearStateVars(); 89 90 94 velcharstream.ReInit( reader, 1, 1 ); 95 96 99 ReInit( velcharstream ); 100 101 104 sn = process(); 105 } 106 catch (MacroParseException mee) 107 { 108 112 rsvc.error ("Parser Error: #macro() : " + templateName + " : " + StringUtils.stackTrace(mee)); 113 throw new ParseException(mee.getMessage()); 114 } 115 catch (ParseException pe) 116 { 117 rsvc.error ("Parser Exception: " + templateName + " : " + StringUtils.stackTrace(pe)); 118 throw new ParseException (pe.currentToken, 119 pe.expectedTokenSequences, pe.tokenImage); 120 } 121 catch (TokenMgrError tme) 122 { 123 throw new ParseException("Lexical error: " + tme.toString()); 124 } 125 catch (Exception e) 126 { 127 rsvc.error ("Parser Error: " + templateName + " : " + StringUtils.stackTrace(e)); 128 } 129 130 currentTemplateName = ""; 131 132 return sn; 133 } 134 135 138 public void setDirectives(Hashtable directives) 139 { 140 this.directives = directives; 141 } 142 143 146 public Directive getDirective(String directive) 147 { 148 return (Directive) directives.get(directive); 149 } 150 151 155 public boolean isDirective(String directive) 156 { 157 if (directives.containsKey(directive)) 158 return true; 159 else 160 return false; 161 } 162 163 164 168 private String escapedDirective( String strImage ) 169 { 170 int iLast = strImage.lastIndexOf("\\"); 171 172 String strDirective = strImage.substring(iLast + 1); 173 174 boolean bRecognizedDirective = false; 175 176 179 180 if ( isDirective( strDirective.substring(1))) 181 { 182 bRecognizedDirective = true; 183 } 184 else if ( rsvc.isVelocimacro( strDirective.substring(1), currentTemplateName)) 185 { 186 bRecognizedDirective = true; 187 } 188 else 189 { 190 191 192 if ( strDirective.substring(1).equals("if") 193 || strDirective.substring(1).equals("end") 194 || strDirective.substring(1).equals("set") 195 || strDirective.substring(1).equals("else") 196 || strDirective.substring(1).equals("elseif") 197 || strDirective.substring(1).equals("stop") 198 ) 199 { 200 bRecognizedDirective = true; 201 } 202 } 203 204 208 209 if (bRecognizedDirective) 210 return ( strImage.substring(0,iLast/2) + strDirective); 211 else 212 return ( strImage ); 213 } 214 215 224 final public SimpleNode process() throws ParseException { 225 226 ASTprocess jjtn000 = new ASTprocess(this, JJTPROCESS); 227 boolean jjtc000 = true; 228 jjtree.openNodeScope(jjtn000); 229 try { 230 label_1: 231 while (true) { 232 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 233 case LPAREN: 234 case RPAREN: 235 case ESCAPE_DIRECTIVE: 236 case SET_DIRECTIVE: 237 case DOUBLE_ESCAPE: 238 case ESCAPE: 239 case TEXT: 240 case SINGLE_LINE_COMMENT: 241 case FORMAL_COMMENT: 242 case MULTI_LINE_COMMENT: 243 case STRING_LITERAL: 244 case IF_DIRECTIVE: 245 case STOP_DIRECTIVE: 246 case NUMBER_LITERAL: 247 case WORD: 248 case IDENTIFIER: 249 case DOT: 250 case LCURLY: 251 case RCURLY: 252 ; 253 break; 254 default: 255 jj_la1[0] = jj_gen; 256 break label_1; 257 } 258 Statement(); 259 } 260 jj_consume_token(0); 261 jjtree.closeNodeScope(jjtn000, true); 262 jjtc000 = false; 263 {if (true) return jjtn000;} 264 } catch (Throwable jjte000) { 265 if (jjtc000) { 266 jjtree.clearNodeScope(jjtn000); 267 jjtc000 = false; 268 } else { 269 jjtree.popNode(); 270 } 271 if (jjte000 instanceof RuntimeException) { 272 {if (true) throw (RuntimeException)jjte000;} 273 } 274 if (jjte000 instanceof ParseException) { 275 {if (true) throw (ParseException)jjte000;} 276 } 277 {if (true) throw (Error)jjte000;} 278 } finally { 279 if (jjtc000) { 280 jjtree.closeNodeScope(jjtn000, true); 281 } 282 } 283 throw new Error("Missing return statement in function"); 284 } 285 286 290 final public void Statement() throws ParseException { 291 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 292 case IF_DIRECTIVE: 293 IfStatement(); 294 break; 295 case STOP_DIRECTIVE: 296 StopStatement(); 297 break; 298 default: 299 jj_la1[1] = jj_gen; 300 if (jj_2_1(2)) { 301 Reference(); 302 } else { 303 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 304 case SINGLE_LINE_COMMENT: 305 case FORMAL_COMMENT: 306 case MULTI_LINE_COMMENT: 307 Comment(); 308 break; 309 case SET_DIRECTIVE: 310 SetDirective(); 311 break; 312 case ESCAPE_DIRECTIVE: 313 EscapedDirective(); 314 break; 315 case DOUBLE_ESCAPE: 316 Escape(); 317 break; 318 case WORD: 319 Directive(); 320 break; 321 case LPAREN: 322 case RPAREN: 323 case ESCAPE: 324 case TEXT: 325 case STRING_LITERAL: 326 case NUMBER_LITERAL: 327 case DOT: 328 case LCURLY: 329 case RCURLY: 330 Text(); 331 break; 332 default: 333 jj_la1[2] = jj_gen; 334 jj_consume_token(-1); 335 throw new ParseException(); 336 } 337 } 338 } 339 } 340 341 348 final public void EscapedDirective() throws ParseException { 349 350 ASTEscapedDirective jjtn000 = new ASTEscapedDirective(this, JJTESCAPEDDIRECTIVE); 351 boolean jjtc000 = true; 352 jjtree.openNodeScope(jjtn000); 353 try { 354 Token t = null; 355 t = jj_consume_token(ESCAPE_DIRECTIVE); 356 jjtree.closeNodeScope(jjtn000, true); 357 jjtc000 = false; 358 361 t.image = escapedDirective( t.image ); 362 } finally { 363 if (jjtc000) { 364 jjtree.closeNodeScope(jjtn000, true); 365 } 366 } 367 } 368 369 376 final public void Escape() throws ParseException { 377 378 ASTEscape jjtn000 = new ASTEscape(this, JJTESCAPE); 379 boolean jjtc000 = true; 380 jjtree.openNodeScope(jjtn000); 381 try { 382 Token t = null; 383 int count = 0; 384 boolean control = false; 385 label_2: 386 while (true) { 387 t = jj_consume_token(DOUBLE_ESCAPE); 388 count++; 389 if (jj_2_2(2)) { 390 ; 391 } else { 392 break label_2; 393 } 394 } 395 jjtree.closeNodeScope(jjtn000, true); 396 jjtc000 = false; 397 400 switch(t.next.kind ) { 401 case IF_DIRECTIVE : 402 case ELSE_DIRECTIVE : 403 case ELSEIF_DIRECTIVE : 404 case END : 405 case STOP_DIRECTIVE : 406 control = true; 407 break; 408 } 409 410 413 414 if ( isDirective( t.next.image.substring(1))) 415 control = true; 416 else if ( rsvc.isVelocimacro( t.next.image.substring(1), currentTemplateName)) 417 control = true; 418 419 jjtn000.val = ""; 420 421 for( int i = 0; i < count; i++) 422 jjtn000.val += ( control ? "\\" : "\\\\"); 423 } finally { 424 if (jjtc000) { 425 jjtree.closeNodeScope(jjtn000, true); 426 } 427 } 428 } 429 430 final public void Comment() throws ParseException { 431 432 ASTComment jjtn000 = new ASTComment(this, JJTCOMMENT); 433 boolean jjtc000 = true; 434 jjtree.openNodeScope(jjtn000); 435 try { 436 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 437 case SINGLE_LINE_COMMENT: 438 jj_consume_token(SINGLE_LINE_COMMENT); 439 break; 440 case MULTI_LINE_COMMENT: 441 jj_consume_token(MULTI_LINE_COMMENT); 442 break; 443 case FORMAL_COMMENT: 444 jj_consume_token(FORMAL_COMMENT); 445 break; 446 default: 447 jj_la1[3] = jj_gen; 448 jj_consume_token(-1); 449 throw new ParseException(); 450 } 451 } finally { 452 if (jjtc000) { 453 jjtree.closeNodeScope(jjtn000, true); 454 } 455 } 456 } 457 458 final public void NumberLiteral() throws ParseException { 459 460 ASTNumberLiteral jjtn000 = new ASTNumberLiteral(this, JJTNUMBERLITERAL); 461 boolean jjtc000 = true; 462 jjtree.openNodeScope(jjtn000); 463 try { 464 jj_consume_token(NUMBER_LITERAL); 465 } finally { 466 if (jjtc000) { 467 jjtree.closeNodeScope(jjtn000, true); 468 } 469 } 470 } 471 472 final public void StringLiteral() throws ParseException { 473 474 ASTStringLiteral jjtn000 = new ASTStringLiteral(this, JJTSTRINGLITERAL); 475 boolean jjtc000 = true; 476 jjtree.openNodeScope(jjtn000); 477 try { 478 jj_consume_token(STRING_LITERAL); 479 } finally { 480 if (jjtc000) { 481 jjtree.closeNodeScope(jjtn000, true); 482 } 483 } 484 } 485 486 497 final public void Identifier() throws ParseException { 498 499 ASTIdentifier jjtn000 = new ASTIdentifier(this, JJTIDENTIFIER); 500 boolean jjtc000 = true; 501 jjtree.openNodeScope(jjtn000); 502 try { 503 jj_consume_token(IDENTIFIER); 504 } finally { 505 if (jjtc000) { 506 jjtree.closeNodeScope(jjtn000, true); 507 } 508 } 509 } 510 511 final public void Word() throws ParseException { 512 513 ASTWord jjtn000 = new ASTWord(this, JJTWORD); 514 boolean jjtc000 = true; 515 jjtree.openNodeScope(jjtn000); 516 try { 517 jj_consume_token(WORD); 518 } finally { 519 if (jjtc000) { 520 jjtree.closeNodeScope(jjtn000, true); 521 } 522 } 523 } 524 525 531 final public int DirectiveArg() throws ParseException { 532 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 533 case IDENTIFIER: 534 case LCURLY: 535 Reference(); 536 {if (true) return ParserTreeConstants.JJTREFERENCE;} 537 break; 538 case WORD: 539 Word(); 540 {if (true) return ParserTreeConstants.JJTWORD;} 541 break; 542 case STRING_LITERAL: 543 StringLiteral(); 544 {if (true) return ParserTreeConstants.JJTSTRINGLITERAL;} 545 break; 546 case NUMBER_LITERAL: 547 NumberLiteral(); 548 {if (true) return ParserTreeConstants.JJTNUMBERLITERAL;} 549 break; 550 default: 551 jj_la1[4] = jj_gen; 552 if (jj_2_3(2147483647)) { 553 IntegerRange(); 554 {if (true) return ParserTreeConstants.JJTINTEGERRANGE;} 555 } else { 556 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 557 case LBRACKET: 558 ObjectArray(); 559 {if (true) return ParserTreeConstants.JJTOBJECTARRAY;} 560 break; 561 case TRUE: 562 True(); 563 {if (true) return ParserTreeConstants.JJTTRUE;} 564 break; 565 case FALSE: 566 False(); 567 {if (true) return ParserTreeConstants.JJTFALSE;} 568 break; 569 default: 570 jj_la1[5] = jj_gen; 571 jj_consume_token(-1); 572 throw new ParseException(); 573 } 574 } 575 } 576 throw new Error("Missing return statement in function"); 577 } 578 579 583 final public SimpleNode Directive() throws ParseException { 584 585 ASTDirective jjtn000 = new ASTDirective(this, JJTDIRECTIVE); 586 boolean jjtc000 = true; 587 jjtree.openNodeScope(jjtn000);Token t = null; 588 int argType; 589 int argPos = 0; 590 Directive d; 591 int directiveType; 592 boolean isVM = false; 593 boolean doItNow = false; 594 try { 595 599 t = jj_consume_token(WORD); 600 String directiveName = t.image.substring(1); 601 602 d = (Directive) directives.get(directiveName); 603 604 609 610 if (directiveName.equals("macro")) 611 { 612 doItNow = true; 613 } 614 615 619 620 jjtn000.setDirectiveName(directiveName); 621 622 if ( d == null) 623 { 624 627 628 isVM = rsvc.isVelocimacro(directiveName, currentTemplateName); 629 630 if (!isVM) 631 { 632 token_source.stateStackPop(); 633 token_source.inDirective = false; 634 {if (true) return jjtn000;} 635 } 636 637 638 641 642 directiveType = Directive.LINE; 643 } 644 else 645 { 646 directiveType = d.getType(); 647 } 648 649 652 653 token_source.SwitchTo(DIRECTIVE); 654 655 argPos = 0; 656 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 657 case WHITESPACE: 658 jj_consume_token(WHITESPACE); 659 break; 660 default: 661 jj_la1[6] = jj_gen; 662 ; 663 } 664 jj_consume_token(LPAREN); 665 label_3: 666 while (true) { 667 if (jj_2_4(2)) { 668 ; 669 } else { 670 break label_3; 671 } 672 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 673 case WHITESPACE: 674 jj_consume_token(WHITESPACE); 675 break; 676 default: 677 jj_la1[7] = jj_gen; 678 ; 679 } 680 argType = DirectiveArg(); 681 if (argType == ParserTreeConstants.JJTWORD) 682 { 683 if (doItNow && argPos == 0) 684 { 685 686 ; 687 } 688 else if( t.image.equals("#foreach") && argPos == 1) 689 { 690 691 ; 692 } 693 else 694 { 695 {if (true) throw new MacroParseException("Invalid arg #" 696 + argPos + " in " 697 + (isVM ? "VM " : "directive " ) 698 + t.image 699 + " at line " + t.beginLine + ", column " 700 + t.beginColumn 701 + " in template " + currentTemplateName);} 702 } 703 } 704 else 705 { 706 if (doItNow && argPos == 0) 707 { 708 709 710 {if (true) throw new MacroParseException("Invalid first arg " 711 + " in #macro() directive - must be a" 712 + " word token (no \' or \" surrounding)" 713 + " at line " + t.beginLine + ", column " 714 + t.beginColumn 715 + " in template " + currentTemplateName);} 716 } 717 } 718 719 argPos++; 720 } 721 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 722 case WHITESPACE: 723 jj_consume_token(WHITESPACE); 724 break; 725 default: 726 jj_la1[8] = jj_gen; 727 ; 728 } 729 jj_consume_token(RPAREN); 730 if (directiveType == Directive.LINE) 731 { 732 {if (true) return jjtn000;} 733 } 734 ASTBlock jjtn001 = new ASTBlock(this, JJTBLOCK); 735 boolean jjtc001 = true; 736 jjtree.openNodeScope(jjtn001); 737 try { 738 label_4: 739 while (true) { 740 Statement(); 741 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 742 case LPAREN: 743 case RPAREN: 744 case ESCAPE_DIRECTIVE: 745 case SET_DIRECTIVE: 746 case DOUBLE_ESCAPE: 747 case ESCAPE: 748 case TEXT: 749 case SINGLE_LINE_COMMENT: 750 case FORMAL_COMMENT: 751 case MULTI_LINE_COMMENT: 752 case STRING_LITERAL: 753 case IF_DIRECTIVE: 754 case STOP_DIRECTIVE: 755 case NUMBER_LITERAL: 756 case WORD: 757 case IDENTIFIER: 758 case DOT: 759 case LCURLY: 760 case RCURLY: 761 ; 762 break; 763 default: 764 jj_la1[9] = jj_gen; 765 break label_4; 766 } 767 } 768 } catch (Throwable jjte001) { 769 if (jjtc001) { 770 jjtree.clearNodeScope(jjtn001); 771 jjtc001 = false; 772 } else { 773 jjtree.popNode(); 774 } 775 if (jjte001 instanceof RuntimeException) { 776 {if (true) throw (RuntimeException)jjte001;} 777 } 778 if (jjte001 instanceof ParseException) { 779 {if (true) throw (ParseException)jjte001;} 780 } 781 {if (true) throw (Error)jjte001;} 782 } finally { 783 if (jjtc001) { 784 jjtree.closeNodeScope(jjtn001, true); 785 } 786 } 787 jj_consume_token(END); 788 jjtree.closeNodeScope(jjtn000, true); 789 jjtc000 = false; 790 797 798 if (doItNow) 799 { 800 Macro.processAndRegister(rsvc, jjtn000, currentTemplateName); 801 } 802 803 806 807 {if (true) return jjtn000;} 808 } catch (Throwable jjte000) { 809 if (jjtc000) { 810 jjtree.clearNodeScope(jjtn000); 811 jjtc000 = false; 812 } else { 813 jjtree.popNode(); 814 } 815 if (jjte000 instanceof RuntimeException) { 816 {if (true) throw (RuntimeException)jjte000;} 817 } 818 if (jjte000 instanceof ParseException) { 819 {if (true) throw (ParseException)jjte000;} 820 } 821 {if (true) throw (Error)jjte000;} 822 } finally { 823 if (jjtc000) { 824 jjtree.closeNodeScope(jjtn000, true); 825 } 826 } 827 throw new Error("Missing return statement in function"); 828 } 829 830 final public void ObjectArray() throws ParseException { 831 832 ASTObjectArray jjtn000 = new ASTObjectArray(this, JJTOBJECTARRAY); 833 boolean jjtc000 = true; 834 jjtree.openNodeScope(jjtn000); 835 try { 836 jj_consume_token(LBRACKET); 837 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 838 case LBRACKET: 839 case WHITESPACE: 840 case STRING_LITERAL: 841 case TRUE: 842 case FALSE: 843 case NUMBER_LITERAL: 844 case IDENTIFIER: 845 case LCURLY: 846 Parameter(); 847 label_5: 848 while (true) { 849 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 850 case COMMA: 851 ; 852 break; 853 default: 854 jj_la1[10] = jj_gen; 855 break label_5; 856 } 857 jj_consume_token(COMMA); 858 Parameter(); 859 } 860 break; 861 default: 862 jj_la1[11] = jj_gen; 863 ; 864 } 865 jj_consume_token(RBRACKET); 866 } catch (Throwable jjte000) { 867 if (jjtc000) { 868 jjtree.clearNodeScope(jjtn000); 869 jjtc000 = false; 870 } else { 871 jjtree.popNode(); 872 } 873 if (jjte000 instanceof RuntimeException) { 874 {if (true) throw (RuntimeException)jjte000;} 875 } 876 if (jjte000 instanceof ParseException) { 877 {if (true) throw (ParseException)jjte000;} 878 } 879 {if (true) throw (Error)jjte000;} 880 } finally { 881 if (jjtc000) { 882 jjtree.closeNodeScope(jjtn000, true); 883 } 884 } 885 } 886 887 892 final public void IntegerRange() throws ParseException { 893 894 ASTIntegerRange jjtn000 = new ASTIntegerRange(this, JJTINTEGERRANGE); 895 boolean jjtc000 = true; 896 jjtree.openNodeScope(jjtn000); 897 try { 898 jj_consume_token(LBRACKET); 899 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 900 case WHITESPACE: 901 jj_consume_token(WHITESPACE); 902 break; 903 default: 904 jj_la1[12] = jj_gen; 905 ; 906 } 907 switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { 908 case IDENTIFIER: 909 case LCURLY: 910 Reference(); 911 |