Chromium Code Reviews| Index: src/preparser.h |
| diff --git a/src/preparser.h b/src/preparser.h |
| index ddf9cecc66a9b9c80c61a235ae0c3a421e5d5e78..15859fffdf363a274f0fd1f5ee77f00dbc18df1e 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,9 @@ 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 AddTemplateSpan(); |
| + 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, |
| @@ -1379,6 +1386,27 @@ class PreParserTraits { |
| return 0; |
| } |
| + struct TemplateLiteralState {}; |
| + |
| + TemplateLiteralState OpenTemplateLiteral(int pos) { |
| + return TemplateLiteralState(); |
| + } |
| + void AddTemplateSpan(TemplateLiteralState* state) { USE(state); } |
| + void AddTemplateExpression(TemplateLiteralState* state, |
| + PreParserExpression expression) { |
| + USE(state); |
| + USE(expression); |
| + } |
| + PreParserExpression CloseTemplateLiteral(TemplateLiteralState* state, |
| + int start, PreParserExpression tag) { |
| + USE(state); |
| + USE(start); |
| + USE(tag); |
| + return EmptyExpression(); |
| + } |
| + PreParserExpression NoTemplateTag() { |
| + return PreParserExpression::Default(); |
| + } |
| static AstValueFactory* ast_value_factory() { return NULL; } |
| void CheckConflictingVarDeclarations(PreParserScope scope, bool* ok) {} |
| @@ -1749,6 +1777,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
| // RegExpLiteral |
| // ClassLiteral |
| // '(' Expression ')' |
| + // TemplateLiteral |
| int pos = peek_position(); |
| ExpressionT result = this->EmptyExpression(); |
| @@ -1837,6 +1866,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); |
| @@ -2460,6 +2495,21 @@ 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) { |
| + result->AsFunctionLiteral()->set_parenthesized(); |
|
marja
2014/11/10 15:32:02
Why?
caitp (gmail)
2014/11/10 15:43:56
It's basically copy/pasted from the MemberExpressi
marja
2014/11/11 09:15:36
I dug up a bit where this is coming from. In any c
|
| + } |
| + } |
| + result = ParseTemplateLiteral(result, pos, CHECK_OK); |
| + break; |
| + } |
| + |
| case Token::PERIOD: { |
| Consume(Token::PERIOD); |
| int pos = position(); |
| @@ -2798,6 +2848,59 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseClassLiteral( |
| template <typename Traits> |
| typename ParserBase<Traits>::ExpressionT |
| +ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start, bool* ok) { |
|
marja
2014/11/10 15:32:02
Can you add here a comment about the parse rules w
|
| + CHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL); |
| + |
| + // Add TV / TRV |
| + if (peek() == Token::TEMPLATE_SPAN) { |
| + Consume(Token::TEMPLATE_SPAN); |
| + int pos = position(); |
| + typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos); |
| + Traits::AddTemplateSpan(&ts); |
| + |
| + for (;;) { |
| + Token::Value next = peek(); |
| + if (next < 0) { |
| + ReportMessage("unterminated_template"); |
| + *ok = false; |
| + return Traits::EmptyExpression(); |
| + } |
| + |
| + // Parse an Expression |
| + ExpressionT expression = this->ParseExpression(false, CHECK_OK); |
|
marja
2014/11/10 15:32:02
Why expression? Are we now inside the ${... or...
caitp (gmail)
2014/11/10 15:43:56
Yeah, if we get a TEMPLATE_SPAN token, then we jus
|
| + 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(); |
| + } |
| + |
| + CHECK(next == Token::TEMPLATE_SPAN || next == Token::TEMPLATE_TAIL); |
| + Traits::AddTemplateSpan(&ts); |
| + |
| + if (next == Token::TEMPLATE_TAIL) { |
| + break; |
| + } |
| + } |
| + return Traits::CloseTemplateLiteral(&ts, start, tag); |
| + } |
| + Consume(Token::TEMPLATE_TAIL); |
| + int pos = position(); |
| + typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos); |
| + Traits::AddTemplateSpan(&ts); |
| + 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) { |