1 // Copyright 2018 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_PARSING_EXPRESSION_SCOPE_H_ 6 #define V8_PARSING_EXPRESSION_SCOPE_H_ 7 8 #include <utility> 9 10 #include "src/ast/scopes.h" 11 #include "src/common/message-template.h" 12 #include "src/objects/function-kind.h" 13 #include "src/parsing/scanner.h" 14 #include "src/zone/zone.h" // For ScopedPtrList. 15 16 namespace v8 { 17 namespace internal { 18 19 template <typename Types> 20 class ExpressionParsingScope; 21 template <typename Types> 22 class AccumulationScope; 23 template <typename Types> 24 class ArrowHeadParsingScope; 25 template <typename Types> 26 class ParameterDeclarationParsingScope; 27 template <typename Types> 28 class VariableDeclarationParsingScope; 29 class VariableProxy; 30 31 // ExpressionScope is used in a stack fashion, and is used to specialize 32 // expression parsing for the task at hand. It allows the parser to reuse the 33 // same code to parse destructuring declarations, assignment patterns, 34 // expressions, and (async) arrow function heads. 35 // 36 // One of the specific subclasses needs to be instantiated to tell the parser 37 // the meaning of the expression it will parse next. The parser then calls 38 // Record* on the expression_scope() to indicate errors. The expression_scope 39 // will either discard those errors, immediately report those errors, or 40 // classify the errors for later validation. 41 // TODO(verwaest): Record is a slightly odd name since it will directly throw 42 // for unambiguous scopes. 43 template <typename Types> 44 class ExpressionScope { 45 public: 46 using ParserT = typename Types::Impl; 47 using ExpressionT = typename Types::Expression; 48 49 VariableProxy* NewVariable(const AstRawString* name, 50 int pos = kNoSourcePosition) { 51 VariableProxy* result = parser_->NewRawVariable(name, pos); 52 if (CanBeExpression()) { 53 AsExpressionParsingScope()->TrackVariable(result); 54 } else { 55 Variable* var = Declare(name, pos); 56 if (IsVarDeclaration()) { 57 bool passed_through_with = false; 58 for (Scope* scope = parser()->scope(); !scope->is_declaration_scope(); 59 scope = scope->outer_scope()) { 60 if (scope->is_with_scope()) { 61 passed_through_with = true; 62 } else if (scope->is_catch_scope()) { 63 Variable* var = scope->LookupLocal(name); 64 // If a variable is declared in a catch scope with a masking 65 // catch-declared variable, the initializing assignment is an 66 // assignment to the catch-declared variable instead. 67 // https://tc39.es/ecma262/#sec-variablestatements-in-catch-blocks 68 if (var != nullptr) { 69 result->set_is_assigned(); 70 if (passed_through_with) break; 71 result->BindTo(var); 72 var->SetMaybeAssigned(); 73 return result; 74 } 75 } 76 } 77 if (passed_through_with) { 78 // If a variable is declared in a with scope, the initializing 79 // assignment might target a with-declared variable instead. 80 parser()->scope()->AddUnresolved(result); 81 return result; 82 } 83 } 84 DCHECK_NOT_NULL(var); 85 result->BindTo(var); 86 } 87 return result; 88 } 89 MergeVariableList(ScopedList<std::pair<VariableProxy *,int>> * variable_list)90 void MergeVariableList( 91 ScopedList<std::pair<VariableProxy*, int>>* variable_list) { 92 if (!CanBeExpression()) return; 93 // Merged variables come from a CanBeDeclaration expression scope, and 94 // weren't added as unresolved references to the variable scope yet. Add 95 // them to the variable scope on the boundary where it becomes clear they 96 // aren't declarations. We explicitly delay declaring the variables up to 97 // that point to avoid trying to add them to the unresolved list multiple 98 // times, e.g., for (((a))). 99 if (!CanBeDeclaration()) { 100 for (auto& proxy_initializer_pair : *variable_list) { 101 VariableProxy* proxy = proxy_initializer_pair.first; 102 this->parser()->scope()->AddUnresolved(proxy); 103 } 104 } 105 variable_list->MergeInto(AsExpressionParsingScope()->variable_list()); 106 } 107 108 Variable* Declare(const AstRawString* name, int pos = kNoSourcePosition) { 109 if (type_ == kParameterDeclaration) { 110 return AsParameterDeclarationParsingScope()->Declare(name, pos); 111 } 112 return AsVariableDeclarationParsingScope()->Declare(name, pos); 113 } 114 MarkIdentifierAsAssigned()115 void MarkIdentifierAsAssigned() { 116 if (!CanBeExpression()) return; 117 AsExpressionParsingScope()->MarkIdentifierAsAssigned(); 118 } 119 ValidateAsPattern(ExpressionT expression,int begin,int end)120 void ValidateAsPattern(ExpressionT expression, int begin, int end) { 121 if (!CanBeExpression()) return; 122 AsExpressionParsingScope()->ValidatePattern(expression, begin, end); 123 AsExpressionParsingScope()->ClearExpressionError(); 124 } 125 ValidateAsExpression()126 void ValidateAsExpression() { 127 if (!CanBeExpression()) return; 128 AsExpressionParsingScope()->ValidateExpression(); 129 AsExpressionParsingScope()->ClearPatternError(); 130 } 131 132 // Record async arrow parameters errors in all ambiguous async arrow scopes in 133 // the chain up to the first unambiguous scope. RecordAsyncArrowParametersError(const Scanner::Location & loc,MessageTemplate message)134 void RecordAsyncArrowParametersError(const Scanner::Location& loc, 135 MessageTemplate message) { 136 // Only ambiguous scopes (ExpressionParsingScope, *ArrowHeadParsingScope) 137 // need to propagate errors to a possible kAsyncArrowHeadParsingScope, so 138 // immediately return if the current scope is not ambiguous. 139 if (!CanBeExpression()) return; 140 AsExpressionParsingScope()->RecordAsyncArrowParametersError(loc, message); 141 } 142 143 // Record initializer errors in all scopes that can turn into parameter scopes 144 // (ArrowHeadParsingScopes) up to the first known unambiguous parameter scope. RecordParameterInitializerError(const Scanner::Location & loc,MessageTemplate message)145 void RecordParameterInitializerError(const Scanner::Location& loc, 146 MessageTemplate message) { 147 ExpressionScope* scope = this; 148 while (!scope->IsCertainlyParameterDeclaration()) { 149 if (!has_possible_parameter_in_scope_chain_) return; 150 if (scope->CanBeParameterDeclaration()) { 151 scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); 152 } 153 scope = scope->parent(); 154 if (scope == nullptr) return; 155 } 156 Report(loc, message); 157 } 158 RecordThisUse()159 void RecordThisUse() { 160 ExpressionScope* scope = this; 161 do { 162 if (scope->IsArrowHeadParsingScope()) { 163 scope->AsArrowHeadParsingScope()->RecordThisUse(); 164 } 165 scope = scope->parent(); 166 } while (scope != nullptr); 167 } 168 RecordPatternError(const Scanner::Location & loc,MessageTemplate message)169 void RecordPatternError(const Scanner::Location& loc, 170 MessageTemplate message) { 171 // TODO(verwaest): Non-assigning expression? 172 if (IsCertainlyPattern()) { 173 Report(loc, message); 174 } else { 175 AsExpressionParsingScope()->RecordPatternError(loc, message); 176 } 177 } 178 RecordStrictModeParameterError(const Scanner::Location & loc,MessageTemplate message)179 void RecordStrictModeParameterError(const Scanner::Location& loc, 180 MessageTemplate message) { 181 DCHECK_IMPLIES(!has_error(), loc.IsValid()); 182 if (!CanBeParameterDeclaration()) return; 183 if (IsCertainlyParameterDeclaration()) { 184 if (is_strict(parser_->language_mode())) { 185 Report(loc, message); 186 } else { 187 parser_->parameters_->set_strict_parameter_error(loc, message); 188 } 189 } else { 190 parser_->next_arrow_function_info_.strict_parameter_error_location = loc; 191 parser_->next_arrow_function_info_.strict_parameter_error_message = 192 message; 193 } 194 } 195 RecordDeclarationError(const Scanner::Location & loc,MessageTemplate message)196 void RecordDeclarationError(const Scanner::Location& loc, 197 MessageTemplate message) { 198 if (!CanBeDeclaration()) return; 199 if (IsCertainlyDeclaration()) { 200 Report(loc, message); 201 } else { 202 AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); 203 } 204 } 205 RecordExpressionError(const Scanner::Location & loc,MessageTemplate message)206 void RecordExpressionError(const Scanner::Location& loc, 207 MessageTemplate message) { 208 if (!CanBeExpression()) return; 209 // TODO(verwaest): Non-assigning expression? 210 // if (IsCertainlyExpression()) Report(loc, message); 211 AsExpressionParsingScope()->RecordExpressionError(loc, message); 212 } 213 RecordNonSimpleParameter()214 void RecordNonSimpleParameter() { 215 if (!IsArrowHeadParsingScope()) return; 216 AsArrowHeadParsingScope()->RecordNonSimpleParameter(); 217 } 218 IsCertainlyDeclaration()219 bool IsCertainlyDeclaration() const { 220 return base::IsInRange(type_, kParameterDeclaration, kLexicalDeclaration); 221 } 222 SetInitializers(int variable_index,int peek_position)223 int SetInitializers(int variable_index, int peek_position) { 224 if (CanBeExpression()) { 225 return AsExpressionParsingScope()->SetInitializers(variable_index, 226 peek_position); 227 } 228 return variable_index; 229 } 230 has_possible_arrow_parameter_in_scope_chain()231 bool has_possible_arrow_parameter_in_scope_chain() const { 232 return has_possible_arrow_parameter_in_scope_chain_; 233 } 234 235 protected: 236 enum ScopeType : uint8_t { 237 // Expression or assignment target. 238 kExpression, 239 240 // Declaration or expression or assignment target. 241 kMaybeArrowParameterDeclaration, 242 kMaybeAsyncArrowParameterDeclaration, 243 244 // Declarations. 245 kParameterDeclaration, 246 kVarDeclaration, 247 kLexicalDeclaration, 248 }; 249 parser()250 ParserT* parser() const { return parser_; } parent()251 ExpressionScope* parent() const { return parent_; } 252 Report(const Scanner::Location & loc,MessageTemplate message)253 void Report(const Scanner::Location& loc, MessageTemplate message) const { 254 parser_->ReportMessageAt(loc, message); 255 } 256 ExpressionScope(ParserT * parser,ScopeType type)257 ExpressionScope(ParserT* parser, ScopeType type) 258 : parser_(parser), 259 parent_(parser->expression_scope_), 260 type_(type), 261 has_possible_parameter_in_scope_chain_( 262 CanBeParameterDeclaration() || 263 (parent_ && parent_->has_possible_parameter_in_scope_chain_)), 264 has_possible_arrow_parameter_in_scope_chain_( 265 CanBeArrowParameterDeclaration() || 266 (parent_ && 267 parent_->has_possible_arrow_parameter_in_scope_chain_)) { 268 parser->expression_scope_ = this; 269 } 270 ~ExpressionScope()271 ~ExpressionScope() { 272 DCHECK(parser_->expression_scope_ == this || 273 parser_->expression_scope_ == parent_); 274 parser_->expression_scope_ = parent_; 275 } 276 AsExpressionParsingScope()277 ExpressionParsingScope<Types>* AsExpressionParsingScope() { 278 DCHECK(CanBeExpression()); 279 return static_cast<ExpressionParsingScope<Types>*>(this); 280 } 281 282 #ifdef DEBUG has_error()283 bool has_error() const { return parser_->has_error(); } 284 #endif 285 CanBeExpression()286 bool CanBeExpression() const { 287 return base::IsInRange(type_, kExpression, 288 kMaybeAsyncArrowParameterDeclaration); 289 } CanBeDeclaration()290 bool CanBeDeclaration() const { 291 return base::IsInRange(type_, kMaybeArrowParameterDeclaration, 292 kLexicalDeclaration); 293 } IsVariableDeclaration()294 bool IsVariableDeclaration() const { 295 return base::IsInRange(type_, kVarDeclaration, kLexicalDeclaration); 296 } IsLexicalDeclaration()297 bool IsLexicalDeclaration() const { return type_ == kLexicalDeclaration; } IsAsyncArrowHeadParsingScope()298 bool IsAsyncArrowHeadParsingScope() const { 299 return type_ == kMaybeAsyncArrowParameterDeclaration; 300 } IsVarDeclaration()301 bool IsVarDeclaration() const { return type_ == kVarDeclaration; } 302 303 private: 304 friend class AccumulationScope<Types>; 305 friend class ExpressionParsingScope<Types>; 306 AsArrowHeadParsingScope()307 ArrowHeadParsingScope<Types>* AsArrowHeadParsingScope() { 308 DCHECK(IsArrowHeadParsingScope()); 309 return static_cast<ArrowHeadParsingScope<Types>*>(this); 310 } 311 312 ParameterDeclarationParsingScope<Types>* AsParameterDeclarationParsingScope()313 AsParameterDeclarationParsingScope() { 314 DCHECK(IsCertainlyParameterDeclaration()); 315 return static_cast<ParameterDeclarationParsingScope<Types>*>(this); 316 } 317 AsVariableDeclarationParsingScope()318 VariableDeclarationParsingScope<Types>* AsVariableDeclarationParsingScope() { 319 DCHECK(IsVariableDeclaration()); 320 return static_cast<VariableDeclarationParsingScope<Types>*>(this); 321 } 322 IsArrowHeadParsingScope()323 bool IsArrowHeadParsingScope() const { 324 return base::IsInRange(type_, kMaybeArrowParameterDeclaration, 325 kMaybeAsyncArrowParameterDeclaration); 326 } IsCertainlyPattern()327 bool IsCertainlyPattern() const { return IsCertainlyDeclaration(); } CanBeParameterDeclaration()328 bool CanBeParameterDeclaration() const { 329 return base::IsInRange(type_, kMaybeArrowParameterDeclaration, 330 kParameterDeclaration); 331 } CanBeArrowParameterDeclaration()332 bool CanBeArrowParameterDeclaration() const { 333 return base::IsInRange(type_, kMaybeArrowParameterDeclaration, 334 kMaybeAsyncArrowParameterDeclaration); 335 } IsCertainlyParameterDeclaration()336 bool IsCertainlyParameterDeclaration() const { 337 return type_ == kParameterDeclaration; 338 } 339 340 ParserT* parser_; 341 ExpressionScope<Types>* parent_; 342 ScopeType type_; 343 bool has_possible_parameter_in_scope_chain_; 344 bool has_possible_arrow_parameter_in_scope_chain_; 345 346 DISALLOW_COPY_AND_ASSIGN(ExpressionScope); 347 }; 348 349 // Used to unambiguously parse var, let, const declarations. 350 template <typename Types> 351 class VariableDeclarationParsingScope : public ExpressionScope<Types> { 352 public: 353 using ParserT = typename Types::Impl; 354 using ExpressionScopeT = ExpressionScope<Types>; 355 using ScopeType = typename ExpressionScopeT::ScopeType; 356 VariableDeclarationParsingScope(ParserT * parser,VariableMode mode,ZonePtrList<const AstRawString> * names)357 VariableDeclarationParsingScope(ParserT* parser, VariableMode mode, 358 ZonePtrList<const AstRawString>* names) 359 : ExpressionScopeT(parser, IsLexicalVariableMode(mode) 360 ? ExpressionScopeT::kLexicalDeclaration 361 : ExpressionScopeT::kVarDeclaration), 362 mode_(mode), 363 names_(names) {} 364 Declare(const AstRawString * name,int pos)365 Variable* Declare(const AstRawString* name, int pos) { 366 VariableKind kind = NORMAL_VARIABLE; 367 bool was_added; 368 Variable* var = this->parser()->DeclareVariable( 369 name, kind, mode_, Variable::DefaultInitializationFlag(mode_), 370 this->parser()->scope(), &was_added, pos); 371 if (was_added && 372 this->parser()->scope()->num_var() > kMaxNumFunctionLocals) { 373 this->parser()->ReportMessage(MessageTemplate::kTooManyVariables); 374 } 375 if (names_) names_->Add(name, this->parser()->zone()); 376 if (this->IsLexicalDeclaration()) { 377 if (this->parser()->IsLet(name)) { 378 this->parser()->ReportMessageAt( 379 Scanner::Location(pos, pos + name->length()), 380 MessageTemplate::kLetInLexicalBinding); 381 } 382 } else { 383 if (this->parser()->loop_nesting_depth() > 0) { 384 // Due to hoisting, the value of a 'var'-declared variable may actually 385 // change even if the code contains only the "initial" assignment, 386 // namely when that assignment occurs inside a loop. For example: 387 // 388 // let i = 10; 389 // do { var x = i } while (i--): 390 // 391 // Note that non-lexical variables include temporaries, which may also 392 // get assigned inside a loop due to the various rewritings that the 393 // parser performs. 394 // 395 // Pessimistically mark all vars in loops as assigned. This 396 // overapproximates the actual assigned vars due to unassigned var 397 // without initializer, but that's unlikely anyway. 398 // 399 // This also handles marking of loop variables in for-in and for-of 400 // loops, as determined by loop-nesting-depth. 401 DCHECK_NOT_NULL(var); 402 var->SetMaybeAssigned(); 403 } 404 } 405 return var; 406 } 407 408 private: 409 // Limit the allowed number of local variables in a function. The hard limit 410 // in Ignition is 2^31-1 due to the size of register operands. We limit it to 411 // a more reasonable lower up-limit. 412 static const int kMaxNumFunctionLocals = (1 << 23) - 1; 413 414 VariableMode mode_; 415 ZonePtrList<const AstRawString>* names_; 416 417 DISALLOW_COPY_AND_ASSIGN(VariableDeclarationParsingScope); 418 }; 419 420 template <typename Types> 421 class ParameterDeclarationParsingScope : public ExpressionScope<Types> { 422 public: 423 using ParserT = typename Types::Impl; 424 using ExpressionScopeT = ExpressionScope<Types>; 425 using ScopeType = typename ExpressionScopeT::ScopeType; 426 ParameterDeclarationParsingScope(ParserT * parser)427 explicit ParameterDeclarationParsingScope(ParserT* parser) 428 : ExpressionScopeT(parser, ExpressionScopeT::kParameterDeclaration) {} 429 Declare(const AstRawString * name,int pos)430 Variable* Declare(const AstRawString* name, int pos) { 431 VariableKind kind = PARAMETER_VARIABLE; 432 VariableMode mode = VariableMode::kVar; 433 bool was_added; 434 Variable* var = this->parser()->DeclareVariable( 435 name, kind, mode, Variable::DefaultInitializationFlag(mode), 436 this->parser()->scope(), &was_added, pos); 437 if (!has_duplicate() && !was_added) { 438 duplicate_loc_ = Scanner::Location(pos, pos + name->length()); 439 } 440 return var; 441 } 442 has_duplicate()443 bool has_duplicate() const { return duplicate_loc_.IsValid(); } 444 duplicate_location()445 const Scanner::Location& duplicate_location() const { return duplicate_loc_; } 446 447 private: 448 Scanner::Location duplicate_loc_ = Scanner::Location::invalid(); 449 DISALLOW_COPY_AND_ASSIGN(ParameterDeclarationParsingScope); 450 }; 451 452 // Parsing expressions is always ambiguous between at least left-hand-side and 453 // right-hand-side of assignments. This class is used to keep track of errors 454 // relevant for either side until it is clear what was being parsed. 455 // The class also keeps track of all variable proxies that are created while the 456 // scope was active. If the scope is an expression, the variable proxies will be 457 // added to the unresolved list. Otherwise they are declarations and aren't 458 // added. The list is also used to mark the variables as assigned in case we are 459 // parsing an assignment expression. 460 template <typename Types> 461 class ExpressionParsingScope : public ExpressionScope<Types> { 462 public: 463 using ParserT = typename Types::Impl; 464 using ExpressionT = typename Types::Expression; 465 using ExpressionScopeT = ExpressionScope<Types>; 466 using ScopeType = typename ExpressionScopeT::ScopeType; 467 468 explicit ExpressionParsingScope( 469 ParserT* parser, ScopeType type = ExpressionScopeT::kExpression) ExpressionScopeT(parser,type)470 : ExpressionScopeT(parser, type), 471 variable_list_(parser->variable_buffer()), 472 has_async_arrow_in_scope_chain_( 473 type == ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration || 474 (this->parent() && this->parent()->CanBeExpression() && 475 this->parent() 476 ->AsExpressionParsingScope() 477 ->has_async_arrow_in_scope_chain_)) { 478 DCHECK(this->CanBeExpression()); 479 clear(kExpressionIndex); 480 clear(kPatternIndex); 481 } 482 RecordAsyncArrowParametersError(const Scanner::Location & loc,MessageTemplate message)483 void RecordAsyncArrowParametersError(const Scanner::Location& loc, 484 MessageTemplate message) { 485 for (ExpressionScopeT* scope = this; scope != nullptr; 486 scope = scope->parent()) { 487 if (!has_async_arrow_in_scope_chain_) break; 488 if (scope->type_ == 489 ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration) { 490 scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); 491 } 492 } 493 } 494 ~ExpressionParsingScope()495 ~ExpressionParsingScope() { DCHECK(this->has_error() || verified_); } 496 ValidateAndRewriteReference(ExpressionT expression,int beg_pos,int end_pos)497 ExpressionT ValidateAndRewriteReference(ExpressionT expression, int beg_pos, 498 int end_pos) { 499 if (V8_LIKELY(this->parser()->IsAssignableIdentifier(expression))) { 500 MarkIdentifierAsAssigned(); 501 this->mark_verified(); 502 return expression; 503 } else if (V8_LIKELY(expression->IsProperty())) { 504 ValidateExpression(); 505 return expression; 506 } 507 this->mark_verified(); 508 const bool early_error = false; 509 return this->parser()->RewriteInvalidReferenceExpression( 510 expression, beg_pos, end_pos, MessageTemplate::kInvalidLhsInFor, 511 early_error); 512 } 513 RecordExpressionError(const Scanner::Location & loc,MessageTemplate message)514 void RecordExpressionError(const Scanner::Location& loc, 515 MessageTemplate message) { 516 Record(kExpressionIndex, loc, message); 517 } 518 RecordPatternError(const Scanner::Location & loc,MessageTemplate message)519 void RecordPatternError(const Scanner::Location& loc, 520 MessageTemplate message) { 521 Record(kPatternIndex, loc, message); 522 } 523 ValidateExpression()524 void ValidateExpression() { Validate(kExpressionIndex); } 525 ValidatePattern(ExpressionT expression,int begin,int end)526 void ValidatePattern(ExpressionT expression, int begin, int end) { 527 Validate(kPatternIndex); 528 if (expression->is_parenthesized()) { 529 ExpressionScopeT::Report(Scanner::Location(begin, end), 530 MessageTemplate::kInvalidDestructuringTarget); 531 } 532 for (auto& variable_initializer_pair : variable_list_) { 533 variable_initializer_pair.first->set_is_assigned(); 534 } 535 } 536 ClearExpressionError()537 void ClearExpressionError() { 538 DCHECK(verified_); 539 #ifdef DEBUG 540 verified_ = false; 541 #endif 542 clear(kExpressionIndex); 543 } 544 ClearPatternError()545 void ClearPatternError() { 546 DCHECK(verified_); 547 #ifdef DEBUG 548 verified_ = false; 549 #endif 550 clear(kPatternIndex); 551 } 552 TrackVariable(VariableProxy * variable)553 void TrackVariable(VariableProxy* variable) { 554 if (!this->CanBeDeclaration()) { 555 this->parser()->scope()->AddUnresolved(variable); 556 } 557 variable_list_.Add({variable, kNoSourcePosition}); 558 } 559 MarkIdentifierAsAssigned()560 void MarkIdentifierAsAssigned() { 561 // It's possible we're parsing a syntax error. In that case it's not 562 // guaranteed that there's a variable in the list. 563 if (variable_list_.length() == 0) return; 564 variable_list_.at(variable_list_.length() - 1).first->set_is_assigned(); 565 } 566 SetInitializers(int first_variable_index,int position)567 int SetInitializers(int first_variable_index, int position) { 568 int len = variable_list_.length(); 569 if (len == 0) return 0; 570 571 int end = len - 1; 572 // Loop backwards and abort as soon as we see one that's already set to 573 // avoid a loop on expressions like a,b,c,d,e,f,g (outside of an arrowhead). 574 // TODO(delphick): Look into removing this loop. 575 for (int i = end; i >= first_variable_index && 576 variable_list_.at(i).second == kNoSourcePosition; 577 --i) { 578 variable_list_.at(i).second = position; 579 } 580 return end; 581 } 582 variable_list()583 ScopedList<std::pair<VariableProxy*, int>>* variable_list() { 584 return &variable_list_; 585 } 586 587 protected: is_verified()588 bool is_verified() const { 589 #ifdef DEBUG 590 return verified_; 591 #else 592 return false; 593 #endif 594 } 595 ValidatePattern()596 void ValidatePattern() { Validate(kPatternIndex); } 597 598 private: 599 friend class AccumulationScope<Types>; 600 601 enum ErrorNumber : uint8_t { 602 kExpressionIndex = 0, 603 kPatternIndex = 1, 604 kNumberOfErrors = 2, 605 }; clear(int index)606 void clear(int index) { 607 messages_[index] = MessageTemplate::kNone; 608 locations_[index] = Scanner::Location::invalid(); 609 } is_valid(int index)610 bool is_valid(int index) const { return !locations_[index].IsValid(); } Record(int index,const Scanner::Location & loc,MessageTemplate message)611 void Record(int index, const Scanner::Location& loc, 612 MessageTemplate message) { 613 DCHECK_IMPLIES(!this->has_error(), loc.IsValid()); 614 if (!is_valid(index)) return; 615 messages_[index] = message; 616 locations_[index] = loc; 617 } Validate(int index)618 void Validate(int index) { 619 DCHECK(!this->is_verified()); 620 if (!is_valid(index)) Report(index); 621 this->mark_verified(); 622 } Report(int index)623 void Report(int index) const { 624 ExpressionScopeT::Report(locations_[index], messages_[index]); 625 } 626 627 // Debug verification to make sure every scope is validated exactly once. mark_verified()628 void mark_verified() { 629 #ifdef DEBUG 630 verified_ = true; 631 #endif 632 } clear_verified()633 void clear_verified() { 634 #ifdef DEBUG 635 verified_ = false; 636 #endif 637 } 638 #ifdef DEBUG 639 bool verified_ = false; 640 #endif 641 642 ScopedList<std::pair<VariableProxy*, int>> variable_list_; 643 MessageTemplate messages_[kNumberOfErrors]; 644 Scanner::Location locations_[kNumberOfErrors]; 645 bool has_async_arrow_in_scope_chain_; 646 647 DISALLOW_COPY_AND_ASSIGN(ExpressionParsingScope); 648 }; 649 650 // This class is used to parse multiple ambiguous expressions and declarations 651 // in the same scope. E.g., in async(X,Y,Z) or [X,Y,Z], X and Y and Z will all 652 // be parsed in the respective outer ArrowHeadParsingScope and 653 // ExpressionParsingScope. It provides a clean error state in the underlying 654 // scope to parse the individual expressions, while keeping track of the 655 // expression and pattern errors since the start. The AccumulationScope is only 656 // used to keep track of the errors so far, and the underlying ExpressionScope 657 // keeps being used as the expression_scope(). If the expression_scope() isn't 658 // ambiguous, this class does not do anything. 659 template <typename Types> 660 class AccumulationScope { 661 public: 662 using ParserT = typename Types::Impl; 663 664 static const int kNumberOfErrors = 665 ExpressionParsingScope<Types>::kNumberOfErrors; AccumulationScope(ExpressionScope<Types> * scope)666 explicit AccumulationScope(ExpressionScope<Types>* scope) : scope_(nullptr) { 667 if (!scope->CanBeExpression()) return; 668 scope_ = scope->AsExpressionParsingScope(); 669 for (int i = 0; i < kNumberOfErrors; i++) { 670 copy(i); 671 scope_->clear(i); 672 } 673 } 674 675 // Merge errors from the underlying ExpressionParsingScope into this scope. 676 // Only keeps the first error across all accumulate calls, and removes the 677 // error from the underlying scope. Accumulate()678 void Accumulate() { 679 if (scope_ == nullptr) return; 680 DCHECK(!scope_->is_verified()); 681 for (int i = 0; i < kNumberOfErrors; i++) { 682 if (!locations_[i].IsValid()) copy(i); 683 scope_->clear(i); 684 } 685 } 686 687 // This is called instead of Accumulate in case the parsed member is already 688 // known to be an expression. In that case we don't need to accumulate the 689 // expression but rather validate it immediately. We also ignore the pattern 690 // error since the parsed member is known to not be a pattern. This is 691 // necessary for "{x:1}.y" parsed as part of an assignment pattern. {x:1} will 692 // record a pattern error, but "{x:1}.y" is actually a valid as part of an 693 // assignment pattern since it's a property access. ValidateExpression()694 void ValidateExpression() { 695 if (scope_ == nullptr) return; 696 DCHECK(!scope_->is_verified()); 697 scope_->ValidateExpression(); 698 DCHECK(scope_->is_verified()); 699 scope_->clear(ExpressionParsingScope<Types>::kPatternIndex); 700 #ifdef DEBUG 701 scope_->clear_verified(); 702 #endif 703 } 704 ~AccumulationScope()705 ~AccumulationScope() { 706 if (scope_ == nullptr) return; 707 Accumulate(); 708 for (int i = 0; i < kNumberOfErrors; i++) copy_back(i); 709 } 710 711 private: copy(int entry)712 void copy(int entry) { 713 messages_[entry] = scope_->messages_[entry]; 714 locations_[entry] = scope_->locations_[entry]; 715 } 716 copy_back(int entry)717 void copy_back(int entry) { 718 if (!locations_[entry].IsValid()) return; 719 scope_->messages_[entry] = messages_[entry]; 720 scope_->locations_[entry] = locations_[entry]; 721 } 722 723 ExpressionParsingScope<Types>* scope_; 724 MessageTemplate messages_[2]; 725 Scanner::Location locations_[2]; 726 727 DISALLOW_COPY_AND_ASSIGN(AccumulationScope); 728 }; 729 730 // The head of an arrow function is ambiguous between expression, assignment 731 // pattern and declaration. This keeps track of the additional declaration 732 // error and allows the scope to be validated as a declaration rather than an 733 // expression or a pattern. 734 template <typename Types> 735 class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { 736 public: 737 using ParserT = typename Types::Impl; 738 using ScopeType = typename ExpressionScope<Types>::ScopeType; 739 ArrowHeadParsingScope(ParserT * parser,FunctionKind kind)740 ArrowHeadParsingScope(ParserT* parser, FunctionKind kind) 741 : ExpressionParsingScope<Types>( 742 parser, 743 kind == FunctionKind::kArrowFunction 744 ? ExpressionScope<Types>::kMaybeArrowParameterDeclaration 745 : ExpressionScope< 746 Types>::kMaybeAsyncArrowParameterDeclaration) { 747 DCHECK(kind == FunctionKind::kAsyncArrowFunction || 748 kind == FunctionKind::kArrowFunction); 749 DCHECK(this->CanBeDeclaration()); 750 DCHECK(!this->IsCertainlyDeclaration()); 751 } 752 ValidateExpression()753 void ValidateExpression() { 754 // Turns out this is not an arrow head. Clear any possible tracked strict 755 // parameter errors, and reinterpret tracked variables as unresolved 756 // references. 757 this->parser()->next_arrow_function_info_.ClearStrictParameterError(); 758 ExpressionParsingScope<Types>::ValidateExpression(); 759 this->parent()->MergeVariableList(this->variable_list()); 760 } 761 ValidateAndCreateScope()762 DeclarationScope* ValidateAndCreateScope() { 763 DCHECK(!this->is_verified()); 764 DeclarationScope* result = this->parser()->NewFunctionScope(kind()); 765 if (declaration_error_location.IsValid()) { 766 ExpressionScope<Types>::Report(declaration_error_location, 767 declaration_error_message); 768 return result; 769 } 770 this->ValidatePattern(); 771 772 if (!has_simple_parameter_list_) result->SetHasNonSimpleParameters(); 773 VariableKind kind = PARAMETER_VARIABLE; 774 VariableMode mode = 775 has_simple_parameter_list_ ? VariableMode::kVar : VariableMode::kLet; 776 for (auto& proxy_initializer_pair : *this->variable_list()) { 777 VariableProxy* proxy = proxy_initializer_pair.first; 778 int initializer_position = proxy_initializer_pair.second; 779 // Default values for parameters will have been parsed as assignments so 780 // clear the is_assigned bit as they are not actually assignments. 781 proxy->clear_is_assigned(); 782 bool was_added; 783 this->parser()->DeclareAndBindVariable(proxy, kind, mode, result, 784 &was_added, initializer_position); 785 if (!was_added) { 786 ExpressionScope<Types>::Report(proxy->location(), 787 MessageTemplate::kParamDupe); 788 } 789 } 790 791 #ifdef DEBUG 792 if (!this->has_error()) { 793 for (auto declaration : *result->declarations()) { 794 DCHECK_NE(declaration->var()->initializer_position(), 795 kNoSourcePosition); 796 } 797 } 798 #endif // DEBUG 799 800 if (uses_this_) result->UsesThis(); 801 return result; 802 } 803 RecordDeclarationError(const Scanner::Location & loc,MessageTemplate message)804 void RecordDeclarationError(const Scanner::Location& loc, 805 MessageTemplate message) { 806 DCHECK_IMPLIES(!this->has_error(), loc.IsValid()); 807 declaration_error_location = loc; 808 declaration_error_message = message; 809 } 810 RecordNonSimpleParameter()811 void RecordNonSimpleParameter() { has_simple_parameter_list_ = false; } RecordThisUse()812 void RecordThisUse() { uses_this_ = true; } 813 814 private: kind()815 FunctionKind kind() const { 816 return this->IsAsyncArrowHeadParsingScope() 817 ? FunctionKind::kAsyncArrowFunction 818 : FunctionKind::kArrowFunction; 819 } 820 821 Scanner::Location declaration_error_location = Scanner::Location::invalid(); 822 MessageTemplate declaration_error_message = MessageTemplate::kNone; 823 bool has_simple_parameter_list_ = true; 824 bool uses_this_ = false; 825 826 DISALLOW_COPY_AND_ASSIGN(ArrowHeadParsingScope); 827 }; 828 829 } // namespace internal 830 } // namespace v8 831 832 #endif // V8_PARSING_EXPRESSION_SCOPE_H_ 833