Commit 1aae3a1c authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

[es6] support template literals after MemberExpression

BUG=v8:3958, 450942
LOG=N
R=arv@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#27159}
parent 811caee0
...@@ -2653,23 +2653,6 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) { ...@@ -2653,23 +2653,6 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) {
break; break;
} }
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
int pos;
if (scanner()->current_token() == Token::IDENTIFIER) {
pos = position();
} else {
pos = peek_position();
if (result->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
// If the tag function looks like an IIFE, set_parenthesized() to
// force eager compilation.
result->AsFunctionLiteral()->set_parenthesized();
}
}
result = ParseTemplateLiteral(result, pos, CHECK_OK);
break;
}
case Token::PERIOD: { case Token::PERIOD: {
Consume(Token::PERIOD); Consume(Token::PERIOD);
int pos = position(); int pos = position();
...@@ -2740,7 +2723,7 @@ typename ParserBase<Traits>::ExpressionT ...@@ -2740,7 +2723,7 @@ typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseMemberExpression(bool* ok) { ParserBase<Traits>::ParseMemberExpression(bool* ok) {
// MemberExpression :: // MemberExpression ::
// (PrimaryExpression | FunctionLiteral | ClassLiteral) // (PrimaryExpression | FunctionLiteral | ClassLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments)* // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
// The '[' Expression ']' and '.' Identifier parts are parsed by // The '[' Expression ']' and '.' Identifier parts are parsed by
// ParseMemberExpressionContinuation, and the Arguments part is parsed by the // ParseMemberExpressionContinuation, and the Arguments part is parsed by the
...@@ -2817,7 +2800,7 @@ typename ParserBase<Traits>::ExpressionT ...@@ -2817,7 +2800,7 @@ typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression, ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
bool* ok) { bool* ok) {
// Parses this part of MemberExpression: // Parses this part of MemberExpression:
// ('[' Expression ']' | '.' Identifier)* // ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
while (true) { while (true) {
switch (peek()) { switch (peek()) {
case Token::LBRACK: { case Token::LBRACK: {
...@@ -2842,6 +2825,22 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression, ...@@ -2842,6 +2825,22 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
} }
break; break;
} }
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
int pos;
if (scanner()->current_token() == Token::IDENTIFIER) {
pos = position();
} else {
pos = peek_position();
if (expression->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
// If the tag function looks like an IIFE, set_parenthesized() to
// force eager compilation.
expression->AsFunctionLiteral()->set_parenthesized();
}
}
expression = ParseTemplateLiteral(expression, pos, CHECK_OK);
break;
}
default: default:
return expression; return expression;
} }
......
...@@ -532,8 +532,11 @@ class Scanner { ...@@ -532,8 +532,11 @@ class Scanner {
} }
inline void StartRawLiteral() { inline void StartRawLiteral() {
raw_literal_buffer_.Reset(); LiteralBuffer* free_buffer =
next_.raw_literal_chars = &raw_literal_buffer_; (current_.raw_literal_chars == &raw_literal_buffer1_) ?
&raw_literal_buffer2_ : &raw_literal_buffer1_;
free_buffer->Reset();
next_.raw_literal_chars = free_buffer;
} }
INLINE(void AddLiteralChar(uc32 c)) { INLINE(void AddLiteralChar(uc32 c)) {
...@@ -716,7 +719,8 @@ class Scanner { ...@@ -716,7 +719,8 @@ class Scanner {
LiteralBuffer source_mapping_url_; LiteralBuffer source_mapping_url_;
// Buffer to store raw string values // Buffer to store raw string values
LiteralBuffer raw_literal_buffer_; LiteralBuffer raw_literal_buffer1_;
LiteralBuffer raw_literal_buffer2_;
TokenDesc current_; // desc for current token (as returned by Next()) TokenDesc current_; // desc for current token (as returned by Next())
TokenDesc next_; // desc for next token (one token look-ahead) TokenDesc next_; // desc for next token (one token look-ahead)
......
...@@ -423,10 +423,12 @@ var obj = { ...@@ -423,10 +423,12 @@ var obj = {
Object.defineProperty(Array.prototype, 0, { Object.defineProperty(Array.prototype, 0, {
set: function() { set: function() {
assertUnreachable(); assertUnreachable();
} },
configurable: true
}); });
function tag(){} function tag(){}
tag`a${1}b`; tag`a${1}b`;
delete Array.prototype[0];
})(); })();
...@@ -518,3 +520,69 @@ var obj = { ...@@ -518,3 +520,69 @@ var obj = {
assertThrows("`${(function() { \"use strict\"; return \"\\07\"; })()}`", assertThrows("`${(function() { \"use strict\"; return \"\\07\"; })()}`",
SyntaxError); SyntaxError);
})(); })();
var global = this;
(function testCallNew() {
"use strict";
var called = false;
var calledWith;
global.log = function(x) { called = true; calledWith = x; }
assertInstanceof(new Function`log("test")`, Object);
assertTrue(called);
assertSame("test", calledWith);
delete global.log;
})();
(function testCallNew2() {
"use strict";
var log = [];
function tag(x) {
log.push(x);
if (!(this instanceof tag)) {
return tag;
}
this.x = x === void 0 ? null : x;
return this;
}
// No arguments passed to constructor
var instance = new tag`x``y``z`;
assertInstanceof(instance, tag);
assertSame(tag.prototype, Object.getPrototypeOf(instance));
assertEquals({ x: null }, instance);
assertEquals([["x"], ["y"], ["z"], undefined], log);
// Arguments passed to constructor
log.length = 0;
instance = new tag`x2` `y2` `z2` (`test`);
assertInstanceof(instance, tag);
assertSame(tag.prototype, Object.getPrototypeOf(instance));
assertEquals({ x: "test" }, instance);
assertEquals([["x2"], ["y2"], ["z2"], "test"], log);
})();
(function testCallResultOfTagFn() {
"use strict";
var i = 0;
var raw = [];
function tag(cs) {
var args = Array.prototype.slice.call(arguments);
var text = String.raw.apply(null, args);
if (i++ < 2) {
raw.push("tag;" + text);
return tag;
}
raw.push("raw;" + text);
return text;
}
assertEquals("test3", tag`test1``test2``test3`);
assertEquals([
"tag;test1",
"tag;test2",
"raw;test3"
], raw);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment