diff options
author | Ujjwal Sharma <usharma1998@gmail.com> | 2019-03-15 18:35:06 +0530 |
---|---|---|
committer | Refael Ackermann <refack@gmail.com> | 2019-03-28 16:36:18 -0400 |
commit | f579e1194046c50f2e6bb54348d48c8e7d1a53cf (patch) | |
tree | 9125787c758358365f74f9fd9673c14f57e67870 /deps/v8/src/parsing/parser-base.h | |
parent | 2c73868b0471fbd4038f500d076df056cbf697fe (diff) | |
download | android-node-v8-f579e1194046c50f2e6bb54348d48c8e7d1a53cf.tar.gz android-node-v8-f579e1194046c50f2e6bb54348d48c8e7d1a53cf.tar.bz2 android-node-v8-f579e1194046c50f2e6bb54348d48c8e7d1a53cf.zip |
deps: update V8 to 7.4.288.13
PR-URL: https://github.com/nodejs/node/pull/26685
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michaƫl Zasso <targos@protonmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Diffstat (limited to 'deps/v8/src/parsing/parser-base.h')
-rw-r--r-- | deps/v8/src/parsing/parser-base.h | 545 |
1 files changed, 351 insertions, 194 deletions
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index 33c165cd92..3bcb8bed91 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -16,6 +16,7 @@ #include "src/base/hashmap.h" #include "src/base/v8-fallthrough.h" #include "src/counters.h" +#include "src/function-kind.h" #include "src/globals.h" #include "src/log.h" #include "src/message-template.h" @@ -277,13 +278,13 @@ class ParserBase { bool allow_##name() const { return allow_##name##_; } \ void set_allow_##name(bool allow) { allow_##name##_ = allow; } - ALLOW_ACCESSORS(natives); - ALLOW_ACCESSORS(harmony_public_fields); - ALLOW_ACCESSORS(harmony_static_fields); - ALLOW_ACCESSORS(harmony_dynamic_import); - ALLOW_ACCESSORS(harmony_import_meta); - ALLOW_ACCESSORS(harmony_private_methods); - ALLOW_ACCESSORS(eval_cache); + ALLOW_ACCESSORS(natives) + ALLOW_ACCESSORS(harmony_public_fields) + ALLOW_ACCESSORS(harmony_static_fields) + ALLOW_ACCESSORS(harmony_dynamic_import) + ALLOW_ACCESSORS(harmony_import_meta) + ALLOW_ACCESSORS(harmony_private_methods) + ALLOW_ACCESSORS(eval_cache) #undef ALLOW_ACCESSORS @@ -399,7 +400,7 @@ class ParserBase { } void set_next_function_is_likely_called() { - next_function_is_likely_called_ = true; + next_function_is_likely_called_ = !FLAG_max_lazy; } void RecordFunctionOrEvalCall() { contains_function_or_eval_ = true; } @@ -480,16 +481,14 @@ class ParserBase { struct DeclarationParsingResult { struct Declaration { - Declaration(ExpressionT pattern, int initializer_position, - ExpressionT initializer) - : pattern(pattern), - initializer_position(initializer_position), - initializer(initializer) {} + Declaration(ExpressionT pattern, ExpressionT initializer) + : pattern(pattern), initializer(initializer) { + DCHECK_IMPLIES(Impl::IsNull(pattern), Impl::IsNull(initializer)); + } ExpressionT pattern; - int initializer_position; - int value_beg_position = kNoSourcePosition; ExpressionT initializer; + int value_beg_pos = kNoSourcePosition; }; DeclarationParsingResult() @@ -798,6 +797,7 @@ class ParserBase { bool PeekContextualKeyword(const AstRawString* name) { return peek() == Token::IDENTIFIER && + !scanner()->next_literal_contains_escapes() && scanner()->NextSymbol(ast_value_factory()) == name; } @@ -809,14 +809,21 @@ class ParserBase { return false; } - void ExpectMetaProperty(const AstRawString* property_name, - const char* full_name, int pos); - - void ExpectContextualKeyword(const AstRawString* name) { + void ExpectContextualKeyword(const AstRawString* name, + const char* fullname = nullptr, int pos = -1) { Expect(Token::IDENTIFIER); if (V8_UNLIKELY(scanner()->CurrentSymbol(ast_value_factory()) != name)) { ReportUnexpectedToken(scanner()->current_token()); } + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + const char* full = fullname == nullptr + ? reinterpret_cast<const char*>(name->raw_data()) + : fullname; + int start = pos == -1 ? position() : pos; + impl()->ReportMessageAt(Scanner::Location(start, end_position()), + MessageTemplate::kInvalidEscapedMetaProperty, + full); + } } bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode) { @@ -955,6 +962,26 @@ class ParserBase { if (is_strict(language_mode)) parameters.ValidateStrictMode(impl()); } + // Needs to be called if the reference needs to be available from the current + // point. It causes the receiver to be context allocated if necessary. + // Returns the receiver variable that we're referencing. + V8_INLINE Variable* UseThis() { + DeclarationScope* closure_scope = scope()->GetClosureScope(); + DeclarationScope* receiver_scope = closure_scope->GetReceiverScope(); + Variable* var = receiver_scope->receiver(); + var->set_is_used(); + if (closure_scope == receiver_scope) { + // It's possible that we're parsing the head of an arrow function, in + // which case we haven't realized yet that closure_scope != + // receiver_scope. Mark through the ExpressionScope for now. + expression_scope()->RecordThisUse(); + } else { + closure_scope->set_has_this_reference(); + var->ForceContextAllocation(); + } + return var; + } + V8_INLINE IdentifierT ParseAndClassifyIdentifier(Token::Value token); // Parses an identifier or a strict mode future reserved word. Allows passing // in function_kind for the case of parsing the identifier in a function @@ -968,6 +995,8 @@ class ParserBase { // mode. IdentifierT ParseNonRestrictedIdentifier(); + // This method should be used to ambiguously parse property names that can + // become destructuring identifiers. V8_INLINE IdentifierT ParsePropertyName(); ExpressionT ParsePropertyOrPrivatePropertyName(); @@ -1027,10 +1056,11 @@ class ParserBase { ExpressionT ParseAwaitExpression(); V8_INLINE ExpressionT ParseUnaryExpression(); V8_INLINE ExpressionT ParsePostfixExpression(); + V8_NOINLINE ExpressionT ParsePostfixContinuation(ExpressionT expression, + int lhs_beg_pos); V8_INLINE ExpressionT ParseLeftHandSideExpression(); ExpressionT ParseLeftHandSideContinuation(ExpressionT expression); ExpressionT ParseMemberWithPresentNewPrefixesExpression(); - V8_INLINE ExpressionT ParseMemberWithNewPrefixesExpression(); ExpressionT ParseFunctionExpression(); V8_INLINE ExpressionT ParseMemberExpression(); V8_INLINE ExpressionT @@ -1082,6 +1112,31 @@ class ParserBase { FunctionLiteral::FunctionType function_type, FunctionBodyType body_type); + // Check if the scope has conflicting var/let declarations from different + // scopes. This covers for example + // + // function f() { { { var x; } let x; } } + // function g() { { var x; let x; } } + // + // The var declarations are hoisted to the function scope, but originate from + // a scope where the name has also been let bound or the var declaration is + // hoisted over such a scope. + void CheckConflictingVarDeclarations(DeclarationScope* scope) { + if (has_error()) return; + Declaration* decl = scope->CheckConflictingVarDeclarations(); + if (decl != nullptr) { + // In ES6, conflicting variable bindings are early errors. + const AstRawString* name = decl->var()->raw_name(); + int position = decl->position(); + Scanner::Location location = + position == kNoSourcePosition + ? Scanner::Location::invalid() + : Scanner::Location(position, position + 1); + impl()->ReportMessageAt(location, MessageTemplate::kVarRedeclaration, + name); + } + } + // TODO(nikolaos, marja): The first argument should not really be passed // by value. The method is expected to add the parsed statements to the // list. This works because in the case of the parser, StatementListT is @@ -1159,39 +1214,6 @@ class ParserBase { return identifier == ast_value_factory()->let_string(); } - void DesugarBindingInForEachStatement(ForInfo* for_info, BlockT* body_block, - ExpressionT* each_variable) { - // Annex B.3.5 prohibits the form - // `try {} catch(e) { for (var e of {}); }` - // So if we are parsing a statement like `for (var ... of ...)` - // we need to walk up the scope chain and look for catch scopes - // which have a simple binding, then compare their binding against - // all of the names declared in the init of the for-of we're - // parsing. - bool is_for_var_of = - for_info->mode == ForEachStatement::ITERATE && - for_info->parsing_result.descriptor.mode == VariableMode::kVar; - - if (is_for_var_of) { - Scope* scope = this->scope(); - while (scope != nullptr && !scope->is_declaration_scope()) { - if (scope->is_catch_scope()) { - auto name = scope->catch_variable()->raw_name(); - // If it's a simple binding and the name is declared in the for loop. - if (name != ast_value_factory()->dot_catch_string() && - for_info->bound_names.Contains(name)) { - impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, - MessageTemplate::kVarRedeclaration, name); - } - } - scope = scope->outer_scope(); - } - } - - impl()->DesugarBindingInForEachStatement(for_info, body_block, - each_variable); - } - bool IsNextLetKeyword(); // Checks if the expression is a valid reference expression (e.g., on the @@ -1461,9 +1483,8 @@ template <typename Impl> typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) { DCHECK_EQ(scanner()->current_token(), next); - STATIC_ASSERT(Token::IDENTIFIER + 1 == Token::ASYNC); if (V8_LIKELY(IsInRange(next, Token::IDENTIFIER, Token::ASYNC))) { - IdentifierT name = impl()->GetSymbol(); + IdentifierT name = impl()->GetIdentifier(); if (V8_UNLIKELY(impl()->IsArguments(name) && scope()->ShouldBanArguments())) { ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer); @@ -1481,13 +1502,13 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) { if (next == Token::AWAIT) { expression_scope()->RecordAsyncArrowParametersError( scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); - return impl()->GetSymbol(); + return impl()->GetIdentifier(); } DCHECK(Token::IsStrictReservedWord(next)); expression_scope()->RecordStrictModeParameterError( scanner()->location(), MessageTemplate::kUnexpectedStrictReserved); - return impl()->GetSymbol(); + return impl()->GetIdentifier(); } template <class Impl> @@ -1502,7 +1523,7 @@ typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier( return impl()->EmptyIdentifierString(); } - return impl()->GetSymbol(); + return impl()->GetIdentifier(); } template <typename Impl> @@ -1522,7 +1543,10 @@ ParserBase<Impl>::ParseNonRestrictedIdentifier() { template <typename Impl> typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParsePropertyName() { Token::Value next = Next(); - if (V8_LIKELY(Token::IsPropertyName(next))) return impl()->GetSymbol(); + if (V8_LIKELY(Token::IsPropertyName(next))) { + if (peek() == Token::COLON) return impl()->GetSymbol(); + return impl()->GetIdentifier(); + } ReportUnexpectedToken(next); return impl()->EmptyIdentifierString(); @@ -1539,7 +1563,23 @@ ParserBase<Impl>::ParsePropertyOrPrivatePropertyName() { name = impl()->GetSymbol(); key = factory()->NewStringLiteral(name, pos); } else if (allow_harmony_private_fields() && next == Token::PRIVATE_NAME) { - name = impl()->GetSymbol(); + // In the case of a top level function, we completely skip + // analysing it's scope, meaning, we don't have a chance to + // resolve private names and find that they are not enclosed in a + // class body. + // + // Here, we check if this is a new private name reference in a top + // level function and throw an error if so. + // + // Bug(v8:7468): This hack will go away once we refactor private + // name resolution to happen independently from scope resolution. + if (scope()->scope_type() == FUNCTION_SCOPE && + scope()->outer_scope() != nullptr && + scope()->outer_scope()->scope_type() == SCRIPT_SCOPE) { + ReportMessage(MessageTemplate::kInvalidPrivateFieldResolution); + } + + name = impl()->GetIdentifier(); key = impl()->ExpressionFromIdentifier(name, pos, InferName::kNo); } else { ReportUnexpectedToken(next); @@ -1637,7 +1677,8 @@ ParserBase<Impl>::ParsePrimaryExpression() { FunctionKind kind = FunctionKind::kArrowFunction; if (V8_UNLIKELY(token == Token::ASYNC && - !scanner()->HasLineTerminatorBeforeNext())) { + !scanner()->HasLineTerminatorBeforeNext() && + !scanner()->literal_contains_escapes())) { // async function ... if (peek() == Token::FUNCTION) return ParseAsyncFunctionLiteral(); @@ -1668,15 +1709,29 @@ ParserBase<Impl>::ParsePrimaryExpression() { } switch (token) { + case Token::NEW: + return ParseMemberWithPresentNewPrefixesExpression(); + case Token::THIS: { Consume(Token::THIS); - return impl()->ThisExpression(beg_pos); + return impl()->ThisExpression(); } case Token::ASSIGN_DIV: case Token::DIV: return ParseRegExpLiteral(); + case Token::FUNCTION: + return ParseFunctionExpression(); + + case Token::SUPER: { + const bool is_new = false; + return ParseSuperExpression(is_new); + } + case Token::IMPORT: + if (!allow_harmony_dynamic_import()) break; + return ParseImportExpressions(); + case Token::LBRACK: return ParseArrayLiteral(); @@ -1914,10 +1969,13 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( Token::Value token = peek(); if ((token != Token::MUL && prop_info->ParsePropertyKindFromToken(token)) || scanner()->HasLineTerminatorBeforeNext()) { - prop_info->name = impl()->GetSymbol(); + prop_info->name = impl()->GetIdentifier(); impl()->PushLiteralName(prop_info->name); return factory()->NewStringLiteral(prop_info->name, position()); } + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD); + } prop_info->function_flags = ParseFunctionFlag::kIsAsync; prop_info->kind = ParsePropertyKind::kMethod; } @@ -1928,21 +1986,21 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( } if (prop_info->kind == ParsePropertyKind::kNotSet && - Check(Token::IDENTIFIER)) { - IdentifierT symbol = impl()->GetSymbol(); - if (!prop_info->ParsePropertyKindFromToken(peek())) { - if (impl()->IdentifierEquals(symbol, ast_value_factory()->get_string())) { - prop_info->kind = ParsePropertyKind::kAccessorGetter; - } else if (impl()->IdentifierEquals(symbol, - ast_value_factory()->set_string())) { - prop_info->kind = ParsePropertyKind::kAccessorSetter; - } - } - if (!IsAccessor(prop_info->kind)) { - prop_info->name = symbol; + IsInRange(peek(), Token::GET, Token::SET)) { + Token::Value token = Next(); + if (prop_info->ParsePropertyKindFromToken(peek())) { + prop_info->name = impl()->GetIdentifier(); impl()->PushLiteralName(prop_info->name); return factory()->NewStringLiteral(prop_info->name, position()); } + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD); + } + if (token == Token::GET) { + prop_info->kind = ParsePropertyKind::kAccessorGetter; + } else if (token == Token::SET) { + prop_info->kind = ParsePropertyKind::kAccessorSetter; + } } int pos = peek_position(); @@ -1966,19 +2024,26 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( if (prop_info->kind == ParsePropertyKind::kNotSet) { prop_info->ParsePropertyKindFromToken(peek()); } - prop_info->name = impl()->GetSymbol(); - if (prop_info->position == PropertyPosition::kObjectLiteral || - (!allow_harmony_private_methods() && - (IsAccessor(prop_info->kind) || - prop_info->kind == ParsePropertyKind::kMethod))) { + prop_info->name = impl()->GetIdentifier(); + if (V8_UNLIKELY(prop_info->position == + PropertyPosition::kObjectLiteral)) { + ReportUnexpectedToken(Token::PRIVATE_NAME); + prop_info->kind = ParsePropertyKind::kNotSet; + return impl()->FailureExpression(); + } + if (V8_UNLIKELY(!allow_harmony_private_methods() && + (IsAccessor(prop_info->kind) || + prop_info->kind == ParsePropertyKind::kMethod))) { ReportUnexpectedToken(Next()); + prop_info->kind = ParsePropertyKind::kNotSet; return impl()->FailureExpression(); } break; case Token::STRING: Consume(Token::STRING); - prop_info->name = impl()->GetSymbol(); + prop_info->name = peek() == Token::COLON ? impl()->GetSymbol() + : impl()->GetIdentifier(); is_array_index = impl()->IsArrayIndex(prop_info->name, &index); break; @@ -2071,13 +2136,13 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info, if (peek() == Token::LPAREN) { prop_info->kind = ParsePropertyKind::kMethod; // TODO(bakkot) specialize on 'static' - prop_info->name = impl()->GetSymbol(); + prop_info->name = impl()->GetIdentifier(); name_expression = factory()->NewStringLiteral(prop_info->name, position()); } else if (peek() == Token::ASSIGN || peek() == Token::SEMICOLON || peek() == Token::RBRACE) { // TODO(bakkot) specialize on 'static' - prop_info->name = impl()->GetSymbol(); + prop_info->name = impl()->GetIdentifier(); name_expression = factory()->NewStringLiteral(prop_info->name, position()); } else { @@ -2264,6 +2329,9 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, Scanner::Location next_loc = scanner()->peek_location(); ExpressionT name_expression = ParseProperty(prop_info); + + DCHECK_IMPLIES(name_token == Token::PRIVATE_NAME, has_error()); + IdentifierT name = prop_info->name; ParseFunctionFlags function_flags = prop_info->function_flags; ParsePropertyKind kind = prop_info->kind; @@ -2285,7 +2353,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); if (!prop_info->is_computed_name && - impl()->IdentifierEquals(name, ast_value_factory()->proto_string())) { + scanner()->CurrentLiteralEquals("__proto__")) { if (*has_seen_proto) { expression_scope()->RecordExpressionError( scanner()->location(), MessageTemplate::kDuplicateProto); @@ -2322,10 +2390,6 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, DCHECK(!prop_info->is_computed_name); - if (name_token == Token::LET) { - expression_scope()->RecordLexicalDeclarationError( - scanner()->location(), MessageTemplate::kLetInLexicalBinding); - } if (name_token == Token::AWAIT) { DCHECK(!is_async_function()); expression_scope()->RecordAsyncArrowParametersError( @@ -2666,6 +2730,9 @@ ParserBase<Impl>::ParseYieldExpression() { expression_scope()->RecordParameterInitializerError( scanner()->peek_location(), MessageTemplate::kYieldInParameter); Consume(Token::YIELD); + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD); + } CheckStackOverflow(); @@ -2890,6 +2957,9 @@ ParserBase<Impl>::ParseAwaitExpression() { MessageTemplate::kAwaitExpressionFormalParameter); int await_pos = peek_position(); Consume(Token::AWAIT); + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD); + } CheckStackOverflow(); @@ -2933,24 +3003,29 @@ ParserBase<Impl>::ParsePostfixExpression() { int lhs_beg_pos = peek_position(); ExpressionT expression = ParseLeftHandSideExpression(); - if (!scanner()->HasLineTerminatorBeforeNext() && Token::IsCountOp(peek())) { - if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) { - expression = RewriteInvalidReferenceExpression( - expression, lhs_beg_pos, end_position(), - MessageTemplate::kInvalidLhsInPostfixOp); - } - if (impl()->IsIdentifier(expression)) { - expression_scope()->MarkIdentifierAsAssigned(); - } + if (V8_LIKELY(!Token::IsCountOp(peek()) || + scanner()->HasLineTerminatorBeforeNext())) { + return expression; + } + return ParsePostfixContinuation(expression, lhs_beg_pos); +} - Token::Value next = Next(); - expression = - factory()->NewCountOperation(next, - false /* postfix */, - expression, - position()); +template <typename Impl> +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParsePostfixContinuation(ExpressionT expression, + int lhs_beg_pos) { + if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) { + expression = RewriteInvalidReferenceExpression( + expression, lhs_beg_pos, end_position(), + MessageTemplate::kInvalidLhsInPostfixOp); } - return expression; + if (impl()->IsIdentifier(expression)) { + expression_scope()->MarkIdentifierAsAssigned(); + } + + Token::Value next = Next(); + return factory()->NewCountOperation(next, false /* postfix */, expression, + position()); } template <typename Impl> @@ -2959,7 +3034,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression() { // LeftHandSideExpression :: // (NewExpression | MemberExpression) ... - ExpressionT result = ParseMemberWithNewPrefixesExpression(); + ExpressionT result = ParseMemberExpression(); if (!Token::IsPropertyOrCall(peek())) return result; return ParseLeftHandSideContinuation(result); } @@ -2971,7 +3046,8 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { if (V8_UNLIKELY(peek() == Token::LPAREN && impl()->IsIdentifier(result) && scanner()->current_token() == Token::ASYNC && - !scanner()->HasLineTerminatorBeforeNext())) { + !scanner()->HasLineTerminatorBeforeNext() && + !scanner()->literal_contains_escapes())) { DCHECK(impl()->IsAsync(impl()->AsIdentifier(result))); int pos = position(); @@ -3128,7 +3204,7 @@ ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression() { result = ParseNewTargetExpression(); return ParseMemberExpressionContinuation(result); } else { - result = ParseMemberWithNewPrefixesExpression(); + result = ParseMemberExpression(); } if (peek() == Token::LPAREN) { // NewExpression with arguments. @@ -3153,13 +3229,6 @@ ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression() { template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseMemberWithNewPrefixesExpression() { - return peek() == Token::NEW ? ParseMemberWithPresentNewPrefixesExpression() - : ParseMemberExpression(); -} - -template <typename Impl> -typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseFunctionExpression() { Consume(Token::FUNCTION); int function_token_position = position(); @@ -3207,22 +3276,11 @@ ParserBase<Impl>::ParseMemberExpression() { // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)* // // The '[' Expression ']' and '.' Identifier parts are parsed by - // ParseMemberExpressionContinuation, and the Arguments part is parsed by the - // caller. + // ParseMemberExpressionContinuation, and everything preceeding it is merged + // into ParsePrimaryExpression. // Parse the initial primary or function expression. - ExpressionT result; - if (peek() == Token::FUNCTION) { - result = ParseFunctionExpression(); - } else if (peek() == Token::SUPER) { - const bool is_new = false; - result = ParseSuperExpression(is_new); - } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT) { - result = ParseImportExpressions(); - } else { - result = ParsePrimaryExpression(); - } - + ExpressionT result = ParsePrimaryExpression(); return ParseMemberExpressionContinuation(result); } @@ -3233,8 +3291,9 @@ ParserBase<Impl>::ParseImportExpressions() { Consume(Token::IMPORT); int pos = position(); - if (allow_harmony_import_meta() && peek() == Token::PERIOD) { - ExpectMetaProperty(ast_value_factory()->meta_string(), "import.meta", pos); + if (allow_harmony_import_meta() && Check(Token::PERIOD)) { + ExpectContextualKeyword(ast_value_factory()->meta_string(), "import.meta", + pos); if (!parsing_module_) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kImportMetaOutsideModule); @@ -3267,7 +3326,15 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( if (IsConciseMethod(kind) || IsAccessorFunction(kind) || IsClassConstructor(kind)) { if (Token::IsProperty(peek())) { + if (peek() == Token::PERIOD && PeekAhead() == Token::PRIVATE_NAME) { + Consume(Token::PERIOD); + Consume(Token::PRIVATE_NAME); + + impl()->ReportMessage(MessageTemplate::kUnexpectedPrivateField); + return impl()->FailureExpression(); + } scope->RecordSuperPropertyUsage(); + UseThis(); return impl()->NewSuperPropertyReference(pos); } // new super() is never allowed. @@ -3275,6 +3342,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( if (!is_new && peek() == Token::LPAREN && IsDerivedConstructor(kind)) { // TODO(rossberg): This might not be the correct FunctionState for the // method here. + expression_scope()->RecordThisUse(); + UseThis()->set_maybe_assigned(); return impl()->NewSuperCallReference(pos); } } @@ -3285,22 +3354,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( } template <typename Impl> -void ParserBase<Impl>::ExpectMetaProperty(const AstRawString* property_name, - const char* full_name, int pos) { - Consume(Token::PERIOD); - ExpectContextualKeyword(property_name); - if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { - impl()->ReportMessageAt(Scanner::Location(pos, end_position()), - MessageTemplate::kInvalidEscapedMetaProperty, - full_name); - } -} - -template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseNewTargetExpression() { int pos = position(); - ExpectMetaProperty(ast_value_factory()->target_string(), "new.target", pos); + Consume(Token::PERIOD); + ExpectContextualKeyword(ast_value_factory()->target_string(), "new.target", + pos); if (!GetReceiverScope()->is_function_scope()) { impl()->ReportMessageAt(scanner()->location(), @@ -3363,6 +3422,7 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters) { // BindingElement[?Yield, ?GeneratorParameter] FuncNameInferrerState fni_state(&fni_); int pos = peek_position(); + auto declaration_it = scope()->declarations()->end(); ExpressionT pattern = ParseBindingPattern(); if (impl()->IsIdentifier(pattern)) { ClassifyParameter(impl()->AsIdentifier(pattern), pos, end_position()); @@ -3379,11 +3439,17 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters) { return; } - AcceptINScope scope(this, true); + AcceptINScope accept_in_scope(this, true); initializer = ParseAssignmentExpression(); impl()->SetFunctionNameFromIdentifierRef(initializer, pattern); } + auto declaration_end = scope()->declarations()->end(); + int initializer_end = end_position(); + for (; declaration_it != declaration_end; ++declaration_it) { + declaration_it->var()->set_initializer_position(initializer_end); + } + impl()->AddFormalParameter(parameters, pattern, initializer, end_position(), parameters->has_rest); } @@ -3473,6 +3539,11 @@ void ParserBase<Impl>::ParseVariableDeclarations( VariableDeclarationParsingScope declaration( impl(), parsing_result->descriptor.mode, names); + Scope* target_scope = IsLexicalVariableMode(parsing_result->descriptor.mode) + ? scope() + : scope()->GetDeclarationScope(); + + auto declaration_it = target_scope->declarations()->end(); int bindings_start = peek_position(); do { @@ -3480,17 +3551,44 @@ void ParserBase<Impl>::ParseVariableDeclarations( FuncNameInferrerState fni_state(&fni_); int decl_pos = peek_position(); - ExpressionT pattern = ParseBindingPattern(); + + IdentifierT name; + ExpressionT pattern; + // Check for an identifier first, so that we can elide the pattern in cases + // where there is no initializer (and so no proxy needs to be created). + if (V8_LIKELY(Token::IsAnyIdentifier(peek()))) { + name = ParseAndClassifyIdentifier(Next()); + if (V8_UNLIKELY(is_strict(language_mode()) && + impl()->IsEvalOrArguments(name))) { + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kStrictEvalArguments); + return; + } + if (peek() == Token::ASSIGN || + (var_context == kForStatement && PeekInOrOf()) || + parsing_result->descriptor.mode == VariableMode::kLet) { + // Assignments need the variable expression for the assignment LHS, and + // for of/in will need it later, so create the expression now. + pattern = impl()->ExpressionFromIdentifier(name, decl_pos); + } else { + // Otherwise, elide the variable expression and just declare it. + impl()->DeclareIdentifier(name, decl_pos); + pattern = impl()->NullExpression(); + } + } else { + name = impl()->NullIdentifier(); + pattern = ParseBindingPattern(); + DCHECK(!impl()->IsIdentifier(pattern)); + } Scanner::Location variable_loc = scanner()->location(); ExpressionT value = impl()->NullExpression(); - int initializer_position = kNoSourcePosition; - int value_beg_position = kNoSourcePosition; + int value_beg_pos = kNoSourcePosition; if (Check(Token::ASSIGN)) { - value_beg_position = peek_position(); - + DCHECK(!impl()->IsNull(pattern)); { + value_beg_pos = peek_position(); AcceptINScope scope(this, var_context != kForStatement); value = ParseAssignmentExpression(); } @@ -3510,18 +3608,36 @@ void ParserBase<Impl>::ParseVariableDeclarations( } impl()->SetFunctionNameFromIdentifierRef(value, pattern); - - // End position of the initializer is after the assignment expression. - initializer_position = end_position(); } else { +#ifdef DEBUG + // We can fall through into here on error paths, so don't DCHECK those. + if (!has_error()) { + // We should never get identifier patterns for the non-initializer path, + // as those expressions should be elided. + DCHECK_EQ(!impl()->IsNull(name), + Token::IsAnyIdentifier(scanner()->current_token())); + DCHECK_IMPLIES(impl()->IsNull(pattern), !impl()->IsNull(name)); + // The only times we have a non-null pattern are: + // 1. This is a destructuring declaration (with no initializer, which + // is immediately an error), + // 2. This is a declaration in a for in/of loop, or + // 3. This is a let (which has an implicit undefined initializer) + DCHECK_IMPLIES( + !impl()->IsNull(pattern), + !impl()->IsIdentifier(pattern) || + (var_context == kForStatement && PeekInOrOf()) || + parsing_result->descriptor.mode == VariableMode::kLet); + } +#endif + if (var_context != kForStatement || !PeekInOrOf()) { // ES6 'const' and binding patterns require initializers. if (parsing_result->descriptor.mode == VariableMode::kConst || - !impl()->IsIdentifier(pattern)) { + impl()->IsNull(name)) { impl()->ReportMessageAt( Scanner::Location(decl_pos, end_position()), MessageTemplate::kDeclarationMissingInitializer, - !impl()->IsIdentifier(pattern) ? "destructuring" : "const"); + impl()->IsNull(name) ? "destructuring" : "const"); return; } // 'let x' initializes 'x' to undefined. @@ -3529,14 +3645,22 @@ void ParserBase<Impl>::ParseVariableDeclarations( value = factory()->NewUndefinedLiteral(position()); } } + } - // End position of the initializer is after the variable. - initializer_position = position(); + int initializer_position = end_position(); + auto declaration_end = target_scope->declarations()->end(); + for (; declaration_it != declaration_end; ++declaration_it) { + declaration_it->var()->set_initializer_position(initializer_position); } - typename DeclarationParsingResult::Declaration decl( - pattern, initializer_position, value); - decl.value_beg_position = value_beg_position; + // Patterns should be elided iff. they don't have an initializer. + DCHECK_IMPLIES(impl()->IsNull(pattern), + impl()->IsNull(value) || + (var_context == kForStatement && PeekInOrOf())); + + typename DeclarationParsingResult::Declaration decl(pattern, value); + decl.value_beg_pos = value_beg_pos; + parsing_result->declarations.push_back(decl); } while (Check(Token::COMMA)); @@ -3617,10 +3741,10 @@ ParserBase<Impl>::ParseHoistableDeclaration( FuncNameInferrerState fni_state(&fni_); impl()->PushEnclosingName(name); - FunctionKind kind = FunctionKindFor(flags); + FunctionKind function_kind = FunctionKindFor(flags); FunctionLiteralT function = impl()->ParseFunctionLiteral( - name, scanner()->location(), name_validity, kind, pos, + name, scanner()->location(), name_validity, function_kind, pos, FunctionLiteral::kDeclaration, language_mode(), nullptr); // In ES6, a function behaves as a lexical binding, except in @@ -3631,16 +3755,17 @@ ParserBase<Impl>::ParseHoistableDeclaration( : VariableMode::kVar; // Async functions don't undergo sloppy mode block scoped hoisting, and don't // allow duplicates in a block. Both are represented by the - // sloppy_block_function_map. Don't add them to the map for async functions. + // sloppy_block_functions_. Don't add them to the map for async functions. // Generators are also supposed to be prohibited; currently doing this behind // a flag and UseCounting violations to assess web compatibility. - bool is_sloppy_block_function = is_sloppy(language_mode()) && - !scope()->is_declaration_scope() && - flags == ParseFunctionFlag::kIsNormal; - - return impl()->DeclareFunction(variable_name, function, mode, pos, - end_position(), is_sloppy_block_function, - names); + VariableKind kind = is_sloppy(language_mode()) && + !scope()->is_declaration_scope() && + flags == ParseFunctionFlag::kIsNormal + ? SLOPPY_BLOCK_FUNCTION_VARIABLE + : NORMAL_VARIABLE; + + return impl()->DeclareFunction(variable_name, function, mode, kind, pos, + end_position(), names); } template <typename Impl> @@ -3716,6 +3841,9 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration( // async [no LineTerminator here] function BindingIdentifier[Await] // ( FormalParameters[Await] ) { AsyncFunctionBody } DCHECK_EQ(scanner()->current_token(), Token::ASYNC); + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD); + } int pos = position(); DCHECK(!scanner()->HasLineTerminatorBeforeNext()); Consume(Token::FUNCTION); @@ -3786,8 +3914,10 @@ void ParserBase<Impl>::ParseFunctionBody( } if (IsDerivedConstructor(kind)) { + ExpressionParsingScope expression_scope(impl()); inner_body.Add(factory()->NewReturnStatement(impl()->ThisExpression(), kNoSourcePosition)); + expression_scope.ValidateExpression(); } Expect(closing_token); } @@ -3797,6 +3927,8 @@ void ParserBase<Impl>::ParseFunctionBody( bool allow_duplicate_parameters = false; + CheckConflictingVarDeclarations(inner_scope); + if (V8_LIKELY(parameters.is_simple)) { DCHECK_EQ(inner_scope, function_scope); if (is_sloppy(function_scope->language_mode())) { @@ -3820,12 +3952,13 @@ void ParserBase<Impl>::ParseFunctionBody( inner_body.Rewind(); inner_body.Add(inner_block); inner_block->set_scope(inner_scope); - const AstRawString* conflict = inner_scope->FindVariableDeclaredIn( - function_scope, VariableMode::kLastLexicalVariableMode); - if (conflict != nullptr) { - impl()->ReportVarRedeclarationIn(conflict, inner_scope); + if (!impl()->HasCheckedSyntax()) { + const AstRawString* conflict = inner_scope->FindVariableDeclaredIn( + function_scope, VariableMode::kLastLexicalVariableMode); + if (conflict != nullptr) { + impl()->ReportVarRedeclarationIn(conflict, inner_scope); + } } - impl()->CheckConflictingVarDeclarations(inner_scope); impl()->InsertShadowingVarBindingInitializers(inner_block); } } @@ -3851,6 +3984,7 @@ void ParserBase<Impl>::CheckArityRestrictions(int param_count, bool has_rest, int formals_start_pos, int formals_end_pos) { + if (impl()->HasCheckedSyntax()) return; if (IsGetterFunction(function_kind)) { if (param_count != 0) { impl()->ReportMessageAt( @@ -3887,6 +4021,8 @@ bool ParserBase<Impl>::IsNextLetKeyword() { // tokens. case Token::YIELD: case Token::AWAIT: + case Token::GET: + case Token::SET: case Token::ASYNC: return true; case Token::FUTURE_STRICT_RESERVED_WORD: @@ -3912,7 +4048,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); DCHECK_IMPLIES(!has_error(), peek() == Token::ARROW); - if (scanner_->HasLineTerminatorBeforeNext()) { + if (!impl()->HasCheckedSyntax() && scanner_->HasLineTerminatorBeforeNext()) { // ASI inserts `;` after arrow parameters if a line terminator is found. // `=> ...` is never a valid expression, so report as syntax error. // If next token is not `=>`, it's a syntax error anyways. @@ -4068,7 +4204,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( bool is_anonymous = impl()->IsNull(name); // All parts of a ClassDeclaration and ClassExpression are strict code. - if (!is_anonymous) { + if (!impl()->HasCheckedSyntax() && !is_anonymous) { if (name_is_strict_reserved) { impl()->ReportMessageAt(class_name_location, MessageTemplate::kUnexpectedStrictReserved); @@ -4167,6 +4303,9 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral() { // async [no LineTerminator here] function BindingIdentifier[Await] // ( FormalParameters[Await] ) { AsyncFunctionBody } DCHECK_EQ(scanner()->current_token(), Token::ASYNC); + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD); + } int pos = position(); Consume(Token::FUNCTION); IdentifierT name = impl()->NullIdentifier(); @@ -4418,9 +4557,9 @@ void ParserBase<Impl>::ParseStatementList(StatementListT* body, Scanner::Location token_loc = scanner()->peek_location(); - if (scanner()->NextLiteralEquals("use strict")) { + if (scanner()->NextLiteralExactlyEquals("use strict")) { use_strict = true; - } else if (scanner()->NextLiteralEquals("use asm")) { + } else if (scanner()->NextLiteralExactlyEquals("use asm")) { use_asm = true; } @@ -4604,7 +4743,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( case Token::VAR: return ParseVariableStatement(kStatement, nullptr); case Token::ASYNC: - if (!scanner()->HasLineTerminatorAfterNext() && + if (!impl()->HasCheckedSyntax() && + !scanner()->HasLineTerminatorAfterNext() && PeekAhead() == Token::FUNCTION) { impl()->ReportMessageAt( scanner()->peek_location(), @@ -4922,7 +5062,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement() { ExpressionT return_value = impl()->NullExpression(); if (scanner()->HasLineTerminatorBeforeNext() || Token::IsAutoSemicolon(tok)) { if (IsDerivedConstructor(function_state_->kind())) { - return_value = impl()->ThisExpression(loc.beg_pos); + ExpressionParsingScope expression_scope(impl()); + return_value = impl()->ThisExpression(); + expression_scope.ValidateExpression(); } } else { return_value = ParseExpression(); @@ -5181,9 +5323,20 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() { } else { catch_info.variable = catch_info.scope->DeclareCatchVariableName( ast_value_factory()->dot_catch_string()); + + auto declaration_it = scope()->declarations()->end(); + VariableDeclarationParsingScope destructuring( impl(), VariableMode::kLet, nullptr); catch_info.pattern = ParseBindingPattern(); + + int initializer_position = end_position(); + auto declaration_end = scope()->declarations()->end(); + for (; declaration_it != declaration_end; ++declaration_it) { + declaration_it->var()->set_initializer_position( + initializer_position); + } + RETURN_IF_PARSE_ERROR; catch_statements.Add(impl()->RewriteCatchPattern(&catch_info)); } @@ -5194,18 +5347,20 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() { catch_statements.Add(inner_block); // Check for `catch(e) { let e; }` and similar errors. - Scope* inner_scope = inner_block->scope(); - if (inner_scope != nullptr) { - const AstRawString* conflict = nullptr; - if (impl()->IsNull(catch_info.pattern)) { - const AstRawString* name = catch_info.variable->raw_name(); - if (inner_scope->LookupLocal(name)) conflict = name; - } else { - conflict = inner_scope->FindVariableDeclaredIn( - scope(), VariableMode::kVar); - } - if (conflict != nullptr) { - impl()->ReportVarRedeclarationIn(conflict, inner_scope); + if (!impl()->HasCheckedSyntax()) { + Scope* inner_scope = inner_block->scope(); + if (inner_scope != nullptr) { + const AstRawString* conflict = nullptr; + if (impl()->IsNull(catch_info.pattern)) { + const AstRawString* name = catch_info.variable->raw_name(); + if (inner_scope->LookupLocal(name)) conflict = name; + } else { + conflict = inner_scope->FindVariableDeclaredIn( + scope(), VariableMode::kVar); + } + if (conflict != nullptr) { + impl()->ReportVarRedeclarationIn(conflict, inner_scope); + } } } @@ -5424,7 +5579,8 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( } impl()->RecordIterationStatementSourceRange(loop, body_range); - DesugarBindingInForEachStatement(for_info, &body_block, &each_variable); + impl()->DesugarBindingInForEachStatement(for_info, &body_block, + &each_variable); body_block->statements()->Add(body, zone()); if (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode)) { @@ -5680,7 +5836,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( if (has_declarations) { BlockT body_block = impl()->NullBlock(); - DesugarBindingInForEachStatement(&for_info, &body_block, &each_variable); + impl()->DesugarBindingInForEachStatement(&for_info, &body_block, + &each_variable); body_block->statements()->Add(body, zone()); body_block->set_scope(scope()->FinalizeBlockScope()); body = body_block; |