Chromium Code Reviews| Index: src/parsing/scanner.cc |
| diff --git a/src/parsing/scanner.cc b/src/parsing/scanner.cc |
| index 86aadcff9fae2e74e7e6d11172ab2aac91d4f62a..974d0bb5673f9da71db8ec30581e41f4f522d4cb 100644 |
| --- a/src/parsing/scanner.cc |
| +++ b/src/parsing/scanner.cc |
| @@ -19,6 +19,46 @@ |
| namespace v8 { |
| namespace internal { |
| +// Scoped helper for saving & restoring scanner error state. |
| +// This is used for tagged template literals, in which normally forbidden |
| +// escape sequences are allowed. |
| +class ErrorState { |
| + public: |
| + ErrorState(MessageTemplate::Template* message_stack, |
| + Scanner::Location* location_stack) |
| + : message_stack_(message_stack), |
| + old_message_(*message_stack), |
| + location_stack_(location_stack), |
| + old_location_(*location_stack) { |
| + *message_stack_ = MessageTemplate::kNone; |
| + *location_stack_ = Scanner::Location::invalid(); |
| + } |
| + |
| + ~ErrorState() { |
| + *message_stack_ = old_message_; |
| + *location_stack_ = old_location_; |
| + } |
| + |
| + void MoveErrorTo(MessageTemplate::Template* message_dest, |
| + Scanner::Location* location_dest) { |
| + if (*message_stack_ == MessageTemplate::kNone) { |
| + return; |
| + } |
| + if (*message_dest == MessageTemplate::kNone) { |
| + *message_dest = *message_stack_; |
| + *location_dest = *location_stack_; |
| + } |
| + *message_stack_ = MessageTemplate::kNone; |
| + *location_stack_ = Scanner::Location::invalid(); |
| + } |
| + |
| + private: |
| + MessageTemplate::Template* const message_stack_; |
| + MessageTemplate::Template const old_message_; |
| + Scanner::Location* const location_stack_; |
| + Scanner::Location const old_location_; |
| +}; |
| + |
| Handle<String> Scanner::LiteralBuffer::Internalize(Isolate* isolate) const { |
| if (is_one_byte()) { |
| return isolate->factory()->InternalizeOneByteString(one_byte_literal()); |
| @@ -948,16 +988,12 @@ bool Scanner::ScanEscape() { |
| break; |
| } |
| - // According to ECMA-262, section 7.8.4, characters not covered by the |
| - // above cases should be illegal, but they are commonly handled as |
| - // non-escaped characters by JS VMs. |
| + // Other escaped characters are interpreted as their non-escaped version. |
| AddLiteralChar(c); |
| return true; |
| } |
| -// Octal escapes of the forms '\0xx' and '\xxx' are not a part of |
| -// ECMA-262. Other JS VMs support them. |
| template <bool capture_raw> |
| uc32 Scanner::ScanOctalEscape(uc32 c, int length) { |
| uc32 x = c - '0'; |
| @@ -1039,6 +1075,12 @@ Token::Value Scanner::ScanTemplateSpan() { |
| // TEMPLATE_TAIL terminates a TemplateLiteral and does not need to be |
| // followed by an Expression. |
| + // These scoped helpers save and restore the original error state, so that we |
| + // can specially treat invalid escape sequences in templates (which are |
| + // handled by the parser). |
| + ErrorState scanner_error_state(&scanner_error_, &scanner_error_location_); |
| + ErrorState octal_error_state(&octal_message_, &octal_pos_); |
| + |
| Token::Value result = Token::TEMPLATE_SPAN; |
| LiteralScope literal(this); |
| StartRawLiteral(); |
| @@ -1069,8 +1111,15 @@ Token::Value Scanner::ScanTemplateSpan() { |
| AddRawLiteralChar('\n'); |
| } |
| } |
| - } else if (!ScanEscape<capture_raw, in_template_literal>()) { |
| - return Token::ILLEGAL; |
| + } else { |
| + bool success = ScanEscape<capture_raw, in_template_literal>(); |
| + DCHECK_EQ(!success, has_error()); |
|
adamk
2017/02/22 20:45:36
You could add
USE(success);
to avoid the failure
bakkot1
2017/02/22 20:56:44
Ah, thanks. Once more with feeling...
|
| + // For templates, invalid escape sequence checking is handled in the |
| + // parser. |
| + scanner_error_state.MoveErrorTo(&invalid_template_escape_message_, |
| + &invalid_template_escape_location_); |
| + octal_error_state.MoveErrorTo(&invalid_template_escape_message_, |
| + &invalid_template_escape_location_); |
| } |
| } else if (c < 0) { |
| // Unterminated template literal |
| @@ -1095,6 +1144,7 @@ Token::Value Scanner::ScanTemplateSpan() { |
| literal.Complete(); |
| next_.location.end_pos = source_pos(); |
| next_.token = result; |
| + |
| return result; |
| } |