diff --git a/src/org/mozilla/javascript/Parser.java b/src/org/mozilla/javascript/Parser.java index 63abac2118..898bd20e88 100644 --- a/src/org/mozilla/javascript/Parser.java +++ b/src/org/mozilla/javascript/Parser.java @@ -2617,18 +2617,18 @@ private AstNode propertyAccess(int tt, AstNode pn) case Token.THROW: // needed for generator.throw(); saveNameTokenData(ts.tokenBeg, "throw", ts.lineno); - ref = propertyName(-1, "throw", memberTypeFlags); + ref = propertyName(-1, memberTypeFlags); break; case Token.NAME: // handles: name, ns::name, ns::*, ns::[expr] - ref = propertyName(-1, ts.getString(), memberTypeFlags); + ref = propertyName(-1, memberTypeFlags); break; case Token.MUL: // handles: *, *::name, *::*, *::[expr] saveNameTokenData(ts.tokenBeg, "*", ts.lineno); - ref = propertyName(-1, "*", memberTypeFlags); + ref = propertyName(-1, memberTypeFlags); break; case Token.XMLATTR: @@ -2638,14 +2638,10 @@ private AstNode propertyAccess(int tt, AstNode pn) break; default: - if (compilerEnv.isReservedKeywordAsIdentifier()) { + if (convertToName(token)) { // allow keywords as property names, e.g. ({if: 1}) - String name = Token.keywordToName(token); - if (name != null) { - saveNameTokenData(ts.tokenBeg, name, ts.lineno); - ref = propertyName(-1, name, memberTypeFlags); - break; - } + ref = propertyName(-1, memberTypeFlags); + break; } reportError("msg.no.name.after.dot"); return makeErrorNode(); @@ -2680,12 +2676,12 @@ private AstNode attributeAccess() switch (tt) { // handles: @name, @ns::name, @ns::*, @ns::[expr] case Token.NAME: - return propertyName(atPos, ts.getString(), 0); + return propertyName(atPos, 0); // handles: @*, @*::name, @*::*, @*::[expr] case Token.MUL: saveNameTokenData(ts.tokenBeg, "*", ts.lineno); - return propertyName(atPos, "*", 0); + return propertyName(atPos, 0); // handles @[expr] case Token.LB: @@ -2712,7 +2708,7 @@ private AstNode attributeAccess() * returns a Name node. Returns an ErrorNode for malformed XML * expressions. (For now - might change to return a partial XmlRef.) */ - private AstNode propertyName(int atPos, String s, int memberTypeFlags) + private AstNode propertyName(int atPos, int memberTypeFlags) throws IOException { int pos = atPos != -1 ? atPos : ts.tokenBeg, lineno = ts.lineno; @@ -2916,7 +2912,7 @@ private AstNode name(int ttFlagged, int tt) throws IOException { saveNameTokenData(namePos, nameString, nameLineno); if (compilerEnv.isXmlAvailable()) { - return propertyName(-1, nameString, 0); + return propertyName(-1, 0); } else { return createNameNode(true, Token.NAME); } @@ -3432,12 +3428,14 @@ private void saveNameTokenData(int pos, String name, int lineno) { // Check whether token is a reserved keyword that is allowed as property id. private boolean convertToName(int token) { - if (compilerEnv.isReservedKeywordAsIdentifier()) { - String conv = Token.keywordToName(token); - if (conv != null) { - saveNameTokenData(ts.tokenBeg, conv, ts.lineno); - return true; - } + if (token == Token.RESERVED) { + saveNameTokenData(ts.tokenBeg, ts.getString(), ts.lineno); + return true; + } + String conv = Token.keywordToName(token); + if (conv != null) { + saveNameTokenData(ts.tokenBeg, conv, ts.lineno); + return true; } return false; } diff --git a/src/org/mozilla/javascript/TokenStream.java b/src/org/mozilla/javascript/TokenStream.java index 101fbe786c..7d0b58af46 100644 --- a/src/org/mozilla/javascript/TokenStream.java +++ b/src/org/mozilla/javascript/TokenStream.java @@ -123,73 +123,59 @@ private static int stringToKeyword(String name) // #string_id_map# // The following assumes that Token.EOF == 0 final int + // NullLiteral, BooleanLiteral + Id_null = Token.NULL, + Id_false = Token.FALSE, + Id_true = Token.TRUE, + // Keyword Id_break = Token.BREAK, Id_case = Token.CASE, + Id_catch = Token.CATCH, Id_continue = Token.CONTINUE, + Id_debugger = Token.DEBUGGER, Id_default = Token.DEFAULT, Id_delete = Token.DELPROP, Id_do = Token.DO, Id_else = Token.ELSE, - Id_export = Token.RESERVED, - Id_false = Token.FALSE, + Id_finally = Token.FINALLY, Id_for = Token.FOR, Id_function = Token.FUNCTION, Id_if = Token.IF, Id_in = Token.IN, - Id_let = Token.LET, + Id_instanceof = Token.INSTANCEOF, Id_new = Token.NEW, - Id_null = Token.NULL, Id_return = Token.RETURN, Id_switch = Token.SWITCH, Id_this = Token.THIS, - Id_true = Token.TRUE, + Id_throw = Token.THROW, + Id_try = Token.TRY, Id_typeof = Token.TYPEOF, Id_var = Token.VAR, Id_void = Token.VOID, Id_while = Token.WHILE, Id_with = Token.WITH, - Id_yield = Token.YIELD, - - // the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c - Id_abstract = Token.RESERVED, - Id_boolean = Token.RESERVED, - Id_byte = Token.RESERVED, - Id_catch = Token.CATCH, - Id_char = Token.RESERVED, + // FutureReservedWord Id_class = Token.RESERVED, Id_const = Token.CONST, - Id_debugger = Token.DEBUGGER, - Id_double = Token.RESERVED, Id_enum = Token.RESERVED, + Id_export = Token.RESERVED, Id_extends = Token.RESERVED, - Id_final = Token.RESERVED, - Id_finally = Token.FINALLY, - Id_float = Token.RESERVED, - Id_goto = Token.RESERVED, - Id_implements = Token.RESERVED, Id_import = Token.RESERVED, - Id_instanceof = Token.INSTANCEOF, - Id_int = Token.RESERVED, + Id_super = Token.RESERVED, + // FutureReservedWord (strict-mode) + Id_implements = Token.RESERVED, Id_interface = Token.RESERVED, - Id_long = Token.RESERVED, - Id_native = Token.RESERVED, + Id_let = Token.LET, Id_package = Token.RESERVED, Id_private = Token.RESERVED, Id_protected = Token.RESERVED, Id_public = Token.RESERVED, - Id_short = Token.RESERVED, Id_static = Token.RESERVED, - Id_super = Token.RESERVED, - Id_synchronized = Token.RESERVED, - Id_throw = Token.THROW, - Id_throws = Token.RESERVED, - Id_transient = Token.RESERVED, - Id_try = Token.TRY, - Id_volatile = Token.RESERVED; + Id_yield = Token.YIELD; int id; String s = name; -// #generated# Last update: 2007-04-18 13:53:30 PDT +// #generated# Last update: 2012-02-20 23:50:10 MEZ L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 2: c=s.charAt(1); @@ -199,31 +185,20 @@ private static int stringToKeyword(String name) break L; case 3: switch (s.charAt(0)) { case 'f': if (s.charAt(2)=='r' && s.charAt(1)=='o') {id=Id_for; break L0;} break L; - case 'i': if (s.charAt(2)=='t' && s.charAt(1)=='n') {id=Id_int; break L0;} break L; case 'l': if (s.charAt(2)=='t' && s.charAt(1)=='e') {id=Id_let; break L0;} break L; case 'n': if (s.charAt(2)=='w' && s.charAt(1)=='e') {id=Id_new; break L0;} break L; case 't': if (s.charAt(2)=='y' && s.charAt(1)=='r') {id=Id_try; break L0;} break L; case 'v': if (s.charAt(2)=='r' && s.charAt(1)=='a') {id=Id_var; break L0;} break L; } break L; - case 4: switch (s.charAt(0)) { - case 'b': X="byte";id=Id_byte; break L; - case 'c': c=s.charAt(3); - if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='a') {id=Id_case; break L0;} } - else if (c=='r') { if (s.charAt(2)=='a' && s.charAt(1)=='h') {id=Id_char; break L0;} } - break L; - case 'e': c=s.charAt(3); - if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='l') {id=Id_else; break L0;} } - else if (c=='m') { if (s.charAt(2)=='u' && s.charAt(1)=='n') {id=Id_enum; break L0;} } - break L; - case 'g': X="goto";id=Id_goto; break L; - case 'l': X="long";id=Id_long; break L; - case 'n': X="null";id=Id_null; break L; - case 't': c=s.charAt(3); - if (c=='e') { if (s.charAt(2)=='u' && s.charAt(1)=='r') {id=Id_true; break L0;} } - else if (c=='s') { if (s.charAt(2)=='i' && s.charAt(1)=='h') {id=Id_this; break L0;} } - break L; - case 'v': X="void";id=Id_void; break L; - case 'w': X="with";id=Id_with; break L; + case 4: switch (s.charAt(1)) { + case 'a': X="case";id=Id_case; break L; + case 'h': X="this";id=Id_this; break L; + case 'i': X="with";id=Id_with; break L; + case 'l': X="else";id=Id_else; break L; + case 'n': X="enum";id=Id_enum; break L; + case 'o': X="void";id=Id_void; break L; + case 'r': X="true";id=Id_true; break L; + case 'u': X="null";id=Id_null; break L; } break L; case 5: switch (s.charAt(2)) { case 'a': X="class";id=Id_class; break L; @@ -233,60 +208,46 @@ private static int stringToKeyword(String name) break L; case 'i': X="while";id=Id_while; break L; case 'l': X="false";id=Id_false; break L; - case 'n': c=s.charAt(0); - if (c=='c') { X="const";id=Id_const; } - else if (c=='f') { X="final";id=Id_final; } - break L; - case 'o': c=s.charAt(0); - if (c=='f') { X="float";id=Id_float; } - else if (c=='s') { X="short";id=Id_short; } - break L; + case 'n': X="const";id=Id_const; break L; case 'p': X="super";id=Id_super; break L; case 'r': X="throw";id=Id_throw; break L; case 't': X="catch";id=Id_catch; break L; } break L; - case 6: switch (s.charAt(1)) { - case 'a': X="native";id=Id_native; break L; - case 'e': c=s.charAt(0); - if (c=='d') { X="delete";id=Id_delete; } - else if (c=='r') { X="return";id=Id_return; } + case 6: switch (s.charAt(0)) { + case 'd': X="delete";id=Id_delete; break L; + case 'e': X="export";id=Id_export; break L; + case 'i': X="import";id=Id_import; break L; + case 'p': X="public";id=Id_public; break L; + case 'r': X="return";id=Id_return; break L; + case 's': c=s.charAt(5); + if (c=='c') { X="static";id=Id_static; } + else if (c=='h') { X="switch";id=Id_switch; } break L; - case 'h': X="throws";id=Id_throws; break L; - case 'm': X="import";id=Id_import; break L; - case 'o': X="double";id=Id_double; break L; - case 't': X="static";id=Id_static; break L; - case 'u': X="public";id=Id_public; break L; - case 'w': X="switch";id=Id_switch; break L; - case 'x': X="export";id=Id_export; break L; - case 'y': X="typeof";id=Id_typeof; break L; + case 't': X="typeof";id=Id_typeof; break L; } break L; case 7: switch (s.charAt(1)) { case 'a': X="package";id=Id_package; break L; case 'e': X="default";id=Id_default; break L; case 'i': X="finally";id=Id_finally; break L; - case 'o': X="boolean";id=Id_boolean; break L; case 'r': X="private";id=Id_private; break L; case 'x': X="extends";id=Id_extends; break L; } break L; - case 8: switch (s.charAt(0)) { - case 'a': X="abstract";id=Id_abstract; break L; - case 'c': X="continue";id=Id_continue; break L; - case 'd': X="debugger";id=Id_debugger; break L; - case 'f': X="function";id=Id_function; break L; - case 'v': X="volatile";id=Id_volatile; break L; - } break L; + case 8: c=s.charAt(0); + if (c=='c') { X="continue";id=Id_continue; } + else if (c=='d') { X="debugger";id=Id_debugger; } + else if (c=='f') { X="function";id=Id_function; } + break L; case 9: c=s.charAt(0); if (c=='i') { X="interface";id=Id_interface; } else if (c=='p') { X="protected";id=Id_protected; } - else if (c=='t') { X="transient";id=Id_transient; } break L; case 10: c=s.charAt(1); if (c=='m') { X="implements";id=Id_implements; } else if (c=='n') { X="instanceof";id=Id_instanceof; } break L; - case 12: X="synchronized";id=Id_synchronized; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; + break L0; } // #/generated# // #/string_id_map# @@ -365,6 +326,7 @@ final int getToken() throws IOException } if (identifierStart) { + boolean checkIdentifierStart = isUnicodeEscapeStart; boolean containsEscape = isUnicodeEscapeStart; for (;;) { if (isUnicodeEscapeStart) { @@ -385,6 +347,18 @@ final int getToken() throws IOException parser.addError("msg.invalid.escape"); return Token.ERROR; } + if (checkIdentifierStart) { + checkIdentifierStart = false; + if (! Character.isJavaIdentifierStart((char)escapeVal)) { + parser.addError("msg.invalid.escape"); + return Token.ERROR; + } + } else { + if (! Character.isJavaIdentifierPart((char)escapeVal)) { + parser.addError("msg.invalid.escape"); + return Token.ERROR; + } + } addToString(escapeVal); isUnicodeEscapeStart = false; } else { @@ -431,6 +405,7 @@ final int getToken() throws IOException } else if (!parser.compilerEnv. isReservedKeywordAsIdentifier()) { + this.string = (String)allStrings.intern(str); return result; } } @@ -459,10 +434,14 @@ final int getToken() throws IOException } if (base == 16) { - while (0 <= Kit.xDigitToInt(c, 0)) { + if (0 > Kit.xDigitToInt(c, 0)) { + parser.addError("msg.caught.nfe"); + return Token.ERROR; + } + do { addToString(c); c = getChar(); - } + } while (0 <= Kit.xDigitToInt(c, 0)); } else { while ('0' <= c && c <= '9') { /* @@ -566,41 +545,31 @@ final int getToken() throws IOException case 'v': c = 0xb; break; case 'u': - // Get 4 hex digits; if the u escape is not - // followed by 4 hex digits, use 'u' + the - // literal character sequence that follows. - int escapeStart = stringBufferTop; - addToString('u'); + // Get 4 hex digits escapeVal = 0; for (int i = 0; i != 4; ++i) { c = getChar(); escapeVal = Kit.xDigitToInt(c, escapeVal); if (escapeVal < 0) { - continue strLoop; + parser.addError("msg.unterminated.string.lit"); + return Token.ERROR; } - addToString(c); } - // prepare for replace of stored 'u' sequence - // by escape value - stringBufferTop = escapeStart; c = escapeVal; break; case 'x': - // Get 2 hex digits, defaulting to 'x'+literal - // sequence, as above. + // Get 2 hex digits c = getChar(); escapeVal = Kit.xDigitToInt(c, 0); if (escapeVal < 0) { - addToString('x'); - continue strLoop; + parser.addError("msg.unterminated.string.lit"); + return Token.ERROR; } else { - int c1 = c; c = getChar(); escapeVal = Kit.xDigitToInt(c, escapeVal); if (escapeVal < 0) { - addToString('x'); - addToString(c1); - continue strLoop; + parser.addError("msg.unterminated.string.lit"); + return Token.ERROR; } else { // got 2 hex digits c = escapeVal; @@ -893,11 +862,6 @@ static boolean isJSSpace(int c) } } - private static boolean isJSFormatChar(int c) - { - return c > 127 && Character.getType((char)c) == Character.FORMAT; - } - /** * Parser calls the method when it gets / or /= in literal context. */ @@ -911,6 +875,12 @@ void readRegExp(int startToken) addToString('='); } else { if (startToken != Token.DIV) Kit.codeBug(); + if (peekChar() == '*') { + tokenEnd = cursor - 1; + this.string = new String(stringBuffer, 0, stringBufferTop); + parser.reportError("msg.unterminated.re.lit"); + return; + } } boolean inCharSet = false; // true if inside a '['..']' pair @@ -926,6 +896,13 @@ void readRegExp(int startToken) if (c == '\\') { addToString(c); c = getChar(); + if (c == '\n' || c == EOF_CHAR) { + ungetChar(c); + tokenEnd = cursor - 1; + this.string = new String(stringBuffer, 0, stringBufferTop); + parser.reportError("msg.unterminated.re.lit"); + return; + } } else if (c == '[') { inCharSet = true; } else if (c == ']') { @@ -1341,9 +1318,6 @@ private int getChar() throws IOException } } else { if (c == BYTE_ORDER_MARK) return c; // BOM is considered whitespace - if (isJSFormatChar(c)) { - continue; - } if (ScriptRuntime.isJSLineTerminator(c)) { lineEndChar = c; c = '\n'; @@ -1387,9 +1361,6 @@ private int getCharIgnoreLineEnd() throws IOException } } else { if (c == BYTE_ORDER_MARK) return c; // BOM is considered whitespace - if (isJSFormatChar(c)) { - continue; - } if (ScriptRuntime.isJSLineTerminator(c)) { lineEndChar = c; c = '\n';