summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/TokenStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/TokenStream.cpp')
-rw-r--r--js/src/frontend/TokenStream.cpp140
1 files changed, 83 insertions, 57 deletions
diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp
index 186b7a8ab..6a7934e8f 100644
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1918,55 +1918,6 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
bool
-TokenStream::matchBracedUnicode(bool* matched, uint32_t* cp)
-{
- int32_t c;
- if (!peekChar(&c))
- return false;
- if (c != '{') {
- *matched = false;
- return true;
- }
-
- consumeKnownChar('{');
-
- uint32_t start = userbuf.offset();
-
- bool first = true;
- uint32_t code = 0;
- do {
- int32_t c = getCharIgnoreEOL();
- if (c == EOF) {
- error(JSMSG_MALFORMED_ESCAPE, "Unicode");
- return false;
- }
- if (c == '}') {
- if (first) {
- error(JSMSG_MALFORMED_ESCAPE, "Unicode");
- return false;
- }
- break;
- }
-
- if (!JS7_ISHEX(c)) {
- error(JSMSG_MALFORMED_ESCAPE, "Unicode");
- return false;
- }
-
- code = (code << 4) | JS7_UNHEX(c);
- if (code > unicode::NonBMPMax) {
- errorAt(start, JSMSG_UNICODE_OVERFLOW, "escape sequence");
- return false;
- }
- first = false;
- } while (true);
-
- *matched = true;
- *cp = code;
- return true;
-}
-
-bool
TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
{
int c;
@@ -1988,6 +1939,10 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
}
if (c == '\\') {
+ // When parsing templates, we don't immediately report errors for
+ // invalid escapes; these are handled by the parser.
+ // In those cases we don't append to tokenbuf, since it won't be
+ // read.
switch (c = getChar()) {
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
@@ -2003,11 +1958,73 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
// Unicode character specification.
case 'u': {
- bool matched;
- uint32_t code;
- if (!matchBracedUnicode(&matched, &code))
+ uint32_t code = 0;
+
+ int32_t c2;
+ if (!peekChar(&c2))
return false;
- if (matched) {
+
+ uint32_t start = userbuf.offset() - 2;
+
+ if (c2 == '{') {
+ consumeKnownChar('{');
+
+ bool first = true;
+ bool valid = true;
+ do {
+ int32_t c = getCharIgnoreEOL();
+ if (c == EOF) {
+ if (parsingTemplate) {
+ setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
+ valid = false;
+ break;
+ }
+ reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
+ return false;
+ }
+ if (c == '}') {
+ if (first) {
+ if (parsingTemplate) {
+ setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
+ valid = false;
+ break;
+ }
+ reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
+ return false;
+ }
+ break;
+ }
+
+ if (!JS7_ISHEX(c)) {
+ if (parsingTemplate) {
+ // We put the character back so that we read
+ // it on the next pass, which matters if it
+ // was '`' or '\'.
+ ungetCharIgnoreEOL(c);
+ setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
+ valid = false;
+ break;
+ }
+ reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
+ return false;
+ }
+
+ code = (code << 4) | JS7_UNHEX(c);
+ if (code > unicode::NonBMPMax) {
+ if (parsingTemplate) {
+ setInvalidTemplateEscape(start + 3, InvalidEscapeType::UnicodeOverflow);
+ valid = false;
+ break;
+ }
+ reportInvalidEscapeError(start + 3, InvalidEscapeType::UnicodeOverflow);
+ return false;
+ }
+
+ first = false;
+ } while (true);
+
+ if (!valid)
+ continue;
MOZ_ASSERT(code <= unicode::NonBMPMax);
if (code < unicode::NonBMPMin) {
@@ -2030,7 +2047,11 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
c = (c << 4) + JS7_UNHEX(cp[3]);
skipChars(4);
} else {
- error(JSMSG_MALFORMED_ESCAPE, "Unicode");
+ if (parsingTemplate) {
+ setInvalidTemplateEscape(start, InvalidEscapeType::Unicode);
+ continue;
+ }
+ reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
return false;
}
break;
@@ -2043,7 +2064,12 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);
skipChars(2);
} else {
- error(JSMSG_MALFORMED_ESCAPE, "hexadecimal");
+ uint32_t start = userbuf.offset() - 2;
+ if (parsingTemplate) {
+ setInvalidTemplateEscape(start, InvalidEscapeType::Hexadecimal);
+ continue;
+ }
+ reportInvalidEscapeError(start, InvalidEscapeType::Hexadecimal);
return false;
}
break;
@@ -2060,8 +2086,8 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp)
// Strict mode code allows only \0, then a non-digit.
if (val != 0 || JS7_ISDEC(c)) {
if (parsingTemplate) {
- error(JSMSG_DEPRECATED_OCTAL);
- return false;
+ setInvalidTemplateEscape(userbuf.offset() - 2, InvalidEscapeType::Octal);
+ continue;
}
if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
return false;