| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index cdfceea2608f19a6d6f93bc7804d7288e318fc61..ac3683124e7c101bc50976f3d73424207240384d 100644
|
| --- a/src/preparser.h
|
| +++ b/src/preparser.h
|
| @@ -119,7 +119,8 @@ class ParserBase : public Traits {
|
| allow_harmony_new_target_(false),
|
| allow_strong_mode_(false),
|
| allow_legacy_const_(true),
|
| - allow_harmony_do_expressions_(false) {}
|
| + allow_harmony_do_expressions_(false),
|
| + allow_harmony_async_await_(false) {}
|
|
|
| #define ALLOW_ACCESSORS(name) \
|
| bool allow_##name() const { return allow_##name##_; } \
|
| @@ -139,6 +140,7 @@ class ParserBase : public Traits {
|
| ALLOW_ACCESSORS(strong_mode);
|
| ALLOW_ACCESSORS(legacy_const);
|
| ALLOW_ACCESSORS(harmony_do_expressions);
|
| + ALLOW_ACCESSORS(harmony_async_await);
|
| #undef ALLOW_ACCESSORS
|
|
|
| uintptr_t stack_limit() const { return stack_limit_; }
|
| @@ -216,6 +218,7 @@ class ParserBase : public Traits {
|
| }
|
|
|
| bool is_generator() const { return IsGeneratorFunction(kind_); }
|
| + bool is_async() const { return IsAsyncFunction(kind_); }
|
|
|
| FunctionKind kind() const { return kind_; }
|
| FunctionState* outer() const { return outer_function_state_; }
|
| @@ -402,7 +405,8 @@ class ParserBase : public Traits {
|
| Token::Value next = peek();
|
| return next == Token::IDENTIFIER || next == Token::FUTURE_RESERVED_WORD ||
|
| next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
| - next == Token::STATIC || next == Token::YIELD;
|
| + next == Token::STATIC || next == Token::YIELD ||
|
| + next == Token::ASYNC;
|
| }
|
|
|
| bool CheckContextualKeyword(Vector<const char> keyword) {
|
| @@ -509,6 +513,7 @@ class ParserBase : public Traits {
|
|
|
| LanguageMode language_mode() { return scope_->language_mode(); }
|
| bool is_generator() const { return function_state_->is_generator(); }
|
| + bool is_async() const { return function_state_->is_async(); }
|
|
|
| bool allow_const() {
|
| return is_strict(language_mode()) || allow_harmony_sloppy() ||
|
| @@ -743,6 +748,7 @@ class ParserBase : public Traits {
|
| bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok);
|
|
|
| bool IsNextLetKeyword();
|
| + bool IsNextAsyncFunctionKeyword();
|
|
|
| // 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,
|
| @@ -848,6 +854,7 @@ class ParserBase : public Traits {
|
| bool allow_strong_mode_;
|
| bool allow_legacy_const_;
|
| bool allow_harmony_do_expressions_;
|
| + bool allow_harmony_async_await_;
|
| };
|
|
|
|
|
| @@ -881,6 +888,9 @@ class PreParserIdentifier {
|
| static PreParserIdentifier Yield() {
|
| return PreParserIdentifier(kYieldIdentifier);
|
| }
|
| + static PreParserIdentifier Async() {
|
| + return PreParserIdentifier(kAsyncIdentifier);
|
| + }
|
| static PreParserIdentifier Prototype() {
|
| return PreParserIdentifier(kPrototypeIdentifier);
|
| }
|
| @@ -894,6 +904,7 @@ class PreParserIdentifier {
|
| bool IsLet() const { return type_ == kLetIdentifier; }
|
| bool IsStatic() const { return type_ == kStaticIdentifier; }
|
| bool IsYield() const { return type_ == kYieldIdentifier; }
|
| + bool IsAsync() const { return type_ == kAsyncIdentifier; }
|
| bool IsPrototype() const { return type_ == kPrototypeIdentifier; }
|
| bool IsConstructor() const { return type_ == kConstructorIdentifier; }
|
| bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; }
|
| @@ -919,6 +930,7 @@ class PreParserIdentifier {
|
| kLetIdentifier,
|
| kStaticIdentifier,
|
| kYieldIdentifier,
|
| + kAsyncIdentifier,
|
| kEvalIdentifier,
|
| kArgumentsIdentifier,
|
| kUndefinedIdentifier,
|
| @@ -1997,6 +2009,7 @@ void ParserBase<Traits>::GetUnexpectedTokenMessage(
|
| case Token::LET:
|
| case Token::STATIC:
|
| case Token::YIELD:
|
| + case Token::ASYNC:
|
| case Token::FUTURE_STRICT_RESERVED_WORD:
|
| *message = is_strict(language_mode())
|
| ? MessageTemplate::kUnexpectedStrictReserved
|
| @@ -2108,6 +2121,7 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
| } else if (is_sloppy(language_mode()) &&
|
| (next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
| next == Token::LET || next == Token::STATIC ||
|
| + next == Token::ASYNC ||
|
| (next == Token::YIELD && !is_generator()))) {
|
| classifier->RecordStrictModeFormalParameterError(
|
| scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
|
| @@ -2116,6 +2130,10 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
| MessageTemplate::kLetInLexicalBinding);
|
| }
|
| return this->GetSymbol(scanner());
|
| + } else if (next == Token::ASYNC) {
|
| + // Async token is special because it's allowed in any mode
|
| + // as identifier name
|
| + return this->GetSymbol(scanner());
|
| } else {
|
| this->ReportUnexpectedToken(next);
|
| *ok = false;
|
| @@ -2129,7 +2147,8 @@ typename ParserBase<Traits>::IdentifierT ParserBase<
|
| Traits>::ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
|
| bool* ok) {
|
| Token::Value next = Next();
|
| - if (next == Token::IDENTIFIER) {
|
| + // Async is allowed as an identifier
|
| + if (next == Token::IDENTIFIER || next == Token::ASYNC) {
|
| *is_strict_reserved = false;
|
| } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
| next == Token::STATIC ||
|
| @@ -2153,7 +2172,8 @@ ParserBase<Traits>::ParseIdentifierName(bool* ok) {
|
| Token::Value next = Next();
|
| if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
|
| next != Token::LET && next != Token::STATIC && next != Token::YIELD &&
|
| - next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
|
| + next != Token::ASYNC && next != Token::FUTURE_STRICT_RESERVED_WORD &&
|
| + !Token::IsKeyword(next)) {
|
| this->ReportUnexpectedToken(next);
|
| *ok = false;
|
| return Traits::EmptyIdentifier();
|
| @@ -2280,6 +2300,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
| case Token::LET:
|
| case Token::STATIC:
|
| case Token::YIELD:
|
| + case Token::ASYNC:
|
| case Token::FUTURE_STRICT_RESERVED_WORD: {
|
| // Using eval or arguments in this context is OK even in strict mode.
|
| IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK);
|
| @@ -3448,7 +3469,7 @@ typename ParserBase<Traits>::ExpressionT
|
| ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
| bool* ok) {
|
| // MemberExpression ::
|
| - // (PrimaryExpression | FunctionLiteral | ClassLiteral)
|
| + // (PrimaryExpression | FunctionLiteral | AsyncLiteral | ClassLiteral)
|
| // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
|
|
| // The '[' Expression ']' and '.' Identifier parts are parsed by
|
| @@ -3457,13 +3478,17 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
|
|
| // Parse the initial primary or function expression.
|
| ExpressionT result = this->EmptyExpression();
|
| - if (peek() == Token::FUNCTION) {
|
| + Token::Value token = peek();
|
| + if (token == Token::FUNCTION ||
|
| + (allow_harmony_async_await() && token == Token::ASYNC &&
|
| + IsNextAsyncFunctionKeyword())) {
|
| + bool is_async = Check(Token::ASYNC);
|
| BindingPatternUnexpectedToken(classifier);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
|
|
| Consume(Token::FUNCTION);
|
| int function_token_position = position();
|
| - bool is_generator = Check(Token::MUL);
|
| + bool is_generator = is_async ? false : Check(Token::MUL);
|
| IdentifierT name = this->EmptyIdentifier();
|
| bool is_strict_reserved_name = false;
|
| Scanner::Location function_name_location = Scanner::Location::invalid();
|
| @@ -3475,14 +3500,20 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
| function_name_location = scanner()->location();
|
| function_type = FunctionLiteral::NAMED_EXPRESSION;
|
| }
|
| +
|
| + FunctionKind kind = FunctionKind::kNormalFunction;
|
| + if (is_generator) {
|
| + kind = FunctionKind::kGeneratorFunction;
|
| + } else if (is_async) {
|
| + kind = FunctionKind::kAsyncFunction;
|
| + }
|
| +
|
| result = this->ParseFunctionLiteral(
|
| name, function_name_location,
|
| is_strict_reserved_name ? kFunctionNameIsStrictReserved
|
| : kFunctionNameValidityUnknown,
|
| - is_generator ? FunctionKind::kGeneratorFunction
|
| - : FunctionKind::kNormalFunction,
|
| - function_token_position, function_type, FunctionLiteral::NORMAL_ARITY,
|
| - language_mode(), CHECK_OK);
|
| + kind, function_token_position, function_type,
|
| + FunctionLiteral::NORMAL_ARITY, language_mode(), CHECK_OK);
|
| } else if (peek() == Token::SUPER) {
|
| const bool is_new = false;
|
| result = ParseSuperExpression(is_new, classifier, CHECK_OK);
|
| @@ -3900,6 +3931,7 @@ bool ParserBase<Traits>::IsNextLetKeyword() {
|
| case Token::STATIC:
|
| case Token::LET: // Yes, you can do let let = ... in sloppy mode
|
| case Token::YIELD:
|
| + case Token::ASYNC:
|
| return true;
|
| default:
|
| return false;
|
| @@ -3908,6 +3940,15 @@ bool ParserBase<Traits>::IsNextLetKeyword() {
|
|
|
|
|
| template <class Traits>
|
| +bool ParserBase<Traits>::IsNextAsyncFunctionKeyword() {
|
| + DCHECK(peek() == Token::ASYNC);
|
| + Token::Value next_next = PeekAhead();
|
| + return next_next == Token::FUNCTION &&
|
| + !scanner()->HasAnyLineTerminatorBeforeNext();
|
| +}
|
| +
|
| +
|
| +template <class Traits>
|
| typename ParserBase<Traits>::ExpressionT
|
| ParserBase<Traits>::ParseArrowFunctionLiteral(
|
| bool accept_IN, const FormalParametersT& formal_parameters,
|
|
|