1 29 30 package com.caucho.el; 31 32 import com.caucho.util.CharBuffer; 33 import com.caucho.util.L10N; 34 35 import javax.el.ELContext; 36 import javax.el.FunctionMapper; 37 import javax.el.ValueExpression; 38 import javax.el.VariableMapper; 39 import java.lang.reflect.Method ; 40 import java.util.ArrayList ; 41 import java.util.logging.Logger ; 42 43 46 public class ELParser 47 { 48 private static final Logger log = Logger.getLogger(ELParser.class.getName()); 49 private static final L10N L = new L10N(ELParser.class); 50 51 private String _string; 53 private int _index; 55 private int _peek = -1; 57 private String _lexeme; 59 private CharBuffer _cb = new CharBuffer(); 61 62 protected final ELContext _elContext; 63 64 private boolean _checkEscape = true; 65 66 public ELParser(ELContext elContext, String string) 67 { 68 if (elContext == null) 69 throw new NullPointerException (); 70 71 _elContext = elContext; 72 _string = string; 73 } 74 75 protected ELParser create(String string) 76 { 77 ELParser parser = new ELParser(_elContext, string); 78 79 copyTo(parser); 80 81 return parser; 82 } 83 84 87 protected void copyTo(ELParser parser) 88 { 89 } 90 91 94 public void setCheckEscape(boolean checkEscape) 95 { 96 _checkEscape = checkEscape; 97 } 98 99 102 public Expr parse() 103 throws ELParseException 104 { 105 return parseInterpolate(); 106 } 107 108 111 public Expr parseInterpolate() 112 throws ELParseException 113 { 114 CharBuffer text = CharBuffer.allocate(); 115 CharBuffer exprString = CharBuffer.allocate(); 116 Expr expr = null; 117 int ch; 118 119 while ((ch = read()) >= 0) { 120 if (_checkEscape && ch == '\\') { 121 ch = read(); 122 123 if (ch == '$' || ch == '#' || ch == '\\') 124 text.append((char) ch); 125 else { 126 text.append('\\'); 127 unread(); 128 } 129 } 130 else if (ch == '$' || ch == '#') { 131 int origChar = ch; 132 133 ch = read(); 134 135 if (ch == '{') { 136 if (text.length() > 0) { 137 StringLiteral right = new StringLiteral(text.toString()); 138 139 if (expr == null) 140 expr = right; 141 else 142 expr = new InterpolateExpr(expr, right); 143 144 text.clear(); 145 } 146 147 exprString.clear(); 148 149 for (ch = read(); ch > 0 && ch != '}'; ch = read()) { 150 exprString.append((char) ch); 151 152 if (ch == '\'' || ch == '"') { 153 int end = ch; 154 155 for (ch = read(); ch > 0 && ch != end; ch = read()) { 156 exprString.append((char) ch); 157 158 if (ch == '\\') { 159 ch = read(); 160 if (ch > 0) 161 exprString.append((char) ch); 162 } 163 } 164 165 if (ch > 0) 166 exprString.append((char) ch); 167 } 168 } 169 170 if (ch != '}') 171 throw error(L.l("expected '}' at end of EL expression", 172 exprString)); 173 174 Expr right = create(exprString.toString()).parseExpr(); 175 176 if (expr == null) 177 expr = right; 178 else 179 expr = new InterpolateExpr(expr, right); 180 } 181 else { 182 text.append((char) origChar); 183 unread(); 184 } 185 } 186 else 187 text.append((char) ch); 188 } 189 190 if (text.length() > 0) { 191 StringLiteral right = new StringLiteral(text.toString()); 192 193 if (expr == null) 194 expr = right; 195 else 196 expr = new InterpolateExpr(expr, right); 197 } 198 199 if (expr == null) 200 expr = new StringLiteral(""); 201 202 return expr; 203 } 204 205 208 private Expr parseExpr() 209 throws ELParseException 210 { 211 Expr left = parseTerm(); 212 213 while (true) { 214 int token = scanToken(); 215 216 switch (token) { 217 case '?': 218 { 219 Expr trueExpr = parseExpr(); 220 token = scanToken(); 221 if (token != ':') 222 throw error(L.l("Expected `:' at {0}. Conditional syntax is 'expr ? expr : expr'.", badChar(token))); 223 Expr falseExpr = parseExpr(); 224 225 left = new ConditionalExpr(left, trueExpr, falseExpr); 226 } 227 break; 228 229 case Expr.OR: 230 left = parseOrExpr(token, left, parseTerm()); 231 break; 232 233 case Expr.AND: 234 left = parseAndExpr(token, left, parseTerm()); 235 break; 236 237 case Expr.EQ: case Expr.NE: case Expr.LT: 238 case Expr.LE: case Expr.GT: case Expr.GE: 239 left = parseCmpExpr(token, left, parseTerm()); 240 break; 241 242 case Expr.ADD: case Expr.SUB: 243 left = parseAddExpr(token, left, parseTerm()); 244 break; 245 246 case Expr.MUL: case Expr.DIV: case Expr.MOD: 247 left = parseMulExpr(token, left, parseTerm()); 248 break; 249 250 default: 251 _peek = token; 252 return left; 253 } 254 } 255 } 256 257 261 private Expr parseOrExpr(int code, Expr left, Expr right) 262 throws ELParseException 263 { 264 while (true) { 265 int token = scanToken(); 266 switch (token) { 267 case Expr.OR: 268 left = new BooleanExpr(code, left, right); 269 code = token; 270 right = parseTerm(); 271 break; 272 273 case Expr.AND: 274 right = parseAndExpr(token, right, parseTerm()); 275 break; 276 277 case Expr.EQ: case Expr.NE: 278 case Expr.LT: case Expr.GT: 279 case Expr.LE: case Expr.GE: 280 right = parseCmpExpr(token, right, parseTerm()); 281 break; 282 283 case Expr.ADD: case Expr.SUB: 284 right = parseAddExpr(token, right, parseTerm()); 285 break; 286 287 case Expr.MUL: case Expr.DIV: case Expr.MOD: 288 right = parseMulExpr(token, right, parseTerm()); 289 break; 290 291 default: 292 _peek = token; 293 return new BooleanExpr(code, left, right); 294 } 295 } 296 } 297 298 302 private Expr parseAndExpr(int code, Expr left, Expr right) 303 throws ELParseException 304 { 305 while (true) { 306 int token = scanToken(); 307 switch (token) { 308 case Expr.AND: 309 left = new BooleanExpr(code, left, right); 310 code = token; 311 right = parseTerm(); 312 break; 313 314 case Expr.EQ: case Expr.NE: 315 case Expr.LT: case Expr.GT: 316 case Expr.LE: case Expr.GE: 317 right = parseCmpExpr(token, right, parseTerm()); 318 break; 319 320 case Expr.ADD: case Expr.SUB: 321 right = parseAddExpr(token, right, parseTerm()); 322 break; 323 324 case Expr.MUL: case Expr.DIV: case Expr.MOD: 325 right = parseMulExpr(token, right, parseTerm()); 326 break; 327 328 default: 329 _peek = token; 330 return new BooleanExpr(code, left, right); 331 } 332 } 333 } 334 335 339 private Expr parseCmpExpr(int code, Expr left, Expr right) 340 throws ELParseException 341 { 342 while (true) { 343 int token = scanToken(); 344 switch (token) { 345 case Expr.EQ: case Expr.NE: 346 case Expr.GT: case Expr.LT: 347 case Expr.LE: case Expr.GE: 348 left = CmpExpr.create(code, left, right); 349 350 code = token; 351 right = parseTerm(); 352 break; 353 354 case Expr.ADD: case Expr.SUB: 355 right = parseAddExpr(token, right, parseTerm()); 356 break; 357 358 case Expr.MUL: case Expr.DIV: case Expr.MOD: 359 right = parseMulExpr(token, right, parseTerm()); 360 break; 361 362 default: 363 _peek = token; 364 return CmpExpr.create(code, left, right); 365 } 366 } 367 } 368 369 373 private Expr parseAddExpr(int code, Expr left, Expr right) 374 throws ELParseException 375 { 376 while (true) { 377 int token = scanToken(); 378 switch (token) { 379 case Expr.ADD: case Expr.SUB: 380 left = BinaryExpr.create(code, left, right); 381 code = token; 382 right = parseTerm(); 383 break; 384 385 case Expr.MUL: case Expr.DIV: case Expr.MOD: 386 right = parseMulExpr(token, right, parseTerm()); 387 break; 388 389 default: 390 _peek = token; 391 return BinaryExpr.create(code, left, right); 392 } 393 } 394 } 395 396 400 private Expr parseMulExpr(int code, Expr left, Expr right) 401 throws ELParseException 402 { 403 while (true) { 404 int token = scanToken(); 405 switch (token) { 406 case Expr.MUL: case Expr.DIV: case Expr.MOD: 407 left = BinaryExpr.create(code, left, right); 408 right = parseTerm(); 409 code = token; 410 break; 411 412 default: 413 _peek = token; 414 return BinaryExpr.create(code, left, right); 415 } 416 } 417 } 418 419 424 private Expr parseTerm() 425 throws ELParseException 426 { 427 Expr term = parseSimpleTerm(); 428 429 while (true) { 430 int token = scanToken(); 431 432 switch (token) { 433 case '[': 434 { 435 Expr expr = parseExpr(); 436 token = scanToken(); 437 if (token != ']') 438 throw error(L.l("Expected `]' at {0}. All open array braces must have matching closing brace.", badChar(token))); 439 440 term = term.createField(expr); 441 break; 442 } 443 444 case '(': 445 { 446 ArrayList <Expr> argList = new ArrayList <Expr>(); 447 448 int ch = skipWhitespace(read()); 449 450 while (ch > 0 && ch != ')') { 451 unread(); 452 argList.add(parseExpr()); 453 454 token = scanToken(); 455 456 if (token != ',') { 457 ch = token; 458 break; 459 } 460 461 ch = skipWhitespace(read()); 462 } 463 464 if (ch != ')') 465 throw error(L.l("Expected `)' at {0}. All functions must have matching closing parenthesis.", badChar(ch))); 466 467 469 Expr []args = (Expr []) argList.toArray(new Expr[argList.size()]); 470 471 Expr expr = term.createMethod(args); 472 if (expr == null) 473 throw error(L.l("Method call not supported in this context `{0}'.", 474 term)); 475 term = expr; 476 break; 477 } 478 479 case '.': 480 { 481 int ch = skipWhitespace(read()); 482 483 if (! Character.isJavaIdentifierStart((char) ch)) 484 throw error(L.l("Expected `]' at {0}. Field references must be identifiers.", badChar(ch))); 485 486 String field = readName(ch); 487 488 term = term.createField(field); 489 break; 490 } 491 492 default: 493 _peek = token; 494 return term; 495 } 496 } 497 } 498 499 506 private Expr parseSimpleTerm() 507 throws ELParseException 508 { 509 int ch = read(); 510 511 ch = skipWhitespace(ch); 512 513 switch (ch) { 514 case '.': 515 case '0': case '1': case '2': case '3': case '4': 516 case '5': case '6': case '7': case '8': case '9': 517 { 518 long value = 0; 519 double exp = 1; 520 int digits = 0; 521 522 for (; ch >= '0' && ch <= '9'; ch = read()) 523 value = 10 * value + ch - '0'; 524 525 if (ch != '.' && ch != 'e' && ch != 'E') { 526 unread(); 527 return new LongLiteral(value); 528 } 529 530 if (ch == '.') { 531 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) { 532 value = 10 * value + ch - '0'; 533 exp *= 10; 534 digits--; 535 } 536 } 537 538 if (ch == 'e' || ch == 'E') { 539 int sign = 1; 540 int expValue = 0; 541 542 ch = read(); 543 if (ch == '-') { 544 sign = -1; 545 ch = read(); 546 } 547 else if (ch == '+') 548 ch = read(); 549 550 for (; ch >= '0' && ch <= '9'; ch = read()) 551 expValue = 10 * expValue + ch - '0'; 552 553 exp = Math.pow(10, digits + sign * expValue); 554 555 unread(); 556 557 return new DoubleLiteral((double) value * (double) exp); 558 } 559 560 unread(); 561 return new DoubleLiteral((double) value / (double) exp); 562 } 563 564 case '-': 565 return new MinusExpr(parseTerm()); 566 567 case '!': 568 return UnaryExpr.create(Expr.NOT, parseTerm()); 569 570 case '+': 571 return parseTerm(); 572 573 case '(': 574 { 575 Expr expr = parseExpr(); 576 if ((ch = scanToken()) != ')') 577 throw error(L.l("Expected `)' at {0}. All open parentheses must have matching closing parentheses.", badChar(ch))); 578 579 return expr; 580 } 581 582 case '\'': case '"': 583 { 584 int end = ch; 585 CharBuffer cb = new CharBuffer(); 586 for (ch = read(); ch >= 0; ch = read()) { 587 if (ch == '\\') 588 cb.append((char) read()); 589 else if (ch != end) 590 cb.append((char) ch); 591 else if ((ch = read()) == end) 592 cb.append((char) ch); 593 else { 594 unread(); 595 break; 596 } 597 } 598 599 return new StringLiteral(cb.toString()); 600 } 601 602 default: 603 if (! Character.isJavaIdentifierStart((char) ch) && ch != ':') 604 throw error(L.l("Unexpected character at {0}.", badChar(ch))); 605 606 CharBuffer cb = CharBuffer.allocate(); 607 for (; 608 Character.isJavaIdentifierPart((char) ch) || ch == ':'; 609 ch = read()) 610 cb.append((char) ch); 611 612 unread(); 613 614 String name = cb.close(); 615 616 if (name.equals("null")) 617 return new NullLiteral(); 618 else if (name.equals("true")) 619 return new BooleanLiteral(true); 620 else if (name.equals("false")) 621 return new BooleanLiteral(false); 622 else if (name.equals("not")) 623 return UnaryExpr.create(Expr.NOT, parseTerm()); 624 else if (name.equals("empty")) 625 return UnaryExpr.create(Expr.EMPTY, parseTerm()); 626 else { 627 VariableMapper varMapper = _elContext.getVariableMapper(); 628 629 ValueExpression valueExpr = null; 630 631 if (varMapper != null) 632 valueExpr = varMapper.resolveVariable(name); 633 634 if (valueExpr != null) 635 return new ValueExpr(name, valueExpr); 636 637 Expr expr = createImplicitObjectExpr(name); 638 639 if (expr != null) 640 return expr; 641 642 Method method = getStaticMethod(name); 643 644 if (method != null) 645 return new StaticMethodExpr(method); 646 else 647 return new IdExpr(name); 648 } 649 } 650 } 651 652 655 protected Expr createImplicitObjectExpr(String name) 656 { 657 return null; 658 } 659 660 663 protected Method getStaticMethod(String name) 664 throws ELParseException 665 { 666 Method method = null; 667 668 FunctionMapper funMapper = _elContext.getFunctionMapper(); 669 670 if (funMapper != null) { 671 String prefix = ""; 672 String localName = name; 673 674 int p = name.indexOf(':'); 675 if (p > 0) { 676 prefix = name.substring(0, p); 677 localName = name.substring(p + 1); 678 } 679 680 method = funMapper.resolveFunction(prefix, localName); 681 } 682 683 return method; 684 } 685 686 691 private int scanToken() 692 throws ELParseException 693 { 694 if (_peek >= 0) { 695 int value = _peek; 696 _peek = -1; 697 return value; 698 } 699 700 int ch = skipWhitespace(read()); 701 702 switch (ch) { 703 case '+': return Expr.ADD; 704 case '-': return Expr.SUB; 705 case '*': return Expr.MUL; 706 case '/': return Expr.DIV; 707 case '%': return Expr.MOD; 708 709 case '!': 710 ch = read(); 711 if (ch == '=') 712 return Expr.NE; 713 else 714 return Expr.NOT; 715 716 case '=': 717 ch = read(); 718 if (ch == '=') 719 return Expr.EQ; 720 else 721 throw error(L.l("expected '==' at '={0}'", badChar(ch))); 722 723 case '&': 724 ch = read(); 725 if (ch == '&') 726 return Expr.AND; 727 else 728 throw error(L.l("expected '&&' at '&{0}'", badChar(ch))); 729 730 case '|': 731 ch = read(); 732 if (ch == '|') 733 return Expr.OR; 734 else 735 throw error(L.l("expected '||' at '|{0}'", badChar(ch))); 736 737 case '<': 738 ch = read(); 739 if (ch == '=') 740 return Expr.LE; 741 else { 742 unread(); 743 return Expr.LT; 744 } 745 746 case '>': 747 ch = read(); 748 if (ch == '=') 749 return Expr.GE; 750 else { 751 unread(); 752 return Expr.GT; 753 } 754 755 case '[': 756 return '['; 757 758 case ']': 759 return ']'; 760 761 case ')': 762 return ')'; 763 764 case '(': 765 return '('; 766 767 case '.': 768 return '.'; 769 770 case ',': 771 return ','; 772 773 case '?': 774 case ':': 775 return ch; 776 777 default: 778 if (Character.isJavaIdentifierStart((char) ch)) { 779 String name = readName(ch); 780 781 if (name.equals("div")) 782 return Expr.DIV; 783 else if (name.equals("mod")) 784 return Expr.MOD; 785 else if (name.equals("eq")) 786 return Expr.EQ; 787 else if (name.equals("ne")) 788 return Expr.NE; 789 else if (name.equals("lt")) 790 return Expr.LT; 791 else if (name.equals("le")) 792 return Expr.LE; 793 else if (name.equals("gt")) 794 return Expr.GT; 795 else if (name.equals("ge")) 796 return Expr.GE; 797 else if (name.equals("and")) 798 return Expr.AND; 799 else if (name.equals("or")) 800 return Expr.OR; 801 else 802 throw error(L.l("expected binary operation at `{0}'", name)); 803 } 804 805 unread(); 806 return -1; 807 } 808 } 809 810 private String readName(int ch) 811 { 812 CharBuffer cb = CharBuffer.allocate(); 813 814 for (; Character.isJavaIdentifierPart((char) ch); ch = read()) 815 cb.append((char) ch); 816 817 unread(); 818 819 return cb.toString(); 820 } 821 822 825 private int skipWhitespace(int ch) 826 throws ELParseException 827 { 828 for (; ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'; ch = read()) { 829 } 830 831 return ch; 832 } 833 834 837 private int read() 838 { 839 if (_index < _string.length()) 840 return _string.charAt(_index++); 841 else { 842 _index++; 843 return -1; 844 } 845 } 846 847 850 private void unread() 851 { 852 _index--; 853 } 854 855 858 private String badChar(int ch) 859 { 860 if (ch < 0) 861 return L.l("end of file"); 862 else if (ch == '\n') 863 return L.l("end of line"); 864 else 865 return "`" + (char) ch + "'"; 866 } 867 868 871 private ELParseException error(String message) 872 { 873 return new ELParseException(message + " in " + _string); 874 } 875 } 876 | Popular Tags |