1 28 29 package com.caucho.es.parser; 30 31 import com.caucho.es.ESBase; 32 import com.caucho.es.ESException; 33 import com.caucho.es.ESId; 34 import com.caucho.es.ESParseException; 35 import com.caucho.es.Script; 36 import com.caucho.java.JavaCompiler; 37 import com.caucho.java.LineMap; 38 import com.caucho.loader.SimpleLoader; 39 import com.caucho.log.Log; 40 import com.caucho.server.util.CauchoSystem; 41 import com.caucho.util.CharBuffer; 42 import com.caucho.util.IntArray; 43 import com.caucho.util.L10N; 44 import com.caucho.vfs.MergePath; 45 import com.caucho.vfs.Path; 46 import com.caucho.vfs.ReadStream; 47 import com.caucho.vfs.Vfs; 48 import com.caucho.vfs.WriteStream; 49 50 import java.io.IOException ; 51 import java.util.ArrayList ; 52 import java.util.logging.Logger ; 53 54 88 public class Parser { 89 private static final Logger log = Log.open(Parser.class); 90 private static final L10N L = new L10N(Parser.class); 91 private static final Object LOCK = new Object (); 92 93 static ESId CLINIT = ESId.intern("__clinit__"); 94 static ESId PROTOTYPE = ESId.intern("prototype"); 95 static ESId FINALLY = ESId.intern("finally"); 96 static ESId ANONYMOUS = ESId.intern("anonymous"); 97 static ESId OBJECT = ESId.intern("Object"); 98 static ESId REGEXP = ESId.intern("RegExp"); 99 static ESId ARRAY = ESId.intern("Array"); 100 static ESId LENGTH = ESId.intern("length"); 101 static ESId PACKAGES = ESId.intern("Packages"); 102 static ESId JAVA = ESId.intern("java"); 103 static ESId COM = ESId.intern("com"); 104 static ESId CAUCHO = ESId.intern("caucho"); 105 106 static final int PREC_DOT = 1; 107 static final int PREC_POST = PREC_DOT; 108 static final int PREC_FUN = PREC_POST + 1; 109 static final int PREC_UMINUS = PREC_FUN + 1; 110 static final int PREC_TIMES = PREC_UMINUS + 1; 111 static final int PREC_PLUS = PREC_TIMES + 1; 112 static final int PREC_SHIFT = PREC_PLUS + 1; 113 static final int PREC_CMP = PREC_SHIFT + 1; 114 static final int PREC_EQ = PREC_CMP + 1; 115 static final int PREC_BITAND = PREC_EQ + 1; 116 static final int PREC_BITXOR = PREC_BITAND + 1; 117 static final int PREC_BITOR = PREC_BITXOR + 1; 118 static final int PREC_AND = PREC_BITOR + 1; 119 static final int PREC_OR = PREC_AND + 1; 120 static final int PREC_COND = PREC_OR + 1; 121 static final int PREC_ASSIGN = PREC_COND + 1; 122 static final int PREC_COMMA = PREC_ASSIGN + 1; 123 static final int PREC_MAX = PREC_COMMA + 1; 124 125 ClassLoader parentLoader; 126 ClassLoader loader; 127 128 Path scriptPath; 129 boolean isEval; 130 String className; 132 133 Lexer lexer; 134 IntArray hashes = new IntArray(); 135 136 ArrayList importList = new ArrayList (); 137 138 ParseClass parseClass; 139 Function globalFunction; 140 Function staticFunction; 141 Function function; Block block; 143 144 LineMap lineMap; 145 Path workPath; 146 boolean isFast; 148 149 public Parser() 150 { 151 workPath = CauchoSystem.getWorkPath(); 152 addImport("java.lang.*"); 154 addImport("com.caucho.jslib.*"); 155 } 156 157 163 public void setParentLoader(ClassLoader parentLoader) 164 { 165 this.parentLoader = parentLoader; 166 } 167 168 172 public void setClassLoader(ClassLoader loader) 173 { 174 this.loader = loader; 175 } 176 177 181 ClassLoader getClassLoader() 182 { 183 if (loader != null) 184 return loader; 185 186 if (parentLoader != null) 187 loader = SimpleLoader.create(parentLoader, workPath, null); 188 else 189 loader = SimpleLoader.create(null, workPath, null); 190 191 return loader; 192 } 193 194 215 public void setScriptPath(Path scriptPath) 216 { 217 this.scriptPath = scriptPath; 218 } 219 220 226 public Path getScriptPath() 227 { 228 return scriptPath; 229 } 230 231 241 public void addImport(String name) 242 { 243 if (! importList.contains(name)) 244 importList.add(name); 245 } 246 247 253 public void setFast(boolean isFast) 254 { 255 this.isFast = isFast; 256 } 257 258 263 public void setLineMap(LineMap lineMap) 264 { 265 this.lineMap = lineMap; 266 } 267 268 272 public void setClassName(String name) 273 { 274 this.className = name; 275 } 276 277 285 public void setWorkDir(Path path) 286 { 287 workPath = path; 288 } 289 290 293 public Path getWorkDir() 294 { 295 return workPath; 296 } 297 298 308 public Script parse(String name) throws ESException, IOException 309 { 310 Path path; 311 312 try { 313 String className; 314 315 if (this.className != null) 316 className = this.className; 317 else 318 className = "_js." + JavaCompiler.mangleName(name); 319 320 if (scriptPath == null) { 321 MergePath mergePath = new MergePath(); 322 mergePath.addMergePath(Vfs.lookup()); 323 ClassLoader parentLoader = this.parentLoader; 324 if (parentLoader == null) 325 parentLoader = Thread.currentThread().getContextClassLoader(); 326 327 mergePath.addClassPath(parentLoader); 328 scriptPath = mergePath; 329 } 330 331 Script script = loadScript(className); 332 333 if (! script.isModified()) { 334 script.setScriptPath(getScriptPath()); 335 script.setClassDir(workPath); 336 return script; 337 } 338 } catch (Throwable e) { 339 } 340 341 path = getScriptPath().lookup(name); 342 343 ReadStream is = path.openRead(); 344 try { 345 return parse(is, name, 1); 346 } finally { 347 is.close(); 348 } 349 } 350 351 361 public Script parse(ReadStream is) throws ESException, IOException 362 { 363 return parse(is, null, 1); 364 } 365 366 376 public Script parse(ReadStream is, String name, int line) 377 throws ESException, IOException 378 { 379 if (name == null) 380 name = is.getUserPath(); 381 382 if (line <= 0) 383 line = 1; 384 385 return parse(is, name, line, false); 386 } 387 388 399 public Script parseEval(ReadStream is, String name, int line) 400 throws ESException, IOException 401 { 402 if (name == null) 403 name = "eval"; 404 405 if (line <= 0) 406 line = 1; 407 408 return parse(is, name, line, true); 409 } 410 411 421 private Script parse(ReadStream is, String name, 422 int line, boolean isEval) 423 throws ESException, IOException 424 { 425 if (name == null) 426 name = "anonymous"; 427 428 if (line <= 0) 429 line = 1; 430 431 lexer = new Lexer(is, name, line); 432 if (lineMap != null) 433 lexer.setLineMap(lineMap); 434 435 if (className == null) 436 className = "_js." + JavaCompiler.mangleName(name); 437 438 if (scriptPath == null) { 439 MergePath mergePath = new MergePath(); 440 if (is.getPath() != null) 441 mergePath.addMergePath(is.getPath().getParent()); 442 else 443 mergePath.addMergePath(Vfs.lookup()); 444 ClassLoader parentLoader = this.parentLoader; 445 if (parentLoader == null) 446 parentLoader = Thread.currentThread().getContextClassLoader(); 447 448 mergePath.addClassPath(parentLoader); 449 scriptPath = mergePath; 450 } 451 452 block = null; 453 454 JavaCompiler compiler = JavaCompiler.create(getClassLoader()); 455 compiler.setClassDir(workPath); 456 457 parseClass = new ParseClass(name, className); 458 parseClass.setParser(this); 459 if (is.getPath() != null && is.getPath().getLastModified() > 0) 460 parseClass.setSourcePath(is.getPath()); 461 462 globalFunction = parseClass.newFunction(null, ESId.intern("global"), false); 463 globalFunction.setFast(isFast); 464 staticFunction = parseClass.newFunction(null, ESId.intern("__es_static"), false); 465 parseClass.setGlobal(globalFunction); 466 467 if (isEval) { 468 block = Block.create(this, globalFunction); 469 block.finish(); 470 function = parseClass.newFunction(globalFunction, ESId.intern("eval"), false); 471 function.setEval(); 472 } 473 else 474 function = globalFunction; 475 476 block = Block.create(this, function); 477 parseBlock(true); 478 block.finish(); 479 480 if (lexer.peek() != Lexer.EOF) 481 throw expect(L.l("end of file")); 482 483 block = Block.create(this, staticFunction); 484 block.finish(); 485 486 synchronized (LOCK) { 487 Path path = workPath.lookup(className.replace('.', '/') + ".java"); 488 path.getParent().mkdirs(); 489 490 WriteStream os = path.openWrite(); 491 os.setEncoding("JAVA"); 492 parseClass.writeCode(os); 493 os.close(); 494 495 Script script; 496 try { 497 compiler.compile(className.replace('.', '/') + ".java", null); 498 script = loadScript(className); 499 } catch (Exception e) { 500 throw new ESParseException(e); 501 } 502 503 script.setScriptPath(getScriptPath()); 504 script.setClassDir(workPath); 505 506 return script; 507 } 508 } 509 510 515 private Script loadScript(String className) 516 throws Exception 517 { 518 ClassLoader loader = getClassLoader(); 519 Class cl = CauchoSystem.loadClass(className, false, loader); 520 521 Script script = (Script) cl.newInstance(); 522 script.setScriptPath(getScriptPath()); 523 script.setClassDir(workPath); 524 525 return script; 526 } 527 528 531 private Function parseFunction() throws ESException 532 { 533 function.setNeedsScope(); 534 535 ESId id = null; 536 if (lexer.peek() == Lexer.IDENTIFIER) { 537 lexer.next(); 538 id = lexer.getId(); 539 } 540 541 if (lexer.next() != '(') 542 throw expect("`('"); 543 544 if (id != null) { 545 function.addVariable(block, id, null); 546 block.newVar(id).getVar().setType(Expr.TYPE_ES); 547 } 548 549 Block oldBlock = block; 550 Function oldFun = function; 551 function = parseClass.newFunction(oldFun, id, false); 552 553 oldFun.addFunction(function); 554 555 block = Block.create(this, function); 556 557 boolean isFirst = true; 558 while (lexer.peek() != ')') { 559 if (! isFirst && lexer.next() != ',') 560 throw expect("`,'"); 561 isFirst = false; 562 563 if (lexer.next() != Lexer.IDENTIFIER) 564 throw expect(L.l("formal argument")); 565 566 ESId argId = lexer.getId(); 567 568 Expr type = null; 569 if (lexer.peek() == ':') { 570 lexer.next(); 571 type = parseType(); 572 } 573 574 function.addFormal(block, argId, type); 575 } 576 lexer.next(); 577 578 if (lexer.peek() == ':') { 579 lexer.next(); 580 Expr type = parseType(); 581 582 function.setReturnType(type); 583 } 584 585 if (lexer.next() != '{') 586 throw expect("`{'"); 587 588 parseBlock(false); 589 590 if (lexer.next() != '}') { 591 throw expect("`}'"); 592 } 593 594 block.finish(); 595 596 Function newFun = function; 597 598 function = oldFun; 599 block = oldBlock; 600 601 return newFun; 602 } 603 604 611 private void parseBlock(boolean isTop) 612 throws ESException 613 { 614 loop: 615 while (true) { 616 switch (lexer.peek()) { 617 case Lexer.UNARY_OP: 618 case Lexer.BANDU_OP: 619 case Lexer.NEW: 620 case Lexer.DELETE: 621 case Lexer.VOID: 622 case Lexer.TYPEOF: 623 case Lexer.POSTFIX: 624 case Lexer.IDENTIFIER: 625 case Lexer.THIS: 626 case Lexer.EVAL: 627 case Lexer.LITERAL: 628 case Lexer.REGEXP: 629 case '(': 630 case '[': 631 case Lexer.HASH_REF: 632 case Lexer.HASH_DEF: 633 case Lexer.FUNCTION: 634 parseStatement(); 635 break; 636 637 case Lexer.IF: 638 case Lexer.FOR: 639 case Lexer.WHILE: 640 case Lexer.DO: 641 case Lexer.VAR: 642 case Lexer.BREAK: 643 case Lexer.WITH: 644 case Lexer.SYNCHRONIZED: 645 case Lexer.CONTINUE: 646 case Lexer.RETURN: 647 case Lexer.SWITCH: 648 case Lexer.TRY: 649 case Lexer.THROW: 650 case ';': 651 parseStatement(); 652 break; 653 654 case '{': 655 block = block.startBlock(); 656 parseStatement(); 657 block = block.finishBlock(); 658 break; 659 660 case Lexer.CATCH: 661 block.doTry(); 662 parseCatch(); 663 break; 664 665 case Lexer.FINALLY: 666 block.doTry(); 667 parseFinally(); 668 break; 669 670 case Lexer.CLASS: 671 parseClass(); 672 break; 673 674 case Lexer.IMPORT: 675 parseImport(); 676 break; 677 678 case Lexer.STATIC: 679 if (true) throw new ESException("nostatus"); 680 break; 682 683 default: 684 break loop; 685 } 686 } 687 } 688 689 692 private void parseStatement() throws ESException 693 { 694 int lexeme = lexer.peek(); 695 hashes.clear(); 696 int line = lexer.getLine(); 697 Expr expr = null; 698 699 block.setLine(line); 700 701 if (block.isDead) { 702 switch (lexeme) { 703 case ';': 704 case Lexer.VAR: 705 case Lexer.FUNCTION: 706 case Lexer.CATCH: 707 case Lexer.FINALLY: 708 break; 709 710 default: 711 throw error(L.l("can't reach statement")); 712 } 713 } 714 715 switch (lexeme) { 716 case Lexer.IDENTIFIER: 717 parseIdentifierStatement(); 718 break; 719 720 case Lexer.UNARY_OP: 721 case Lexer.BANDU_OP: 722 case Lexer.NEW: 723 case Lexer.THIS: 724 case Lexer.EVAL: 725 case Lexer.LITERAL: 726 case Lexer.REGEXP: 727 case Lexer.POSTFIX: 728 case Lexer.DELETE: 729 case Lexer.VOID: 730 case Lexer.TYPEOF: 731 case '(': 732 case '[': 733 case Lexer.HASH_REF: 734 case Lexer.HASH_DEF: 735 block.addExpr(parseExpression(PREC_MAX, true)); 736 parseStatementEnd(); 737 break; 738 739 case Lexer.FUNCTION: 740 lexer.next(); 741 Function newFun = parseFunction(); 742 break; 743 744 case Lexer.VAR: 745 parseVar(false); 746 parseStatementEnd(); 747 break; 748 749 case Lexer.BREAK: 750 lexer.next(); 751 if (lexer.peek() == Lexer.IDENTIFIER && ! lexer.seenLineFeed()) { 752 block.doBreak(lexer.getId()); 753 lexer.next(); 754 } else 755 block.doBreak(); 756 parseStatementEnd(); 757 break; 758 759 case Lexer.CONTINUE: 760 lexer.next(); 761 if (lexer.peek() == Lexer.IDENTIFIER && ! lexer.seenLineFeed()) { 762 block.doContinue(lexer.getId()); 763 lexer.next(); 764 } else 765 block.doContinue(); 766 767 parseStatementEnd(); 768 break; 769 770 case Lexer.RETURN: 771 lexer.next(); 772 773 if (lexer.peek() == ';' || lexer.peek() == '}' || 774 lexer.seenLineFeed()) { 775 block.doReturn(); 776 } else { 777 block.doReturn(parseExpression(PREC_MAX, true)); 778 } 779 780 parseStatementEnd(); 781 break; 782 783 case Lexer.IF: 784 parseIf(); 785 break; 786 787 case Lexer.SWITCH: 788 parseSwitch(); 789 break; 790 791 case Lexer.WHILE: 792 parseWhile(null); 793 break; 794 795 case Lexer.DO: 796 parseDo(null); 797 break; 798 799 case Lexer.FOR: 800 parseFor(null); 801 break; 802 803 case Lexer.WITH: 804 parseWith(); 805 break; 806 807 case Lexer.SYNCHRONIZED: 808 parseSynchronized(); 809 break; 810 811 case Lexer.TRY: 812 parseTry(); 813 break; 814 815 case Lexer.THROW: 816 lexer.next(); 817 block.doThrow(parseExpression(PREC_MAX)); 818 break; 819 820 case ';': 821 lexer.next(); 822 break; 823 824 case '{': 825 lexer.next(); 826 parseBlock(false); 827 if (lexer.next() != '}') 828 throw expect("`}'"); 829 break; 830 831 default: 832 throw expect(L.l("statement")); 833 } 834 } 835 836 private void parseStatementEnd() throws ESException 837 { 838 if (lexer.peek() == ';') 839 lexer.next(); 840 else if (lexer.peek() == '}' || 841 lexer.peek() == Lexer.EOF || lexer.seenLineFeed()) { 842 } else { 843 throw expect("`;'"); 844 } 845 } 846 847 private void parseIdentifierStatement() 848 throws ESException 849 { 850 ESId id = lexer.getId(); 851 int line = lexer.getLine(); 852 853 lexer.next(); 854 if (lexer.peek() != ':') { 855 Expr var = getVar(id); 856 Expr expr = parseExprRec(parseTermTail(var, false, true), 857 PREC_MAX, false, true); 858 block.addExpr(expr); 859 parseStatementEnd(); 860 return; 861 } 862 863 lexer.next(); 864 865 869 870 switch (lexer.peek()) { 871 case Lexer.WHILE: 872 parseWhile(id); 873 break; 874 875 case Lexer.DO: 876 parseDo(id); 877 break; 878 879 case Lexer.FOR: 880 parseFor(id); 881 break; 882 883 default: 884 block = block.startBlock(id); 885 parseStatement(); 886 block = block.finishBlock(); 887 break; 888 } 889 } 890 891 private Expr parseType() throws ESException 892 { 893 if (lexer.next() != Lexer.IDENTIFIER) 894 throw expect(L.l("identifier")); 895 896 Expr type = block.newType(lexer.getId()); 897 898 while (lexer.peek() == '.') { 899 lexer.next(); 900 if (lexer.next() != Lexer.IDENTIFIER) 901 throw expect(L.l("identifier")); 902 903 type = type.fieldReference(lexer.getId()); 904 } 905 906 return type; 907 } 908 909 912 private void parseIf() throws ESException 913 { 914 boolean isFirst = true; 915 boolean isDead = true; 916 917 block = block.create(); 918 919 while (lexer.peek() == Lexer.IF) { 920 lexer.next(); 921 922 if (lexer.next() != '(') 923 throw expect("`('"); 924 925 block.startIf(parseBooleanExpression(PREC_MAX), ! isFirst); 926 isFirst = false; 927 928 if (lexer.next() != ')') 929 throw expect("`)'"); 930 931 parseStatement(); 932 933 block.endBlock(); 934 if (! block.isDead) 935 isDead = false; 936 block.isDead = false; 937 938 if (lexer.peek() != Lexer.ELSE) { 939 block = block.pop(); 940 return; 941 } 942 943 lexer.next(); 944 } 945 946 block.startElse(); 947 parseStatement(); 948 block.endBlock(); 949 if (! block.isDead) 950 isDead = false; 951 block = block.pop(); 952 block.isDead = isDead; 953 } 954 955 958 private void parseSwitch() throws ESException 959 { 960 lexer.next(); 961 if (lexer.next() != '(') 962 throw expect("`)'"); 963 964 Expr test = parseExpression(PREC_MAX); 965 966 if (lexer.next() != ')') 967 throw expect("`)'"); 968 969 if (lexer.next() != '{') 970 throw expect("`{'"); 971 972 ArrayList exprs = new ArrayList (); 973 974 block = block.startSwitch(test); 975 976 int ch; 977 while ((ch = lexer.peek()) != -1 && ch != '}') { 978 switch (ch) { 979 case Lexer.CASE: 980 lexer.next(); 981 block.doCase(exprs.size()); 982 exprs.add(parseExpression(PREC_MAX)); 983 984 if (lexer.next() != ':') 985 throw expect("`:'"); 986 break; 987 988 case Lexer.DEFAULT: 989 lexer.next(); 990 if (lexer.next() != ':') 991 throw expect("`:'"); 992 993 block.doDefault(); 994 break; 995 996 default: 997 parseStatement(); 998 } 999 } 1000 1001 if (lexer.next() != '}') 1002 throw expect("`}'"); 1003 1004 block = block.fillSwitch(exprs); 1005 } 1006 1007 1010 private void parseWhile(ESId id) throws ESException 1011 { 1012 lexer.next(); 1013 if (lexer.next() != '(') 1014 throw expect("`('"); 1015 1016 Expr expr = parseBooleanExpression(PREC_MAX); 1017 if (expr instanceof LiteralExpr && 1018 ! ((LiteralExpr) expr).getLiteral().toBoolean()) 1019 throw error(L.l("while (false) is never executed.")); 1020 block = block.startWhile(id, expr); 1021 1022 if (lexer.next() != ')') 1023 throw expect("`)'"); 1024 1025 parseStatement(); 1026 block = block.endLoop(); 1027 } 1028 1029 1032 private void parseFor(ESId id) throws ESException 1033 { 1034 lexer.next(); 1035 if (lexer.next() != '(') 1036 throw expect("`('"); 1037 1038 boolean hasValue = false; 1039 Expr lhs = null; 1040 if (lexer.peek() == Lexer.VAR) { 1041 lhs = parseVar(true); 1042 } 1043 else if (lexer.peek() != ';') { 1044 lhs = parseExpression(PREC_MAX); 1045 } else if (lexer.peek() == Lexer.IN) 1046 throw expect(L.l("expression")); 1047 1048 if (lexer.peek() == Lexer.IN) { 1049 parseForIn(id, lhs); 1050 return; 1051 } 1052 1053 if (lhs != null) 1054 lhs.exprStatement(block.function); 1055 1056 if (lexer.next() != ';') 1057 throw expect("`;'"); 1058 1059 Expr test = null; 1060 if (lexer.peek() != ';') 1061 test = parseExpression(PREC_MAX); 1062 1063 if (lexer.next() != ';') 1064 throw expect("`;'"); 1065 1066 Expr incr = null; 1067 if (lexer.peek() != ')') { 1068 incr = parseExpression(PREC_MAX); 1069 incr.killValue(); 1070 } 1071 1072 if (lexer.next() != ')') 1073 throw expect("`)'"); 1074 1075 if (test instanceof LiteralExpr && 1076 ! ((LiteralExpr) test).getLiteral().toBoolean()) 1077 throw error(L.l("for (;false;) is never executed.")); 1078 block = block.startFor(id, test, incr); 1079 parseStatement(); 1080 block = block.endLoop(); 1081 } 1082 1083 private void parseForIn(ESId id, Expr lhs) 1084 throws ESException 1085 { 1086 lexer.next(); 1087 1088 String var = block.newIterator(id, parseExpression(PREC_MAX)); 1089 1090 if (lexer.next() != ')') 1091 throw expect("`)'"); 1092 1093 block = block.startWhile(id, block.hasNext(var)); 1094 1095 block.addExpr(lhs.next(var, lhs)); 1096 1097 parseStatement(); 1098 block = block.endLoop(); 1099 } 1100 1101 1104 private void parseDo(ESId id) throws ESException 1105 { 1106 lexer.next(); 1107 1108 block = block.startDo(id); 1109 parseStatement(); 1110 1111 if (lexer.next() != Lexer.WHILE) 1112 throw expect("`while'"); 1113 1114 if (lexer.next() != '(') 1115 throw expect("`('"); 1116 1117 block = block.endDo(parseBooleanExpression(PREC_MAX)); 1118 1119 if (lexer.next() != ')') 1120 throw expect("`)'"); 1121 1122 parseStatementEnd(); 1123 } 1124 1125 1128 private void parseWith() throws ESException 1129 { 1130 lexer.next(); 1131 if (lexer.next() != '(') 1132 throw expect("`('"); 1133 1134 block = block.startWith(parseExpression(PREC_MAX)); 1135 1136 if (lexer.next() != ')') 1137 throw expect("`)'"); 1138 1139 parseStatement(); 1140 1141 block = block.endWith(); 1142 } 1143 1144 1147 private Expr parseVar(boolean keepValue) throws ESException 1148 { 1149 boolean isFirst = true; 1150 Expr retVar = null; 1151 do { 1152 lexer.next(); 1153 1154 if (lexer.next() != Lexer.IDENTIFIER) 1155 throw expect(L.l("identifier")); 1156 1157 ESId name = lexer.getId(); 1158 1159 Expr type = null; 1160 1161 if (lexer.peek() == ':') { 1162 lexer.next(); 1163 1164 type = parseType(); 1165 } 1166 1167 block.defVar(name, type); 1168 1169 if (lexer.peek() == '=') { 1170 lexer.next(); 1171 1172 Expr var = block.newVar(name, type); 1173 Expr value = parseExpression(Parser.PREC_ASSIGN + 1, true); 1174 block.evalExpr(); 1175 var.assign(value).exprStatement(block.function); 1176 } else if (keepValue) 1177 retVar = block.newVar(name, type); 1178 1179 isFirst = false; 1180 } while (lexer.peek() == ','); 1181 1182 return retVar; 1183 } 1184 1185 1188 private void parseSynchronized() throws ESException 1189 { 1190 lexer.next(); 1191 if (lexer.next() != '(') 1192 throw expect("`('"); 1193 1194 block = block.startSynchronized(parseExpression(PREC_MAX)); 1195 1196 if (lexer.next() != ')') 1197 throw expect("`)'"); 1198 1199 parseStatement(); 1200 1201 block = block.endSynchronized(); 1202 } 1203 1204 1207 private void parseTry() throws ESException 1208 { 1209 lexer.next(); 1210 1211 block = block.startTry(); 1212 parseStatement(); 1213 block = block.endTry(); 1214 1215 if (lexer.peek() == Lexer.CATCH) { 1216 parseCatch(); 1217 } 1218 else if (lexer.peek() == Lexer.FINALLY) 1219 parseFinally(); 1220 else 1221 throw error(L.l("expected `catch' or `finally' at {0}", getToken())); 1222 } 1223 1224 1227 private void parseCatch() throws ESException 1228 { 1229 block.function.disallowJavaLocal(); 1230 1232 boolean oldDead = block.isDead; 1233 boolean hasCatchall = false; 1234 1235 while (lexer.peek() == Lexer.CATCH) { 1236 block.isDead = false; 1237 1238 if (hasCatchall) 1239 throw error(L.l("catch () must be last catch clause")); 1240 1241 lexer.next(); 1242 if (lexer.next() != '(') 1243 throw expect("`('"); 1244 1245 String exceptionClass = ""; 1246 while (lexer.peek() == Lexer.IDENTIFIER) { 1247 lexer.next(); 1248 exceptionClass = exceptionClass + lexer.getText(); 1249 1250 if (lexer.peek() != '.') 1251 break; 1252 1253 lexer.next(); 1254 exceptionClass = exceptionClass + "."; 1255 if (lexer.peek() != Lexer.IDENTIFIER) 1256 throw expect(L.l("identifier")); 1257 } 1258 1259 ESId name = null; 1260 if (lexer.peek() == Lexer.IDENTIFIER) { 1261 name = lexer.getId(); 1262 lexer.next(); 1263 } 1264 1265 if (lexer.next() != ')') { 1266 if (exceptionClass.equals("")) 1267 throw expect(L.l("identifier")); 1268 else 1269 throw expect("`)'"); 1270 } 1271 1272 if (name == null) { 1273 name = ESId.intern(exceptionClass); 1274 exceptionClass = "java.lang.Exception"; 1275 } 1276 1277 Expr var = null; 1278 if (name != null) 1279 var = block.newVar(name); 1280 1281 block = block.startCatch(exceptionClass, var); 1282 parseStatement(); 1283 if (! block.isDead) 1284 oldDead = false; 1285 block = block.endCatch(); 1286 } 1287 1288 block.isDead = oldDead; 1289 if (lexer.peek() == Lexer.FINALLY) 1291 parseFinally(); 1292 } 1293 1294 1297 private void parseFinally() throws ESException 1298 { 1299 boolean oldDead = block.isDead; 1300 block.isDead = false; 1301 lexer.next(); 1302 1303 block = block.startFinally(); 1304 1305 parseStatement(); 1306 1307 block = block.endFinally(); 1308 block.isDead = oldDead; 1309 } 1310 1311 static ESId BOGUS = ESId.intern("return "); 1312 1313 1316 private void parseClass() throws ESException 1317 { 1318 if (function.getParent() != null) 1319 throw error(L.l("`class' only allowed at top level")); 1320 1321 lexer.next(); 1322 1323 if (lexer.next() != Lexer.IDENTIFIER) 1324 throw expect("class name"); 1325 1326 ESId id = lexer.getId(); 1327 1328 ESId proto = parseExtends(); 1329 1330 if (lexer.next() != '{') 1331 throw expect("`{'"); 1332 1333 ParseClass oldClass = parseClass; 1334 Function oldGlobal = globalFunction; 1335 Function oldStatic = staticFunction; 1336 Function oldFunction = function; 1337 Block oldBlock = block; 1338 1339 parseClass = oldClass.newClass(id); 1340 parseClass.setProto(proto); 1341 1342 globalFunction = parseClass.newFunction(null, ESId.intern("global"), true); 1343 staticFunction = parseClass.newFunction(null, ESId.intern("__es_static"), true); 1344 parseClass.setGlobal(globalFunction); 1345 1346 function = globalFunction; 1347 block = Block.create(this, function); 1348 1349 parseBlock(true); 1350 block.finish(); 1351 1352 block = Block.create(this, staticFunction); 1353 block.finish(); 1354 1355 if (parseClass.getFunction(id) == null) { 1356 function = parseClass.newFunction(null, id, false); 1357 block = Block.create(this, function); 1358 block.finish(); 1359 } 1360 1361 block = oldBlock; 1362 function = oldFunction; 1363 globalFunction = oldGlobal; 1364 staticFunction = oldStatic; 1365 parseClass = oldClass; 1366 1367 if (lexer.next() != '}') 1368 throw expect("`}'"); 1369 } 1370 1371 private ESId parseExtends() 1372 throws ESException 1373 { 1374 if (lexer.peek() != Lexer.EXTENDS) 1375 return null; 1376 1377 lexer.next(); 1378 if (lexer.next() != Lexer.IDENTIFIER) 1379 throw expect(L.l("parent class name")); 1380 1381 return lexer.getId(); 1382 } 1383 1384 private void parseImport() 1385 throws ESException 1386 { 1387 CharBuffer path = new CharBuffer(); 1388 1389 lexer.next(); 1390 1391 while (true) { 1392 if (lexer.peek() == Lexer.BIN_OP && lexer.getOp() == '*') { 1393 lexer.next(); 1394 path.append('*'); 1395 importList.add(path.close()); 1396 return; 1397 } 1398 1399 if (lexer.peek() != Lexer.IDENTIFIER) 1400 throw expect(L.l("identifier")); 1401 1402 path.append(lexer.getText()); 1403 1404 lexer.next(); 1405 1406 if (lexer.peek() != '.') 1407 break; 1408 1409 lexer.next(); 1410 path.append('.'); 1411 } 1412 1413 String className = path.close(); 1414 String pathName = className.replace('.', '/') + ".js"; 1415 1416 Path importPath = getScriptPath().lookup(pathName); 1417 1418 if (importPath.exists()) { 1419 function.cl.addImport(pathName); 1420 return; 1421 } 1422 1423 try { 1424 CauchoSystem.loadClass(className, false, getClassLoader()); 1425 1426 importList.add(className); 1427 } catch (ClassNotFoundException e) { 1428 throw error(L.l("can't open import `{0}'", pathName)); 1429 } 1430 } 1431 1432 1451 1452 private Expr parseExpression(int prevPrec, boolean isTop) 1453 throws ESException 1454 { 1455 Expr result = parseExprRec(parseTerm(isTop), prevPrec, false, isTop); 1456 result.getType(); 1457 return result; 1458 } 1459 1460 private Expr parseBooleanExpression(int prevPrec) 1461 throws ESException 1462 { 1463 Expr result = parseExprRec(parseTerm(false), prevPrec, true, false); 1464 result.getType(); 1465 return result; 1466 } 1467 1468 private Expr parseExpression(int prevPrec) 1469 throws ESException 1470 { 1471 Expr result = parseExprRec(parseTerm(false), prevPrec, false, false); 1472 result.getType(); 1473 return result; 1474 } 1475 1476 private Expr parseExpression() 1477 throws ESException 1478 { 1479 Expr result = parseExprRec(parseTerm(false), PREC_MAX, false, false); 1480 result.getType(); 1481 return result; 1482 } 1483 1484 1490 private Expr parseExprRec(Expr lexpr, int prevPrec, 1491 boolean isBool, boolean isTop) 1492 throws ESException 1493 { 1494 Expr rexpr = null; 1495 int op = 0; 1496 int lex = 0; 1497 int prec = 0; 1498 1499 while (true) { 1500 boolean doLookahead = false; 1501 boolean doPostfix = false; 1502 boolean isRightAssoc = false; 1503 int nextPrec = 0; 1504 int nextOp = 0; 1505 int nextLex = 0; 1506 1507 switch (lexer.peek()) { 1508 case '=': 1509 if (op != 0 && lex != ',') 1510 throw error(L.l("illegal left hand side of assignment")); 1511 if (isBool) 1512 throw error(L.l("assignment used as boolean needs parentheses")); 1513 1514 case Lexer.BIN_OP: 1515 if (lexer.getOp() == Lexer.AND || lexer.getOp() == Lexer.OR) 1517 function.setVars(); 1518 case ',': 1520 case Lexer.BANDU_OP: 1521 case '?': 1522 nextLex = lexer.peek(); 1523 nextOp = lexer.getOp(); 1524 nextPrec = lexer.getPrecedence(); 1525 isRightAssoc = lexer.isRightAssoc(); 1526 doLookahead = true; 1527 break; 1528 1529 default: 1530 return op != 0 ? lexpr.binaryOp(lex, op, rexpr) : lexpr; 1531 } 1532 1533 if (nextPrec >= prevPrec) { 1534 return op != 0 ? lexpr.binaryOp(lex, op, rexpr) : lexpr; 1535 } 1536 else if (prec == 0) { 1537 } 1538 else if (nextPrec < prec) { 1539 rexpr = parseExprRec(rexpr, prec, isBool, isTop); 1540 continue; 1541 } 1542 else { 1543 lexpr = op != 0 ? lexpr.binaryOp(lex, op, rexpr) : lexpr; 1544 } 1545 1546 prec = nextPrec; 1547 lex = nextLex; 1548 op = nextOp; 1549 1550 if (doLookahead) 1551 lexer.next(); 1552 1553 if (isRightAssoc) { 1554 1555 rexpr = parseExpression(prec + 1, isTop); 1556 } 1557 else if (op == '?') { 1558 function.setVars(); 1559 Expr mexpr = parseExpression(Parser.PREC_ASSIGN + 1); 1560 if (lexer.peek() != ':') 1561 throw expect("`:'"); 1562 lexer.next(); 1563 rexpr = parseExpression(Parser.PREC_ASSIGN + 1, isTop); 1564 1565 lexpr = lexpr.conditional(mexpr, rexpr); 1566 op = 0; 1567 } 1568 else 1569 rexpr = parseTerm(isTop); 1570 } 1571 } 1572 1573 1583 private Expr parseTerm(boolean isTop) throws ESException 1584 { 1585 int op; 1586 1587 switch (lexer.peek()) { 1588 case Lexer.BANDU_OP: 1589 case Lexer.UNARY_OP: 1590 lexer.next(); 1591 op = lexer.getOp(); 1592 return parseTerm(isTop).unaryOp(op); 1593 1594 case Lexer.VOID: 1595 lexer.next(); 1596 return parseTerm(isTop).doVoid(); 1597 1598 case Lexer.TYPEOF: 1599 lexer.next(); 1600 return parseTerm(isTop).typeof(); 1601 1602 case Lexer.DELETE: 1603 lexer.next(); 1604 return parseTerm(isTop).delete(); 1605 1606 case Lexer.POSTFIX: 1607 lexer.next(); 1608 op = lexer.getOp(); 1609 return parseTerm(isTop).prefix(op); 1610 1611 case Lexer.LITERAL: 1612 case Lexer.REGEXP: 1613 case Lexer.IDENTIFIER: 1614 case Lexer.THIS: 1615 case Lexer.EVAL: 1616 case Lexer.NEW: 1617 case '(': 1618 case '{': 1619 case '[': 1620 case Lexer.HASH_REF: 1621 case Lexer.HASH_DEF: 1622 case Lexer.FUNCTION: 1623 return parseLhs(false, isTop); 1624 1625 default: 1626 throw expect(L.l("expression")); 1627 } 1628 } 1629 1630 1636 private Expr parseLhs(boolean hasNew, boolean isTop) 1637 throws ESException 1638 { 1639 String name; 1640 int op; 1641 Expr expr = null; 1642 1643 switch (lexer.next()) { 1644 case Lexer.NEW: 1645 return parseTermTail(parseLhs(true, isTop), hasNew, isTop); 1646 1647 case Lexer.LITERAL: 1648 return parseTermTail(block.newLiteral(lexer.getLiteral()), 1649 hasNew, isTop); 1650 1651 case Lexer.REGEXP: 1652 1657 throw new UnsupportedOperationException (); 1658 1659 case Lexer.IDENTIFIER: 1660 return parseTermTail(getVar(lexer.getId()), 1661 hasNew, isTop); 1662 1663 case Lexer.THIS: 1664 return parseTermTail(block.newThis(), hasNew, isTop); 1665 1666 case Lexer.EVAL: 1667 if (lexer.peek() != '(') 1668 throw expect("`('"); 1669 function.setArguments(); 1670 return parseTermTail(block.newVar(ESId.intern("eval")), hasNew, false); 1671 1672 case '(': 1673 expr = parseExpression(PREC_MAX); 1674 if (lexer.next() != ')') 1675 throw expect("`)'"); 1676 return parseTermTail(expr, hasNew, isTop); 1677 1678 case '{': 1679 expr = parseObjectLiteral(-1); 1680 if (lexer.next() != '}') 1681 throw expect("`}'"); 1682 return parseTermTail(expr, hasNew, isTop); 1683 1684 case '[': 1685 expr = parseArrayLiteral(-1); 1686 if (lexer.next() != ']') 1687 throw expect("`]'"); 1688 return parseTermTail(expr, hasNew, isTop); 1689 1690 case Lexer.FUNCTION: 1691 Function newFun = parseFunction(); 1692 1693 function.addVariable(block, newFun.id, null); 1695 block.newVar(newFun.id).getVar().setType(Expr.TYPE_ES); 1696 expr = block.newVar(newFun.id); 1697 return parseTermTail(expr, hasNew, isTop); 1698 1699 case Lexer.HASH_DEF: 1700 switch (lexer.peek()) { 1701 case '{': 1702 lexer.next(); 1703 expr = parseObjectLiteral(lexer.intValue); 1704 if (lexer.next() != '}') 1705 throw expect("`}'"); 1706 return parseTermTail(expr, hasNew, isTop); 1707 1708 case '[': 1709 lexer.next(); 1710 expr = parseArrayLiteral(lexer.intValue); 1711 if (lexer.next() != ']') 1712 throw expect("`]'"); 1713 return parseTermTail(expr, hasNew, isTop); 1714 1715 default: 1716 1723 return expr; 1724 } 1725 1734 default: 1735 throw expect(L.l("term")); 1736 } 1737 } 1738 1739 1748 private Expr parseTermTail(Expr term, boolean hasNew, boolean isTop) 1749 throws ESException 1750 { 1751 int op; 1752 1753 while (true) { 1754 switch (lexer.peek()) { 1755 case '.': 1756 lexer.next(); 1757 if (lexer.next() != Lexer.IDENTIFIER) 1758 throw expect(L.l("property name")); 1759 1760 term = term.fieldReference(lexer.getId()); 1761 break; 1762 1763 case '(': 1764 if (isTop && lexer.seenLineFeed()) 1765 return term; 1766 1767 lexer.next(); 1768 1769 int n = 0; 1770 CallExpr call; 1771 if (hasNew) 1772 call = term.startNew(); 1773 else 1774 call = term.startCall(); 1775 1776 while (lexer.peek() != ')') { 1777 if (n != 0 && lexer.peek() != ',') 1778 throw expect("`,'"); 1779 else if (n != 0) 1780 lexer.next(); 1781 1782 call.addCallParam(parseExpression(PREC_COMMA)); 1783 n++; 1784 } 1785 lexer.next(); 1786 1787 if (hasNew) 1788 return call; 1789 else 1790 term = call; 1791 break; 1792 1793 case '[': 1794 if (isTop && lexer.seenLineFeed()) 1795 return term; 1796 1797 lexer.next(); 1798 term = term.fieldReference(parseExpression(PREC_MAX)); 1799 1800 if (lexer.next() != ']') 1801 throw expect("`]'"); 1802 break; 1803 1804 case Lexer.POSTFIX: 1805 if (hasNew) 1806 return term.startNew(); 1807 1808 if (lexer.seenLineFeed()) 1809 return term; 1810 1811 term = term.postfix(lexer.getOp()); 1812 1813 lexer.next(); 1814 break; 1815 1816 case '@': 1817 lexer.next(); 1818 1819 term = term.cast(parseType()); 1820 break; 1821 1822 default: 1823 if (hasNew) 1824 return term.startNew(); 1825 else 1826 return term; 1827 } 1828 } 1829 } 1830 1831 private Expr parseObjectLiteral(int hash) throws ESException 1832 { 1833 Expr expr = block.newVar(ESId.intern("Object")); 1834 CallExpr call = expr.startCall(); 1835 1836 1843 1844 if (lexer.peek() == ',') { 1845 lexer.next(); 1846 1847 return call; 1848 } 1849 1850 while (lexer.peek() == Lexer.LITERAL || 1851 lexer.peek() == Lexer.IDENTIFIER) { 1852 ESId id; 1853 1854 if (lexer.next() == Lexer.LITERAL) 1855 id = ESId.intern(lexer.literal.toString()); 1856 else 1857 id = lexer.getId(); 1858 1859 if (lexer.next() != ':') 1860 throw expect("`:'"); 1861 1862 call.addCallParam(block.newLiteral(id)); 1863 call.addCallParam(parseExpression(PREC_COMMA)); 1864 1865 if (lexer.peek() != ',') 1866 break; 1867 lexer.next(); 1868 } 1869 1870 return call; 1871 } 1872 1873 private Expr parseArrayLiteral(int hash) 1874 throws ESException 1875 { 1876 Expr expr = block.newVar(ESId.intern("Array")); 1877 1878 CallExpr call = expr.startCall(); 1879 1880 boolean isFirst = true; 1881 while (lexer.peek() != ']') { 1882 if (lexer.peek() == ',') { 1883 lexer.next(); 1884 call.addCallParam(block.newLiteral(ESBase.esUndefined)); 1885 isFirst = false; 1886 continue; 1887 } 1888 1889 Expr value = parseExpression(PREC_COMMA); 1890 1891 if (isFirst && lexer.peek() == ']') 1892 return block.newArray(value); 1893 1894 if (lexer.peek() != ',') { 1895 call.addCallParam(value); 1896 break; 1897 } 1898 1899 lexer.next(); 1900 1901 if (isFirst && lexer.peek() == ']') 1902 return block.newArray(value); 1903 1904 isFirst = false; 1905 call.addCallParam(value); 1906 } 1907 1908 return call; 1909 } 1910 1911 1914 private Expr getVar(ESId name) 1915 throws ESException 1916 { 1917 if (name == PACKAGES) 1918 return new PackageExpr(block); 1919 else if (name == JAVA) 1920 return new PackageExpr(block).fieldReference(JAVA); 1921 else if (name == CAUCHO) 1922 return new PackageExpr(block).fieldReference(COM).fieldReference(CAUCHO); 1923 else if (block.hasVar(name)) 1924 return block.newVar(name); 1925 else { 1926 for (int i = 0; i < importList.size(); i++) { 1927 String className = (String ) importList.get(i); 1928 1929 if (className.endsWith(".*")) 1930 className = className.substring(0, className.length() - 1) + name; 1931 1932 try { 1933 Class cl = CauchoSystem.loadClass(className, false, 1934 getClassLoader()); 1935 1936 return new JavaClassExpr(block, cl); 1937 } catch (Throwable e) { 1938 } 1939 } 1940 1941 return block.newVar(name); 1942 } 1943 } 1944 1945 1948 public String getFilename() 1949 { 1950 return lexer.getFilename(); 1951 } 1952 1953 1956 ESException error(String text) 1957 { 1958 return lexer.error(text); 1959 } 1960 1961 1964 private String getToken() 1965 { 1966 if (lexer.isEof()) 1967 return "end of file"; 1968 else 1969 return "`" + lexer.getToken() + "'"; 1970 } 1971 1972 1975 private ESException expect(String expect) 1976 { 1977 try { 1978 return lexer.error(L.l("expected {0} at {1}", expect, getToken())); 1979 } catch (Exception e) { 1980 e.printStackTrace(); 1981 return null; 1982 } 1983 } 1984} 1985 | Popular Tags |