ES6 template literals: Fix issue with template after rbrace
authorarv <arv@chromium.org>
Thu, 4 Dec 2014 14:50:09 +0000 (06:50 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 4 Dec 2014 14:50:17 +0000 (14:50 +0000)
If we hade }` the right brace was always treated as part of the
template literal. We should only treat the right brace as part of
the literal when we continue to parse the template literal after a
placeholder.

BUG=v8:3734
LOG=Y

Review URL: https://codereview.chromium.org/778813003

Cr-Commit-Position: refs/heads/master@{#25661}

src/preparser.h
src/scanner.cc
src/scanner.h
test/mjsunit/harmony/templates.js

index cef5b9473485d715439db147c147dc89531b8eac..b378f47f6576f2739bd9bcad36da634dcff9c752 100644 (file)
@@ -2851,7 +2851,7 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) {
 
     // If we didn't die parsing that expression, our next token should be a
     // TEMPLATE_SPAN or TEMPLATE_TAIL.
-    next = scanner()->ScanTemplateSpan();
+    next = scanner()->ScanTemplateContinuation();
     Next();
 
     if (!next) {
index c533e5754cbc784e8994c338c6e8ef833f52e88d..561c30b58a12e0cb2c5e54d16bfc2e1572c9cd3e 100644 (file)
@@ -647,7 +647,7 @@ void Scanner::Scan() {
 
       case '`':
         if (HarmonyTemplates()) {
-          token = ScanTemplateSpan();
+          token = ScanTemplateStart();
           break;
         }
 
@@ -808,19 +808,8 @@ Token::Value Scanner::ScanTemplateSpan() {
   // A TEMPLATE_SPAN should always be followed by an Expression, while a
   // TEMPLATE_TAIL terminates a TemplateLiteral and does not need to be
   // followed by an Expression.
-  //
-
-  if (next_.token == Token::RBRACE) {
-    // After parsing an Expression, the source position is incorrect due to
-    // having scanned the brace. Push the RBRACE back into the stream.
-    PushBack('}');
-  }
 
-  next_.location.beg_pos = source_pos();
   Token::Value result = Token::TEMPLATE_SPAN;
-  DCHECK(c0_ == '`' || c0_ == '}');
-  Advance();  // Consume ` or }
-
   LiteralScope literal(this, true);
 
   while (true) {
@@ -881,6 +870,21 @@ Token::Value Scanner::ScanTemplateSpan() {
 }
 
 
+Token::Value Scanner::ScanTemplateStart() {
+  DCHECK(c0_ == '`');
+  next_.location.beg_pos = source_pos();
+  Advance();  // Consume `
+  return ScanTemplateSpan();
+}
+
+
+Token::Value Scanner::ScanTemplateContinuation() {
+  DCHECK_EQ(next_.token, Token::RBRACE);
+  next_.location.beg_pos = source_pos() - 1;  // We already consumed }
+  return ScanTemplateSpan();
+}
+
+
 void Scanner::ScanDecimalDigits() {
   while (IsDecimalDigit(c0_))
     AddLiteralCharAdvance();
index 590f3a88e4d6f4ec0361f6d2169eacdd978daf1d..87ff20b753a0f4314dc0553d2ea3ac7847789811 100644 (file)
@@ -484,7 +484,8 @@ class Scanner {
   bool ScanRegExpFlags();
 
   // Scans the input as a template literal
-  Token::Value ScanTemplateSpan();
+  Token::Value ScanTemplateStart();
+  Token::Value ScanTemplateContinuation();
 
   const LiteralBuffer* source_url() const { return &source_url_; }
   const LiteralBuffer* source_mapping_url() const {
@@ -692,6 +693,8 @@ class Scanner {
   // Helper for the above functions.
   uc32 ScanUnicodeEscape();
 
+  Token::Value ScanTemplateSpan();
+
   // Return the current source position.
   int source_pos() {
     return source_->pos() - kCharacterLookaheadBufferSize;
index 13d514610c043c3db91b1a07268cf3f001fb1a59..86caf453a5c998f7cb6f9cabdde145aba400ad2d 100644 (file)
@@ -453,3 +453,21 @@ var obj = {
   assertEquals(`a\u{62}c`, "abc");
   assertEquals(`a\u{000062}c`, "abc");
 })();
+
+
+(function testLiteralAfterRightBrace() {
+  // Regression test for https://code.google.com/p/v8/issues/detail?id=3734
+  function f() {}
+  `abc`;
+
+  function g() {}`def`;
+
+  {
+    // block
+  }
+  `ghi`;
+
+  {
+    // block
+  }`jkl`;
+})();