Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index 7c9791fc9ca25223983afbfee8f4f666c709af24..96b7b985fc19bcaa53111580bc3ef84524d58f62 100644 |
--- a/src/preparser.h |
+++ b/src/preparser.h |
@@ -102,6 +102,7 @@ class ParserBase : public Traits { |
bool allow_harmony_object_literals() const { |
return allow_harmony_object_literals_; |
} |
+ bool allow_harmony_templates() const { return scanner()->HarmonyTemplates(); } |
// Setters that determine whether certain syntactical constructs are |
// allowed to be parsed by this instance of the parser. |
@@ -119,6 +120,9 @@ class ParserBase : public Traits { |
void set_allow_harmony_object_literals(bool allow) { |
allow_harmony_object_literals_ = allow; |
} |
+ void set_allow_harmony_templates(bool allow) { |
+ scanner()->SetHarmonyTemplates(allow); |
+ } |
protected: |
enum AllowEvalOrArgumentsAsIdentifier { |
@@ -494,6 +498,8 @@ class ParserBase : public Traits { |
Scanner::Location function_name_location, |
bool name_is_strict_reserved, int pos, |
bool* ok); |
+ ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok); |
+ void AddTemplateExpression(ExpressionT); |
// Checks if the expression is a valid reference expression (e.g., on the |
// left-hand side of assignments). Although ruled out by ECMA as early errors, |
@@ -1385,6 +1391,20 @@ class PreParserTraits { |
return 0; |
} |
+ struct TemplateLiteralState {}; |
+ |
+ TemplateLiteralState OpenTemplateLiteral(int pos) { |
+ return TemplateLiteralState(); |
+ } |
+ void AddTemplateSpan(TemplateLiteralState*, bool) {} |
+ void AddTemplateExpression(TemplateLiteralState*, PreParserExpression) {} |
+ PreParserExpression CloseTemplateLiteral(TemplateLiteralState*, int, |
+ PreParserExpression) { |
+ return EmptyExpression(); |
+ } |
+ PreParserExpression NoTemplateTag() { |
+ return PreParserExpression::Default(); |
+ } |
static AstValueFactory* ast_value_factory() { return NULL; } |
void CheckConflictingVarDeclarations(PreParserScope scope, bool* ok) {} |
@@ -1755,6 +1775,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
// RegExpLiteral |
// ClassLiteral |
// '(' Expression ')' |
+ // TemplateLiteral |
int pos = peek_position(); |
ExpressionT result = this->EmptyExpression(); |
@@ -1843,6 +1864,12 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
break; |
} |
+ case Token::TEMPLATE_SPAN: |
+ case Token::TEMPLATE_TAIL: |
+ result = this->ParseTemplateLiteral(Traits::NoTemplateTag(), pos, |
+ CHECK_OK); |
+ break; |
+ |
case Token::MOD: |
if (allow_natives_syntax() || extension_ != NULL) { |
result = this->ParseV8Intrinsic(CHECK_OK); |
@@ -2466,6 +2493,23 @@ 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(); |
@@ -2811,6 +2855,72 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseClassLiteral( |
template <typename Traits> |
typename ParserBase<Traits>::ExpressionT |
+ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) { |
+ // A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal |
+ // text followed by a substitution expression), finalized by a single |
+ // TEMPLATE_TAIL. |
+ // |
+ // In terms of draft language, TEMPLATE_SPAN may be either the TemplateHead or |
+ // TemplateMiddle productions, while TEMPLATE_TAIL is either TemplateTail, or |
+ // NoSubstitutionTemplate. |
+ // |
+ // When parsing a TemplateLiteral, we must have scanned either an initial |
+ // TEMPLATE_SPAN, or a TEMPLATE_TAIL. |
+ CHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL); |
+ |
+ if (peek() == Token::TEMPLATE_SPAN) { |
+ Consume(Token::TEMPLATE_SPAN); |
+ int pos = position(); |
+ typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos); |
+ Traits::AddTemplateSpan(&ts, false); |
+ Token::Value next; |
+ |
+ // If we open with a TEMPLATE_SPAN, we must scan the subsequent expression, |
+ // and repeat if the following token is a TEMPLATE_SPAN as well (in this |
+ // case, representing a TemplateMiddle). |
+ do { |
+ next = peek(); |
+ if (next <= 0) { |
+ ReportMessage("unterminated_template"); |
+ *ok = false; |
+ return Traits::EmptyExpression(); |
+ } |
+ |
+ ExpressionT expression = this->ParseExpression(false, CHECK_OK); |
+ Traits::AddTemplateExpression(&ts, expression); |
+ |
+ // If we didn't die parsing that expression, our next token should be a |
+ // TEMPLATE_SPAN or TEMPLATE_TAIL. |
+ next = scanner()->ScanTemplateSpan(); |
+ Next(); |
+ |
+ if (next == Token::ILLEGAL || next <= 0) { |
+ ReportMessage("unterminated_template"); |
+ *ok = false; |
+ return Traits::EmptyExpression(); |
+ } |
+ |
+ Traits::AddTemplateSpan(&ts, next == Token::TEMPLATE_TAIL); |
+ } while (next == Token::TEMPLATE_SPAN); |
+ |
+ DCHECK_EQ(next, Token::TEMPLATE_TAIL); |
+ // Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral. |
+ return Traits::CloseTemplateLiteral(&ts, start, tag); |
+ } |
+ |
+ // If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate. |
+ // In this case we may simply consume the token and build a template with a |
+ // single TEMPLATE_SPAN and no expressions. |
+ Consume(Token::TEMPLATE_TAIL); |
+ int pos = position(); |
+ typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos); |
+ Traits::AddTemplateSpan(&ts, true); |
+ return Traits::CloseTemplateLiteral(&ts, start, tag); |
+} |
+ |
+ |
+template <typename Traits> |
+typename ParserBase<Traits>::ExpressionT |
ParserBase<Traits>::CheckAndRewriteReferenceExpression( |
ExpressionT expression, |
Scanner::Location location, const char* message, bool* ok) { |