Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index 53d18fb3e9b9304d1def1dfcd04806924f298231..ed63b543b46cae98d24debebc9334fcfa1f6f6ec 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -330,6 +330,10 @@ bool ParserTraits::IsUndefined(const AstRawString* identifier) const { |
| return identifier == parser_->ast_value_factory()->undefined_string(); |
| } |
| +bool ParserTraits::IsAwait(const AstRawString* identifier) const { |
| + return identifier == parser_->ast_value_factory()->await_string(); |
| +} |
| + |
| bool ParserTraits::IsPrototype(const AstRawString* identifier) const { |
| return identifier == parser_->ast_value_factory()->prototype_string(); |
| } |
| @@ -791,6 +795,7 @@ Parser::Parser(ParseInfo* info) |
| FLAG_harmony_restrictive_declarations); |
| set_allow_harmony_exponentiation_operator( |
| FLAG_harmony_exponentiation_operator); |
| + set_allow_harmony_async_await(FLAG_harmony_async_await); |
| for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; |
| ++feature) { |
| use_counts_[feature] = 0; |
| @@ -1065,6 +1070,16 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, |
| bool ok = true; |
| if (shared_info->is_arrow()) { |
| + bool is_async = allow_harmony_async_await() && |
| + peek() == Token::IDENTIFIER && |
| + PeekContextualKeyword(CStrVector("async")) && |
| + !scanner()->HasAnyLineTerminatorAfterNext(); |
| + |
| + if (is_async) { |
| + Consume(Token::IDENTIFIER); |
| + DCHECK(peek_any_identifier() || peek() == Token::LPAREN); |
| + } |
| + |
| // TODO(adamk): We should construct this scope from the ScopeInfo. |
| Scope* scope = |
| NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction); |
| @@ -1105,8 +1120,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, |
| checkpoint.Restore(&formals.materialized_literals_count); |
| // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should |
| // not be observable, or else the preparser would have failed. |
| - Expression* expression = |
| - ParseArrowFunctionLiteral(true, formals, formals_classifier, &ok); |
| + Expression* expression = ParseArrowFunctionLiteral( |
| + true, formals, is_async, formals_classifier, &ok); |
| if (ok) { |
| // Scanning must end at the same position that was recorded |
| // previously. If not, parsing has been interrupted due to a stack |
| @@ -1245,8 +1260,8 @@ Statement* Parser::ParseStatementListItem(bool* ok) { |
| // StatementListItem: |
| // Statement |
| // Declaration |
| - |
| - switch (peek()) { |
| + const Token::Value peeked = peek(); |
| + switch (peeked) { |
| case Token::FUNCTION: |
| return ParseFunctionDeclaration(NULL, ok); |
| case Token::CLASS: |
| @@ -1261,6 +1276,15 @@ Statement* Parser::ParseStatementListItem(bool* ok) { |
| return ParseVariableStatement(kStatementListItem, NULL, ok); |
| } |
| break; |
| + case Token::IDENTIFIER: |
| + if (allow_harmony_async_await() && |
| + PeekContextualKeyword(CStrVector("async")) && |
|
Dan Ehrenberg
2016/04/25 21:18:16
You mentioned that this patch causes a parser slow
caitp (gmail)
2016/04/26 00:09:38
I said there was a parser slowdown in JSC. I don't
|
| + PeekAhead() == Token::FUNCTION && |
| + !scanner()->HasAnyLineTerminatorAfterNext()) { |
| + Consume(Token::IDENTIFIER); |
| + return ParseAsyncFunctionDeclaration(NULL, ok); |
| + } |
| + /* falls through */ |
| default: |
| break; |
| } |
| @@ -1550,7 +1574,10 @@ Statement* Parser::ParseExportDefault(bool* ok) { |
| pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK); |
| result = factory()->NewEmptyStatement(RelocInfo::kNoPosition); |
| } else { |
| - result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK); |
| + result = ParseFunctionDeclarationInternal( |
| + pos, is_generator ? ParseFunctionFlags::kIsGenerator |
| + : ParseFunctionFlags::kIsNormal, |
| + &names, CHECK_OK); |
| } |
| break; |
| } |
| @@ -2051,13 +2078,25 @@ Statement* Parser::ParseFunctionDeclaration( |
| ZoneList<const AstRawString*>* names, bool* ok) { |
| Expect(Token::FUNCTION, CHECK_OK); |
| int pos = position(); |
| - bool is_generator = Check(Token::MUL); |
| - return ParseFunctionDeclaration(pos, is_generator, names, ok); |
| + ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal; |
| + if (Check(Token::MUL)) { |
| + flags |= ParseFunctionFlags::kIsGenerator; |
| + } |
| + return ParseFunctionDeclarationInternal(pos, flags, names, ok); |
| } |
| +Statement* Parser::ParseAsyncFunctionDeclaration( |
| + ZoneList<const AstRawString*>* names, bool* ok) { |
| + DCHECK_EQ(scanner()->current_token(), Token::IDENTIFIER); |
| + DCHECK(scanner()->is_literal_contextual_keyword(CStrVector("async"))); |
| + int pos = position(); |
| + Expect(Token::FUNCTION, CHECK_OK); |
| + ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync; |
| + return ParseFunctionDeclarationInternal(pos, flags, names, ok); |
| +} |
| -Statement* Parser::ParseFunctionDeclaration( |
| - int pos, bool is_generator, ZoneList<const AstRawString*>* names, |
| +Statement* Parser::ParseFunctionDeclarationInternal( |
| + int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names, |
| bool* ok) { |
| // FunctionDeclaration :: |
| // 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}' |
| @@ -2065,10 +2104,21 @@ Statement* Parser::ParseFunctionDeclaration( |
| // 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}' |
| // |
| // 'function' and '*' (if present) have been consumed by the caller. |
| + const bool is_generator = flags & ParseFunctionFlags::kIsGenerator; |
| + const bool is_async = flags & ParseFunctionFlags::kIsAsync; |
| + DCHECK(!is_generator || !is_async); |
| + |
| bool is_strict_reserved = false; |
| const AstRawString* name = ParseIdentifierOrStrictReservedWord( |
| &is_strict_reserved, CHECK_OK); |
| + if (V8_UNLIKELY(is_async_function() && is_async && this->IsAwait(name))) { |
| + ReportMessageAt(scanner()->location(), |
| + MessageTemplate::kAwaitBindingIdentifier); |
| + *ok = false; |
| + return nullptr; |
| + } |
| + |
| FuncNameInferrer::State fni_state(fni_); |
| if (fni_ != NULL) fni_->PushEnclosingName(name); |
| FunctionLiteral* fun = ParseFunctionLiteral( |
| @@ -2076,7 +2126,8 @@ Statement* Parser::ParseFunctionDeclaration( |
| is_strict_reserved ? kFunctionNameIsStrictReserved |
| : kFunctionNameValidityUnknown, |
| is_generator ? FunctionKind::kGeneratorFunction |
| - : FunctionKind::kNormalFunction, |
| + : is_async ? FunctionKind::kAsyncFunction |
| + : FunctionKind::kNormalFunction, |
| pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK); |
| // Even if we're not at the top-level of the global or a function |
| @@ -4190,6 +4241,37 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| return function_literal; |
| } |
| +Expression* Parser::ParseAsyncFunctionExpression(bool* ok) { |
| + // AsyncFunctionDeclaration :: |
| + // async [no LineTerminator here] function ( FormalParameters[Await] ) |
| + // { AsyncFunctionBody } |
| + // |
| + // async [no LineTerminator here] function BindingIdentifier[Await] |
| + // ( FormalParameters[Await] ) { AsyncFunctionBody } |
| + DCHECK_EQ(scanner()->current_token(), Token::IDENTIFIER); |
| + DCHECK(scanner()->is_literal_contextual_keyword(CStrVector("async"))); |
| + int pos = position(); |
| + Expect(Token::FUNCTION, CHECK_OK); |
| + bool is_strict_reserved = false; |
| + const AstRawString* name = nullptr; |
| + FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression; |
| + |
| + if (peek_any_identifier()) { |
| + type = FunctionLiteral::kNamedExpression; |
| + name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); |
| + if (this->IsAwait(name)) { |
| + ReportMessageAt(scanner()->location(), |
| + MessageTemplate::kAwaitBindingIdentifier); |
| + *ok = false; |
| + return nullptr; |
| + } |
| + } |
| + return ParseFunctionLiteral(name, scanner()->location(), |
| + is_strict_reserved ? kFunctionNameIsStrictReserved |
| + : kFunctionNameValidityUnknown, |
| + FunctionKind::kAsyncFunction, pos, type, |
| + language_mode(), CHECK_OK); |
| +} |
| void Parser::SkipLazyFunctionBody(int* materialized_literal_count, |
| int* expected_property_count, bool* ok, |
| @@ -4594,6 +4676,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( |
| SET_ALLOW(harmony_function_sent); |
| SET_ALLOW(harmony_exponentiation_operator); |
| SET_ALLOW(harmony_restrictive_declarations); |
| + SET_ALLOW(harmony_async_await); |
| #undef SET_ALLOW |
| } |
| PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( |
| @@ -5279,6 +5362,16 @@ void Parser::RaiseLanguageMode(LanguageMode mode) { |
| SetLanguageMode(scope_, old > mode ? old : mode); |
| } |
| +Expression* ParserTraits::ExpressionListToExpression( |
| + ZoneList<Expression*>* args) { |
| + AstNodeFactory* factory = parser_->factory(); |
| + Expression* expr = args->at(0); |
| + for (int i = 1; i < args->length(); ++i) { |
| + expr = factory->NewBinaryOperation(Token::COMMA, expr, args->at(i), |
| + expr->position()); |
| + } |
| + return expr; |
| +} |
| void ParserTraits::RewriteDestructuringAssignments() { |
| parser_->RewriteDestructuringAssignments(); |
| @@ -5300,6 +5393,11 @@ void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier, |
| parser_->RewriteNonPattern(classifier, ok); |
| } |
| +Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) { |
| + // TODO(caitp): Implement AsyncFunctionAwait() |
| + // per tc39.github.io/ecmascript-asyncawait/#abstract-ops-async-function-await |
| + return value; |
| +} |
| Zone* ParserTraits::zone() const { |
| return parser_->function_state_->scope()->zone(); |