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