diff options
Diffstat (limited to 'deps/v8/src/parsing/expression-scope.h')
-rw-r--r-- | deps/v8/src/parsing/expression-scope.h | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/deps/v8/src/parsing/expression-scope.h b/deps/v8/src/parsing/expression-scope.h new file mode 100644 index 0000000000..878cb3cf25 --- /dev/null +++ b/deps/v8/src/parsing/expression-scope.h @@ -0,0 +1,710 @@ +// 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 "src/ast/scopes.h" +#include "src/message-template.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: + typedef typename Types::Impl ParserT; + typedef typename Types::Expression ExpressionT; + + VariableProxy* NewVariable(const AstRawString* name, + int pos = kNoSourcePosition) { + VariableProxy* result = parser_->NewRawVariable(name, pos); + if (CanBeExpression()) { + AsExpressionParsingScope()->TrackVariable(result); + } else if (type_ == kParameterDeclaration) { + AsParameterDeclarationParsingScope()->Declare(result); + } else { + return AsVariableDeclarationParsingScope()->Declare(result); + } + return result; + } + + 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(); + } + + // 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 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 RecordLexicalDeclarationError(const Scanner::Location& loc, + MessageTemplate message) { + if (IsLexicalDeclaration()) Report(loc, message); + } + + void RecordNonSimpleParameter() { + if (!IsArrowHeadParsingScope()) return; + AsArrowHeadParsingScope()->RecordNonSimpleParameter(); + } + + 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_)) { + 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 IsInRange(type_, kExpression, kMaybeAsyncArrowParameterDeclaration); + } + bool CanBeDeclaration() const { + return IsInRange(type_, kMaybeArrowParameterDeclaration, + kLexicalDeclaration); + } + bool IsCertainlyDeclaration() const { + return IsInRange(type_, kParameterDeclaration, kLexicalDeclaration); + } + bool IsVariableDeclaration() const { + return IsInRange(type_, kVarDeclaration, kLexicalDeclaration); + } + bool IsLexicalDeclaration() const { return type_ == kLexicalDeclaration; } + bool IsAsyncArrowHeadParsingScope() const { + return type_ == kMaybeAsyncArrowParameterDeclaration; + } + + 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 IsInRange(type_, kMaybeArrowParameterDeclaration, + kMaybeAsyncArrowParameterDeclaration); + } + bool IsCertainlyPattern() const { return IsCertainlyDeclaration(); } + bool CanBeParameterDeclaration() const { + return IsInRange(type_, kMaybeArrowParameterDeclaration, + kParameterDeclaration); + } + bool IsCertainlyParameterDeclaration() const { + return type_ == kParameterDeclaration; + } + + ParserT* parser_; + ExpressionScope<Types>* parent_; + ScopeType type_; + bool has_possible_parameter_in_scope_chain_; + + DISALLOW_COPY_AND_ASSIGN(ExpressionScope); +}; + +// Used to unambiguously parse var, let, const declarations. +template <typename Types> +class VariableDeclarationParsingScope : public ExpressionScope<Types> { + public: + typedef typename Types::Impl ParserT; + typedef class ExpressionScope<Types> ExpressionScopeT; + typedef typename ExpressionScopeT::ScopeType ScopeType; + + VariableDeclarationParsingScope(ParserT* parser, VariableMode mode, + ZonePtrList<const AstRawString>* names) + : ExpressionScopeT(parser, IsLexicalVariableMode(mode) + ? ExpressionScopeT::kLexicalDeclaration + : ExpressionScopeT::kVarDeclaration), + mode_(mode), + names_(names) {} + + VariableProxy* Declare(VariableProxy* proxy) { + VariableKind kind = NORMAL_VARIABLE; + bool was_added; + this->parser()->DeclareVariable( + proxy, kind, mode_, Variable::DefaultInitializationFlag(mode_), + this->parser()->scope(), &was_added, proxy->position()); + if (was_added && + this->parser()->scope()->num_var() > kMaxNumFunctionLocals) { + this->parser()->ReportMessage(MessageTemplate::kTooManyVariables); + } + if (names_) names_->Add(proxy->raw_name(), this->parser()->zone()); + if (this->IsLexicalDeclaration()) { + if (this->parser()->IsLet(proxy->raw_name())) { + this->parser()->ReportMessageAt(proxy->location(), + 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. + proxy->set_is_assigned(); + } + + // Make sure we'll properly resolve the variable since we might be in a + // with or catch scope. In those cases the assignment isn't guaranteed to + // write to the variable declared above. + if (!this->parser()->scope()->is_declaration_scope()) { + proxy = + this->parser()->NewUnresolved(proxy->raw_name(), proxy->position()); + } + } + return proxy; + } + + 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_; + + DISALLOW_COPY_AND_ASSIGN(VariableDeclarationParsingScope); +}; + +template <typename Types> +class ParameterDeclarationParsingScope : public ExpressionScope<Types> { + public: + typedef typename Types::Impl ParserT; + typedef class ExpressionScope<Types> ExpressionScopeT; + typedef typename ExpressionScopeT::ScopeType ScopeType; + + explicit ParameterDeclarationParsingScope(ParserT* parser) + : ExpressionScopeT(parser, ExpressionScopeT::kParameterDeclaration) {} + + void Declare(VariableProxy* proxy) { + VariableKind kind = PARAMETER_VARIABLE; + VariableMode mode = VariableMode::kVar; + bool was_added; + this->parser()->DeclareVariable( + proxy, kind, mode, Variable::DefaultInitializationFlag(mode), + this->parser()->scope(), &was_added, proxy->position()); + if (!has_duplicate() && !was_added) { + duplicate_loc_ = proxy->location(); + } + } + + 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(); + DISALLOW_COPY_AND_ASSIGN(ParameterDeclarationParsingScope); +}; + +// 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: + typedef typename Types::Impl ParserT; + typedef typename Types::Expression ExpressionT; + typedef class ExpressionScope<Types> ExpressionScopeT; + typedef typename ExpressionScopeT::ScopeType ScopeType; + + 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); + } + + 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(); + return this->parser()->RewriteInvalidReferenceExpression( + expression, beg_pos, end_pos, MessageTemplate::kInvalidLhsInFor, + kSyntaxError); + } + + 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 (int i = 0; i < variable_list_.length(); i++) { + variable_list_.at(i)->set_is_assigned(); + } + } + + void ClearExpressionError() { + DCHECK(verified_); +#ifdef DEBUG + verified_ = false; +#endif + clear(kExpressionIndex); + } + + void TrackVariable(VariableProxy* variable) { + if (!this->CanBeDeclaration()) { + this->parser()->scope()->AddUnresolved(variable); + } + variable_list_.Add(variable); + } + + 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)->set_is_assigned(); + } + + protected: + bool is_verified() const { +#ifdef DEBUG + return verified_; +#else + return false; +#endif + } + + void ValidatePattern() { Validate(kPatternIndex); } + + ScopedPtrList<VariableProxy>* variable_list() { return &variable_list_; } + + 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 + + ScopedPtrList<VariableProxy> variable_list_; + MessageTemplate messages_[kNumberOfErrors]; + Scanner::Location locations_[kNumberOfErrors]; + bool has_async_arrow_in_scope_chain_; + + DISALLOW_COPY_AND_ASSIGN(ExpressionParsingScope); +}; + +// 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: + typedef typename Types::Impl ParserT; + + 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++) { + // If the underlying scope is already invalid at the start, stop + // accumulating. That means an error was found outside of an + // accumulating path. + if (!scope_->is_valid(i)) { + scope_ = nullptr; + break; + } + copy(i); + } + } + + // 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]; + + DISALLOW_COPY_AND_ASSIGN(AccumulationScope); +}; + +// 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: + typedef typename Types::Impl ParserT; + typedef typename ExpressionScope<Types>::ScopeType 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()); + } + + 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(); + for (int i = 0; i < this->variable_list()->length(); i++) { + this->parser()->scope()->AddUnresolved(this->variable_list()->at(i)); + } + } + + DeclarationScope* ValidateAndCreateScope() { + DCHECK(!this->is_verified()); + if (declaration_error_location.IsValid()) { + ExpressionScope<Types>::Report(declaration_error_location, + declaration_error_message); + } + this->ValidatePattern(); + + DeclarationScope* result = this->parser()->NewFunctionScope(kind()); + if (!has_simple_parameter_list_) result->SetHasNonSimpleParameters(); + VariableKind kind = PARAMETER_VARIABLE; + VariableMode mode = + has_simple_parameter_list_ ? VariableMode::kVar : VariableMode::kLet; + for (int i = 0; i < this->variable_list()->length(); i++) { + VariableProxy* proxy = this->variable_list()->at(i); + bool was_added; + this->parser()->DeclareVariable(proxy, kind, mode, + Variable::DefaultInitializationFlag(mode), + result, &was_added, proxy->position()); + if (!was_added) { + ExpressionScope<Types>::Report(proxy->location(), + MessageTemplate::kParamDupe); + } + } + 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; } + + 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; + + DISALLOW_COPY_AND_ASSIGN(ArrowHeadParsingScope); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_PARSING_EXPRESSION_SCOPE_H_ |