 Chromium Code Reviews
 Chromium Code Reviews Issue 663683006:
  Implement ES6 Template Literals  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 663683006:
  Implement ES6 Template Literals  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| Index: src/preparser.h | 
| diff --git a/src/preparser.h b/src/preparser.h | 
| index 6724435722024481a92e84dabbb50bac2e394fa2..3e3b761c9e3d5feff26416cbebb39350835bf03d 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, | 
| @@ -1386,6 +1392,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) {} | 
| @@ -1756,6 +1776,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { | 
| // RegExpLiteral | 
| // ClassLiteral | 
| // '(' Expression ')' | 
| + // TemplateLiteral | 
| int pos = peek_position(); | 
| ExpressionT result = this->EmptyExpression(); | 
| @@ -1844,6 +1865,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); | 
| @@ -2467,6 +2494,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(); | 
| @@ -2814,6 +2858,83 @@ 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) { | 
| + ReportMessageAt(Scanner::Location(start, peek_position()), | 
| + "unterminated_template"); | 
| + *ok = false; | 
| + return Traits::EmptyExpression(); | 
| + } | 
| + | 
| + int pos = peek_position(); | 
| + ExpressionT expression = this->ParseExpression(false, CHECK_OK); | 
| + Traits::AddTemplateExpression(&ts, expression); | 
| + | 
| + if (peek() != Token::RBRACE) { | 
| + ReportMessageAt(Scanner::Location(pos, peek_position()), | 
| + "unterminated_template_expr"); | 
| + *ok = false; | 
| + return Traits::EmptyExpression(); | 
| + } | 
| + | 
| + // 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) { | 
| + ReportMessageAt(Scanner::Location(start, position()), | 
| + "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. | 
| 
rossberg
2014/11/14 12:28:07
Nit: put this alternative into a conditional inste
 | 
| + // 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) { |