# HG changeset patch # Parent 2411714cd0587e6af3c86929d01502fdd9515eef diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -744,48 +744,104 @@ TokenStream::reportAsmJSError(uint32_t o va_end(args); } // We have encountered a '\': check for a Unicode escape sequence after it. // Return 'true' and the character code value (by value) if we found a // Unicode escape sequence. Otherwise, return 'false'. In both cases, do not // advance along the buffer. bool -TokenStream::peekUnicodeEscape(int *result) +TokenStream::peekUnicodeEscape(jschar *first, jschar *second, size_t *skip) { - jschar cp[5]; + jschar start[2]; + if (!peekChars(2, start)) + return false; - if (peekChars(5, cp) && cp[0] == 'u' && - JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]) && - JS7_ISHEX(cp[3]) && JS7_ISHEX(cp[4])) - { - *result = (((((JS7_UNHEX(cp[1]) << 4) - + JS7_UNHEX(cp[2])) << 4) - + JS7_UNHEX(cp[3])) << 4) - + JS7_UNHEX(cp[4]); - return true; + if (start[0] != 'u') + return false; + + if (JS7_ISHEX(start[1])) { + jschar cp[5]; + if (peekChars(5, cp) && JS7_ISHEX(cp[2]) && + JS7_ISHEX(cp[3]) && JS7_ISHEX(cp[4])) + { + *skip = 5; + *first = (((((JS7_UNHEX(cp[1]) << 4) + + JS7_UNHEX(cp[2])) << 4) + + JS7_UNHEX(cp[3])) << 4) + + JS7_UNHEX(cp[4]); + *second = 0; + return true; + } + return false; + } + if (start[1] == '{') { + uint32_t value = 0; + bool valid = false; + + getCharIgnoreEOL(); + getCharIgnoreEOL(); + + int chars = 0; + for (;; chars++) { + uint32_t c = getCharIgnoreEOL(); + + if (JS7_ISHEX(c)) { + value = (value << 4) + JS7_UNHEX(c); + if (value > 0x10ffff) + break; + } else if (c == '}') { + if (chars > 0) + valid = true; + break; + } else { + break; + } + } + + if (value <= 0xffff) { + *first = value; + *second = 0; + } else { + *first = (value - 0x10000) / 0x400 + 0xD800; + *second = (value - 0x10000) % 0x400 + 0xDC00; + } + + for (int i = 0; i < chars + 2; i++) + userbuf.ungetRawChar(); + + *skip = chars + 2; + return valid; } return false; } bool TokenStream::matchUnicodeEscapeIdStart(int32_t *cp) { - if (peekUnicodeEscape(cp) && IsIdentifierStart(*cp)) { - skipChars(5); + jschar first; + jschar second; + size_t skip; + if (peekUnicodeEscape(&first, &second, &skip) && !second && IsIdentifierStart(first)) { + *cp = first; + skipChars(skip); return true; } return false; } bool TokenStream::matchUnicodeEscapeIdent(int32_t *cp) { - if (peekUnicodeEscape(cp) && IsIdentifierPart(*cp)) { - skipChars(5); + jschar first; + jschar second; + size_t skip; + if (peekUnicodeEscape(&first, &second, &skip) && !second && IsIdentifierPart(first)) { + *cp = first; + skipChars(skip); return true; } return false; } // Helper function which returns true if the first length(q) characters in p are // the same as the characters in q. static bool @@ -1280,29 +1336,35 @@ TokenStream::getTokenInternal(Modifier m getChar(); else val = save; } } c = jschar(val); } else if (c == 'u') { - jschar cp[4]; - if (peekChars(4, cp) && - JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) && - JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) { - c = (((((JS7_UNHEX(cp[0]) << 4) - + JS7_UNHEX(cp[1])) << 4) - + JS7_UNHEX(cp[2])) << 4) - + JS7_UNHEX(cp[3]); - skipChars(4); - } else { + ungetChar(c); + + jschar first; + jschar second; + size_t matched; + if (!peekUnicodeEscape(&first, &second, &matched)) { reportError(JSMSG_MALFORMED_ESCAPE, "Unicode"); goto error; } + + skipChars(matched); + + if (!second) { + c = first; + } else { + if (!tokenbuf.append(first)) + goto error; + c = second; + } } else if (c == 'x') { jschar cp[2]; if (peekChars(2, cp) && JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) { c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]); skipChars(2); } else { reportError(JSMSG_MALFORMED_ESCAPE, "hexadecimal"); diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -834,17 +834,17 @@ class MOZ_STACK_CLASS TokenStream TokenKind getTokenInternal(Modifier modifier); int32_t getChar(); int32_t getCharIgnoreEOL(); void ungetChar(int32_t c); void ungetCharIgnoreEOL(int32_t c); Token *newToken(ptrdiff_t adjust); - bool peekUnicodeEscape(int32_t *c); + bool peekUnicodeEscape(jschar *first, jschar *second, size_t *skip); bool matchUnicodeEscapeIdStart(int32_t *c); bool matchUnicodeEscapeIdent(int32_t *c); bool peekChars(int n, jschar *cp); bool getDirectives(bool isMultiline, bool shouldWarnDeprecated); bool getDirective(bool isMultiline, bool shouldWarnDeprecated, const char *directive, int directiveLength, const char *errorMsgPragma, jschar **destination);