Index: src/parsing/scanner.cc |
diff --git a/src/parsing/scanner.cc b/src/parsing/scanner.cc |
index 86aadcff9fae2e74e7e6d11172ab2aac91d4f62a..c1580bbeae7dd23d69d0e02c13b0090474cb1773 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,16 @@ 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>(); |
+ USE(success); |
+ DCHECK_EQ(!success, has_error()); |
+ // 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 +1145,7 @@ Token::Value Scanner::ScanTemplateSpan() { |
literal.Complete(); |
next_.location.end_pos = source_pos(); |
next_.token = result; |
+ |
return result; |
} |