%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/parsing/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/parsing/expression-scope.h |
// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_PARSING_EXPRESSION_SCOPE_H_ #define V8_PARSING_EXPRESSION_SCOPE_H_ #include <utility> #include "src/ast/scopes.h" #include "src/common/message-template.h" #include "src/objects/function-kind.h" #include "src/parsing/scanner.h" #include "src/zone/zone.h" // For ScopedPtrList. namespace v8 { namespace internal { template <typename Types> class ExpressionParsingScope; template <typename Types> class AccumulationScope; template <typename Types> class ArrowHeadParsingScope; template <typename Types> class ParameterDeclarationParsingScope; template <typename Types> class VariableDeclarationParsingScope; class VariableProxy; // ExpressionScope is used in a stack fashion, and is used to specialize // expression parsing for the task at hand. It allows the parser to reuse the // same code to parse destructuring declarations, assignment patterns, // expressions, and (async) arrow function heads. // // One of the specific subclasses needs to be instantiated to tell the parser // the meaning of the expression it will parse next. The parser then calls // Record* on the expression_scope() to indicate errors. The expression_scope // will either discard those errors, immediately report those errors, or // classify the errors for later validation. // TODO(verwaest): Record is a slightly odd name since it will directly throw // for unambiguous scopes. template <typename Types> class ExpressionScope { public: ExpressionScope(const ExpressionScope&) = delete; ExpressionScope& operator=(const ExpressionScope&) = delete; using ParserT = typename Types::Impl; using ExpressionT = typename Types::Expression; VariableProxy* NewVariable(const AstRawString* name, int pos = kNoSourcePosition) { VariableProxy* result = parser_->NewRawVariable(name, pos); if (CanBeExpression()) { AsExpressionParsingScope()->TrackVariable(result); } else { Variable* var = Declare(name, pos); if (IsVarDeclaration()) { bool passed_through_with = false; for (Scope* scope = parser()->scope(); !scope->is_declaration_scope(); scope = scope->outer_scope()) { if (scope->is_with_scope()) { passed_through_with = true; } else if (scope->is_catch_scope()) { Variable* masking_var = scope->LookupLocal(name); // If a variable is declared in a catch scope with a masking // catch-declared variable, the initializing assignment is an // assignment to the catch-declared variable instead. // https://tc39.es/ecma262/#sec-variablestatements-in-catch-blocks if (masking_var != nullptr) { result->set_is_assigned(); if (passed_through_with) break; result->BindTo(masking_var); masking_var->SetMaybeAssigned(); return result; } } } if (passed_through_with) { // If a variable is declared in a with scope, the initializing // assignment might target a with-declared variable instead. parser()->scope()->AddUnresolved(result); return result; } } DCHECK_NOT_NULL(var); result->BindTo(var); } return result; } void MergeVariableList( ScopedList<std::pair<VariableProxy*, int>>* variable_list) { if (!CanBeExpression()) return; // Merged variables come from a CanBeDeclaration expression scope, and // weren't added as unresolved references to the variable scope yet. Add // them to the variable scope on the boundary where it becomes clear they // aren't declarations. We explicitly delay declaring the variables up to // that point to avoid trying to add them to the unresolved list multiple // times, e.g., for (((a))). if (!CanBeDeclaration()) { for (auto& proxy_initializer_pair : *variable_list) { VariableProxy* proxy = proxy_initializer_pair.first; this->parser()->scope()->AddUnresolved(proxy); } } variable_list->MergeInto(AsExpressionParsingScope()->variable_list()); } Variable* Declare(const AstRawString* name, int pos = kNoSourcePosition) { if (type_ == kParameterDeclaration) { return AsParameterDeclarationParsingScope()->Declare(name, pos); } return AsVariableDeclarationParsingScope()->Declare(name, pos); } void MarkIdentifierAsAssigned() { if (!CanBeExpression()) return; AsExpressionParsingScope()->MarkIdentifierAsAssigned(); } void ValidateAsPattern(ExpressionT expression, int begin, int end) { if (!CanBeExpression()) return; AsExpressionParsingScope()->ValidatePattern(expression, begin, end); AsExpressionParsingScope()->ClearExpressionError(); } void ValidateAsExpression() { if (!CanBeExpression()) return; AsExpressionParsingScope()->ValidateExpression(); AsExpressionParsingScope()->ClearPatternError(); } // Record async arrow parameters errors in all ambiguous async arrow scopes in // the chain up to the first unambiguous scope. void RecordAsyncArrowParametersError(const Scanner::Location& loc, MessageTemplate message) { // Only ambiguous scopes (ExpressionParsingScope, *ArrowHeadParsingScope) // need to propagate errors to a possible kAsyncArrowHeadParsingScope, so // immediately return if the current scope is not ambiguous. if (!CanBeExpression()) return; AsExpressionParsingScope()->RecordAsyncArrowParametersError(loc, message); } // Record initializer errors in all scopes that can turn into parameter scopes // (ArrowHeadParsingScopes) up to the first known unambiguous parameter scope. void RecordParameterInitializerError(const Scanner::Location& loc, MessageTemplate message) { ExpressionScope* scope = this; while (!scope->IsCertainlyParameterDeclaration()) { if (!has_possible_parameter_in_scope_chain_) return; if (scope->CanBeParameterDeclaration()) { scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); } scope = scope->parent(); if (scope == nullptr) return; } Report(loc, message); } void RecordThisUse() { ExpressionScope* scope = this; do { if (scope->IsArrowHeadParsingScope()) { scope->AsArrowHeadParsingScope()->RecordThisUse(); } scope = scope->parent(); } while (scope != nullptr); } void RecordPatternError(const Scanner::Location& loc, MessageTemplate message) { // TODO(verwaest): Non-assigning expression? if (IsCertainlyPattern()) { Report(loc, message); } else { AsExpressionParsingScope()->RecordPatternError(loc, message); } } void RecordStrictModeParameterError(const Scanner::Location& loc, MessageTemplate message) { DCHECK_IMPLIES(!has_error(), loc.IsValid()); if (!CanBeParameterDeclaration()) return; if (IsCertainlyParameterDeclaration()) { if (is_strict(parser_->language_mode())) { Report(loc, message); } else { parser_->parameters_->set_strict_parameter_error(loc, message); } } else { parser_->next_arrow_function_info_.strict_parameter_error_location = loc; parser_->next_arrow_function_info_.strict_parameter_error_message = message; } } void RecordDeclarationError(const Scanner::Location& loc, MessageTemplate message) { if (!CanBeDeclaration()) return; if (IsCertainlyDeclaration()) { Report(loc, message); } else { AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); } } void RecordExpressionError(const Scanner::Location& loc, MessageTemplate message) { if (!CanBeExpression()) return; // TODO(verwaest): Non-assigning expression? // if (IsCertainlyExpression()) Report(loc, message); AsExpressionParsingScope()->RecordExpressionError(loc, message); } void RecordNonSimpleParameter() { if (!IsArrowHeadParsingScope()) return; AsArrowHeadParsingScope()->RecordNonSimpleParameter(); } bool IsCertainlyDeclaration() const { return base::IsInRange(type_, kParameterDeclaration, kLexicalDeclaration); } int SetInitializers(int variable_index, int peek_position) { if (CanBeExpression()) { return AsExpressionParsingScope()->SetInitializers(variable_index, peek_position); } return variable_index; } bool has_possible_arrow_parameter_in_scope_chain() const { return has_possible_arrow_parameter_in_scope_chain_; } protected: enum ScopeType : uint8_t { // Expression or assignment target. kExpression, // Declaration or expression or assignment target. kMaybeArrowParameterDeclaration, kMaybeAsyncArrowParameterDeclaration, // Declarations. kParameterDeclaration, kVarDeclaration, kLexicalDeclaration, }; ParserT* parser() const { return parser_; } ExpressionScope* parent() const { return parent_; } void Report(const Scanner::Location& loc, MessageTemplate message) const { parser_->ReportMessageAt(loc, message); } ExpressionScope(ParserT* parser, ScopeType type) : parser_(parser), parent_(parser->expression_scope_), type_(type), has_possible_parameter_in_scope_chain_( CanBeParameterDeclaration() || (parent_ && parent_->has_possible_parameter_in_scope_chain_)), has_possible_arrow_parameter_in_scope_chain_( CanBeArrowParameterDeclaration() || (parent_ && parent_->has_possible_arrow_parameter_in_scope_chain_)) { parser->expression_scope_ = this; } ~ExpressionScope() { DCHECK(parser_->expression_scope_ == this || parser_->expression_scope_ == parent_); parser_->expression_scope_ = parent_; } ExpressionParsingScope<Types>* AsExpressionParsingScope() { DCHECK(CanBeExpression()); return static_cast<ExpressionParsingScope<Types>*>(this); } #ifdef DEBUG bool has_error() const { return parser_->has_error(); } #endif bool CanBeExpression() const { return base::IsInRange(type_, kExpression, kMaybeAsyncArrowParameterDeclaration); } bool CanBeDeclaration() const { return base::IsInRange(type_, kMaybeArrowParameterDeclaration, kLexicalDeclaration); } bool IsVariableDeclaration() const { return base::IsInRange(type_, kVarDeclaration, kLexicalDeclaration); } bool IsLexicalDeclaration() const { return type_ == kLexicalDeclaration; } bool IsAsyncArrowHeadParsingScope() const { return type_ == kMaybeAsyncArrowParameterDeclaration; } bool IsVarDeclaration() const { return type_ == kVarDeclaration; } private: friend class AccumulationScope<Types>; friend class ExpressionParsingScope<Types>; ArrowHeadParsingScope<Types>* AsArrowHeadParsingScope() { DCHECK(IsArrowHeadParsingScope()); return static_cast<ArrowHeadParsingScope<Types>*>(this); } ParameterDeclarationParsingScope<Types>* AsParameterDeclarationParsingScope() { DCHECK(IsCertainlyParameterDeclaration()); return static_cast<ParameterDeclarationParsingScope<Types>*>(this); } VariableDeclarationParsingScope<Types>* AsVariableDeclarationParsingScope() { DCHECK(IsVariableDeclaration()); return static_cast<VariableDeclarationParsingScope<Types>*>(this); } bool IsArrowHeadParsingScope() const { return base::IsInRange(type_, kMaybeArrowParameterDeclaration, kMaybeAsyncArrowParameterDeclaration); } bool IsCertainlyPattern() const { return IsCertainlyDeclaration(); } bool CanBeParameterDeclaration() const { return base::IsInRange(type_, kMaybeArrowParameterDeclaration, kParameterDeclaration); } bool CanBeArrowParameterDeclaration() const { return base::IsInRange(type_, kMaybeArrowParameterDeclaration, kMaybeAsyncArrowParameterDeclaration); } bool IsCertainlyParameterDeclaration() const { return type_ == kParameterDeclaration; } ParserT* parser_; ExpressionScope<Types>* parent_; ScopeType type_; bool has_possible_parameter_in_scope_chain_; bool has_possible_arrow_parameter_in_scope_chain_; }; // Used to unambiguously parse var, let, const declarations. template <typename Types> class VariableDeclarationParsingScope : public ExpressionScope<Types> { public: using ParserT = typename Types::Impl; using ExpressionScopeT = ExpressionScope<Types>; using ScopeType = typename ExpressionScopeT::ScopeType; VariableDeclarationParsingScope(ParserT* parser, VariableMode mode, ZonePtrList<const AstRawString>* names) : ExpressionScopeT(parser, IsLexicalVariableMode(mode) ? ExpressionScopeT::kLexicalDeclaration : ExpressionScopeT::kVarDeclaration), mode_(mode), names_(names) {} VariableDeclarationParsingScope(const VariableDeclarationParsingScope&) = delete; VariableDeclarationParsingScope& operator=( const VariableDeclarationParsingScope&) = delete; Variable* Declare(const AstRawString* name, int pos) { VariableKind kind = NORMAL_VARIABLE; bool was_added; Variable* var = this->parser()->DeclareVariable( name, kind, mode_, Variable::DefaultInitializationFlag(mode_), this->parser()->scope(), &was_added, pos); if (was_added && this->parser()->scope()->num_var() > kMaxNumFunctionLocals) { this->parser()->ReportMessage(MessageTemplate::kTooManyVariables); } if (names_) names_->Add(name, this->parser()->zone()); if (this->IsLexicalDeclaration()) { if (this->parser()->IsLet(name)) { this->parser()->ReportMessageAt( Scanner::Location(pos, pos + name->length()), MessageTemplate::kLetInLexicalBinding); } } else { if (this->parser()->loop_nesting_depth() > 0) { // Due to hoisting, the value of a 'var'-declared variable may actually // change even if the code contains only the "initial" assignment, // namely when that assignment occurs inside a loop. For example: // // let i = 10; // do { var x = i } while (i--): // // Note that non-lexical variables include temporaries, which may also // get assigned inside a loop due to the various rewritings that the // parser performs. // // Pessimistically mark all vars in loops as assigned. This // overapproximates the actual assigned vars due to unassigned var // without initializer, but that's unlikely anyway. // // This also handles marking of loop variables in for-in and for-of // loops, as determined by loop-nesting-depth. DCHECK_NOT_NULL(var); var->SetMaybeAssigned(); } } return var; } private: // Limit the allowed number of local variables in a function. The hard limit // in Ignition is 2^31-1 due to the size of register operands. We limit it to // a more reasonable lower up-limit. static const int kMaxNumFunctionLocals = (1 << 23) - 1; VariableMode mode_; ZonePtrList<const AstRawString>* names_; }; template <typename Types> class ParameterDeclarationParsingScope : public ExpressionScope<Types> { public: using ParserT = typename Types::Impl; using ExpressionScopeT = ExpressionScope<Types>; using ScopeType = typename ExpressionScopeT::ScopeType; explicit ParameterDeclarationParsingScope(ParserT* parser) : ExpressionScopeT(parser, ExpressionScopeT::kParameterDeclaration) {} ParameterDeclarationParsingScope(const ParameterDeclarationParsingScope&) = delete; ParameterDeclarationParsingScope& operator=( const ParameterDeclarationParsingScope&) = delete; Variable* Declare(const AstRawString* name, int pos) { VariableKind kind = PARAMETER_VARIABLE; VariableMode mode = VariableMode::kVar; bool was_added; Variable* var = this->parser()->DeclareVariable( name, kind, mode, Variable::DefaultInitializationFlag(mode), this->parser()->scope(), &was_added, pos); if (!has_duplicate() && !was_added) { duplicate_loc_ = Scanner::Location(pos, pos + name->length()); } return var; } bool has_duplicate() const { return duplicate_loc_.IsValid(); } const Scanner::Location& duplicate_location() const { return duplicate_loc_; } private: Scanner::Location duplicate_loc_ = Scanner::Location::invalid(); }; // Parsing expressions is always ambiguous between at least left-hand-side and // right-hand-side of assignments. This class is used to keep track of errors // relevant for either side until it is clear what was being parsed. // The class also keeps track of all variable proxies that are created while the // scope was active. If the scope is an expression, the variable proxies will be // added to the unresolved list. Otherwise they are declarations and aren't // added. The list is also used to mark the variables as assigned in case we are // parsing an assignment expression. template <typename Types> class ExpressionParsingScope : public ExpressionScope<Types> { public: using ParserT = typename Types::Impl; using ExpressionT = typename Types::Expression; using ExpressionScopeT = ExpressionScope<Types>; using ScopeType = typename ExpressionScopeT::ScopeType; explicit ExpressionParsingScope( ParserT* parser, ScopeType type = ExpressionScopeT::kExpression) : ExpressionScopeT(parser, type), variable_list_(parser->variable_buffer()), has_async_arrow_in_scope_chain_( type == ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration || (this->parent() && this->parent()->CanBeExpression() && this->parent() ->AsExpressionParsingScope() ->has_async_arrow_in_scope_chain_)) { DCHECK(this->CanBeExpression()); clear(kExpressionIndex); clear(kPatternIndex); } ExpressionParsingScope(const ExpressionParsingScope&) = delete; ExpressionParsingScope& operator=(const ExpressionParsingScope&) = delete; void RecordAsyncArrowParametersError(const Scanner::Location& loc, MessageTemplate message) { for (ExpressionScopeT* scope = this; scope != nullptr; scope = scope->parent()) { if (!has_async_arrow_in_scope_chain_) break; if (scope->type_ == ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration) { scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); } } } ~ExpressionParsingScope() { DCHECK(this->has_error() || verified_); } ExpressionT ValidateAndRewriteReference(ExpressionT expression, int beg_pos, int end_pos) { if (V8_LIKELY(this->parser()->IsAssignableIdentifier(expression))) { MarkIdentifierAsAssigned(); this->mark_verified(); return expression; } else if (V8_LIKELY(expression->IsProperty())) { ValidateExpression(); return expression; } this->mark_verified(); const bool early_error = false; return this->parser()->RewriteInvalidReferenceExpression( expression, beg_pos, end_pos, MessageTemplate::kInvalidLhsInFor, early_error); } void RecordExpressionError(const Scanner::Location& loc, MessageTemplate message) { Record(kExpressionIndex, loc, message); } void RecordPatternError(const Scanner::Location& loc, MessageTemplate message) { Record(kPatternIndex, loc, message); } void ValidateExpression() { Validate(kExpressionIndex); } void ValidatePattern(ExpressionT expression, int begin, int end) { Validate(kPatternIndex); if (expression->is_parenthesized()) { ExpressionScopeT::Report(Scanner::Location(begin, end), MessageTemplate::kInvalidDestructuringTarget); } for (auto& variable_initializer_pair : variable_list_) { variable_initializer_pair.first->set_is_assigned(); } } void ClearExpressionError() { DCHECK(verified_); #ifdef DEBUG verified_ = false; #endif clear(kExpressionIndex); } void ClearPatternError() { DCHECK(verified_); #ifdef DEBUG verified_ = false; #endif clear(kPatternIndex); } void TrackVariable(VariableProxy* variable) { if (!this->CanBeDeclaration()) { this->parser()->scope()->AddUnresolved(variable); } variable_list_.Add({variable, kNoSourcePosition}); } void MarkIdentifierAsAssigned() { // It's possible we're parsing a syntax error. In that case it's not // guaranteed that there's a variable in the list. if (variable_list_.length() == 0) return; variable_list_.at(variable_list_.length() - 1).first->set_is_assigned(); } int SetInitializers(int first_variable_index, int position) { int len = variable_list_.length(); if (len == 0) return 0; int end = len - 1; // Loop backwards and abort as soon as we see one that's already set to // avoid a loop on expressions like a,b,c,d,e,f,g (outside of an arrowhead). // TODO(delphick): Look into removing this loop. for (int i = end; i >= first_variable_index && variable_list_.at(i).second == kNoSourcePosition; --i) { variable_list_.at(i).second = position; } return end; } ScopedList<std::pair<VariableProxy*, int>>* variable_list() { return &variable_list_; } protected: bool is_verified() const { #ifdef DEBUG return verified_; #else return false; #endif } void ValidatePattern() { Validate(kPatternIndex); } private: friend class AccumulationScope<Types>; enum ErrorNumber : uint8_t { kExpressionIndex = 0, kPatternIndex = 1, kNumberOfErrors = 2, }; void clear(int index) { messages_[index] = MessageTemplate::kNone; locations_[index] = Scanner::Location::invalid(); } bool is_valid(int index) const { return !locations_[index].IsValid(); } void Record(int index, const Scanner::Location& loc, MessageTemplate message) { DCHECK_IMPLIES(!this->has_error(), loc.IsValid()); if (!is_valid(index)) return; messages_[index] = message; locations_[index] = loc; } void Validate(int index) { DCHECK(!this->is_verified()); if (!is_valid(index)) Report(index); this->mark_verified(); } void Report(int index) const { ExpressionScopeT::Report(locations_[index], messages_[index]); } // Debug verification to make sure every scope is validated exactly once. void mark_verified() { #ifdef DEBUG verified_ = true; #endif } void clear_verified() { #ifdef DEBUG verified_ = false; #endif } #ifdef DEBUG bool verified_ = false; #endif ScopedList<std::pair<VariableProxy*, int>> variable_list_; MessageTemplate messages_[kNumberOfErrors]; Scanner::Location locations_[kNumberOfErrors]; bool has_async_arrow_in_scope_chain_; }; // This class is used to parse multiple ambiguous expressions and declarations // in the same scope. E.g., in async(X,Y,Z) or [X,Y,Z], X and Y and Z will all // be parsed in the respective outer ArrowHeadParsingScope and // ExpressionParsingScope. It provides a clean error state in the underlying // scope to parse the individual expressions, while keeping track of the // expression and pattern errors since the start. The AccumulationScope is only // used to keep track of the errors so far, and the underlying ExpressionScope // keeps being used as the expression_scope(). If the expression_scope() isn't // ambiguous, this class does not do anything. template <typename Types> class AccumulationScope { public: using ParserT = typename Types::Impl; static const int kNumberOfErrors = ExpressionParsingScope<Types>::kNumberOfErrors; explicit AccumulationScope(ExpressionScope<Types>* scope) : scope_(nullptr) { if (!scope->CanBeExpression()) return; scope_ = scope->AsExpressionParsingScope(); for (int i = 0; i < kNumberOfErrors; i++) { copy(i); scope_->clear(i); } } AccumulationScope(const AccumulationScope&) = delete; AccumulationScope& operator=(const AccumulationScope&) = delete; // Merge errors from the underlying ExpressionParsingScope into this scope. // Only keeps the first error across all accumulate calls, and removes the // error from the underlying scope. void Accumulate() { if (scope_ == nullptr) return; DCHECK(!scope_->is_verified()); for (int i = 0; i < kNumberOfErrors; i++) { if (!locations_[i].IsValid()) copy(i); scope_->clear(i); } } // This is called instead of Accumulate in case the parsed member is already // known to be an expression. In that case we don't need to accumulate the // expression but rather validate it immediately. We also ignore the pattern // error since the parsed member is known to not be a pattern. This is // necessary for "{x:1}.y" parsed as part of an assignment pattern. {x:1} will // record a pattern error, but "{x:1}.y" is actually a valid as part of an // assignment pattern since it's a property access. void ValidateExpression() { if (scope_ == nullptr) return; DCHECK(!scope_->is_verified()); scope_->ValidateExpression(); DCHECK(scope_->is_verified()); scope_->clear(ExpressionParsingScope<Types>::kPatternIndex); #ifdef DEBUG scope_->clear_verified(); #endif } ~AccumulationScope() { if (scope_ == nullptr) return; Accumulate(); for (int i = 0; i < kNumberOfErrors; i++) copy_back(i); } private: void copy(int entry) { messages_[entry] = scope_->messages_[entry]; locations_[entry] = scope_->locations_[entry]; } void copy_back(int entry) { if (!locations_[entry].IsValid()) return; scope_->messages_[entry] = messages_[entry]; scope_->locations_[entry] = locations_[entry]; } ExpressionParsingScope<Types>* scope_; MessageTemplate messages_[2]; Scanner::Location locations_[2]; }; // The head of an arrow function is ambiguous between expression, assignment // pattern and declaration. This keeps track of the additional declaration // error and allows the scope to be validated as a declaration rather than an // expression or a pattern. template <typename Types> class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { public: using ParserT = typename Types::Impl; using ScopeType = typename ExpressionScope<Types>::ScopeType; ArrowHeadParsingScope(ParserT* parser, FunctionKind kind) : ExpressionParsingScope<Types>( parser, kind == FunctionKind::kArrowFunction ? ExpressionScope<Types>::kMaybeArrowParameterDeclaration : ExpressionScope< Types>::kMaybeAsyncArrowParameterDeclaration) { DCHECK(kind == FunctionKind::kAsyncArrowFunction || kind == FunctionKind::kArrowFunction); DCHECK(this->CanBeDeclaration()); DCHECK(!this->IsCertainlyDeclaration()); // clear last next_arrow_function_info tracked strict parameters error. parser->next_arrow_function_info_.ClearStrictParameterError(); } ArrowHeadParsingScope(const ArrowHeadParsingScope&) = delete; ArrowHeadParsingScope& operator=(const ArrowHeadParsingScope&) = delete; void ValidateExpression() { // Turns out this is not an arrow head. Clear any possible tracked strict // parameter errors, and reinterpret tracked variables as unresolved // references. this->parser()->next_arrow_function_info_.ClearStrictParameterError(); ExpressionParsingScope<Types>::ValidateExpression(); this->parent()->MergeVariableList(this->variable_list()); } DeclarationScope* ValidateAndCreateScope() { DCHECK(!this->is_verified()); DeclarationScope* result = this->parser()->NewFunctionScope(kind()); if (declaration_error_location.IsValid()) { ExpressionScope<Types>::Report(declaration_error_location, declaration_error_message); return result; } this->ValidatePattern(); if (!has_simple_parameter_list_) result->SetHasNonSimpleParameters(); VariableKind kind = PARAMETER_VARIABLE; VariableMode mode = has_simple_parameter_list_ ? VariableMode::kVar : VariableMode::kLet; for (auto& proxy_initializer_pair : *this->variable_list()) { VariableProxy* proxy = proxy_initializer_pair.first; int initializer_position = proxy_initializer_pair.second; // Default values for parameters will have been parsed as assignments so // clear the is_assigned bit as they are not actually assignments. proxy->clear_is_assigned(); bool was_added; this->parser()->DeclareAndBindVariable(proxy, kind, mode, result, &was_added, initializer_position); if (!was_added) { ExpressionScope<Types>::Report(proxy->location(), MessageTemplate::kParamDupe); } } #ifdef DEBUG if (!this->has_error()) { for (auto declaration : *result->declarations()) { DCHECK_NE(declaration->var()->initializer_position(), kNoSourcePosition); } } #endif // DEBUG if (uses_this_) result->UsesThis(); return result; } void RecordDeclarationError(const Scanner::Location& loc, MessageTemplate message) { DCHECK_IMPLIES(!this->has_error(), loc.IsValid()); declaration_error_location = loc; declaration_error_message = message; } void RecordNonSimpleParameter() { has_simple_parameter_list_ = false; } void RecordThisUse() { uses_this_ = true; } private: FunctionKind kind() const { return this->IsAsyncArrowHeadParsingScope() ? FunctionKind::kAsyncArrowFunction : FunctionKind::kArrowFunction; } Scanner::Location declaration_error_location = Scanner::Location::invalid(); MessageTemplate declaration_error_message = MessageTemplate::kNone; bool has_simple_parameter_list_ = true; bool uses_this_ = false; }; } // namespace internal } // namespace v8 #endif // V8_PARSING_EXPRESSION_SCOPE_H_