[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}
This commit is contained in:
parent
811caee0e0
commit
1aae3a1c89
@ -2653,23 +2653,6 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) {
|
||||
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: {
|
||||
Consume(Token::PERIOD);
|
||||
int pos = position();
|
||||
@ -2740,7 +2723,7 @@ typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParseMemberExpression(bool* ok) {
|
||||
// MemberExpression ::
|
||||
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
|
||||
// ('[' Expression ']' | '.' Identifier | Arguments)*
|
||||
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
||||
|
||||
// The '[' Expression ']' and '.' Identifier parts are parsed by
|
||||
// ParseMemberExpressionContinuation, and the Arguments part is parsed by the
|
||||
@ -2817,7 +2800,7 @@ typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
|
||||
bool* ok) {
|
||||
// Parses this part of MemberExpression:
|
||||
// ('[' Expression ']' | '.' Identifier)*
|
||||
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
|
||||
while (true) {
|
||||
switch (peek()) {
|
||||
case Token::LBRACK: {
|
||||
@ -2842,6 +2825,22 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
|
||||
}
|
||||
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:
|
||||
return expression;
|
||||
}
|
||||
|
@ -532,8 +532,11 @@ class Scanner {
|
||||
}
|
||||
|
||||
inline void StartRawLiteral() {
|
||||
raw_literal_buffer_.Reset();
|
||||
next_.raw_literal_chars = &raw_literal_buffer_;
|
||||
LiteralBuffer* free_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)) {
|
||||
@ -716,7 +719,8 @@ class Scanner {
|
||||
LiteralBuffer source_mapping_url_;
|
||||
|
||||
// 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 next_; // desc for next token (one token look-ahead)
|
||||
|
@ -423,10 +423,12 @@ var obj = {
|
||||
Object.defineProperty(Array.prototype, 0, {
|
||||
set: function() {
|
||||
assertUnreachable();
|
||||
}
|
||||
},
|
||||
configurable: true
|
||||
});
|
||||
function tag(){}
|
||||
tag`a${1}b`;
|
||||
delete Array.prototype[0];
|
||||
})();
|
||||
|
||||
|
||||
@ -518,3 +520,69 @@ var obj = {
|
||||
assertThrows("`${(function() { \"use strict\"; return \"\\07\"; })()}`",
|
||||
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);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user