/src/hermes/lib/Parser/JSParserImpl-flow.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright (c) Meta Platforms, Inc. and affiliates.  | 
3  |  |  *  | 
4  |  |  * This source code is licensed under the MIT license found in the  | 
5  |  |  * LICENSE file in the root directory of this source tree.  | 
6  |  |  */  | 
7  |  |  | 
8  |  | #include "JSParserImpl.h"  | 
9  |  |  | 
10  |  | #include "llvh/Support/SaveAndRestore.h"  | 
11  |  |  | 
12  |  | using llvh::dyn_cast;  | 
13  |  | using llvh::isa;  | 
14  |  |  | 
15  |  | namespace hermes { | 
16  |  | namespace parser { | 
17  |  | namespace detail { | 
18  |  |  | 
19  |  | #if HERMES_PARSE_FLOW  | 
20  |  |  | 
21  | 0  | Optional<ESTree::Node *> JSParserImpl::parseFlowDeclaration() { | 
22  | 0  |   assert(checkDeclaration());  | 
23  | 0  |   SMLoc start = tok_->getStartLoc();  | 
24  |  | 
  | 
25  | 0  |   if (context_.getParseFlowComponentSyntax() &&  | 
26  | 0  |       checkComponentDeclarationFlow()) { | 
27  | 0  |     return parseComponentDeclarationFlow(start, /* declare */ false);  | 
28  | 0  |   }  | 
29  |  |  | 
30  | 0  |   if (context_.getParseFlowComponentSyntax() && checkHookDeclarationFlow()) { | 
31  | 0  |     return parseHookDeclarationFlow(start);  | 
32  | 0  |   }  | 
33  |  |  | 
34  | 0  |   if (check(TokenKind::rw_enum)) { | 
35  | 0  |     auto optEnum = parseEnumDeclarationFlow(start, /* declare */ false);  | 
36  | 0  |     if (!optEnum)  | 
37  | 0  |       return None;  | 
38  | 0  |     return *optEnum;  | 
39  | 0  |   }  | 
40  |  |  | 
41  | 0  |   TypeAliasKind kind = TypeAliasKind::None;  | 
42  | 0  |   if (checkAndEat(declareIdent_))  | 
43  | 0  |     kind = TypeAliasKind::Declare;  | 
44  | 0  |   else if (checkAndEat(opaqueIdent_))  | 
45  | 0  |     kind = TypeAliasKind::Opaque;  | 
46  |  | 
  | 
47  | 0  |   if (kind == TypeAliasKind::Declare &&  | 
48  | 0  |       !checkN(typeIdent_, interfaceIdent_, TokenKind::rw_interface)) { | 
49  | 0  |     error(tok_->getSourceRange(), "invalid token in type declaration");  | 
50  | 0  |     return None;  | 
51  | 0  |   }  | 
52  | 0  |   if (kind == TypeAliasKind::Opaque && !check(typeIdent_)) { | 
53  | 0  |     error(tok_->getSourceRange(), "invalid token in opaque type declaration");  | 
54  | 0  |     return None;  | 
55  | 0  |   }  | 
56  |  |  | 
57  | 0  |   if (checkAndEat(typeIdent_)) { | 
58  | 0  |     auto optType = parseTypeAliasFlow(start, kind);  | 
59  | 0  |     if (!optType)  | 
60  | 0  |       return None;  | 
61  | 0  |     return *optType;  | 
62  | 0  |   }  | 
63  |  |  | 
64  | 0  |   if (checkN(interfaceIdent_, TokenKind::rw_interface)) { | 
65  | 0  |     auto optType = parseInterfaceDeclarationFlow(  | 
66  | 0  |         kind == TypeAliasKind::Declare ? Optional<SMLoc>(start) : None);  | 
67  | 0  |     if (!optType)  | 
68  | 0  |       return None;  | 
69  | 0  |     return *optType;  | 
70  | 0  |   }  | 
71  |  |  | 
72  | 0  |   assert(  | 
73  | 0  |       kind == TypeAliasKind::None &&  | 
74  | 0  |       "checkDeclaration() returned true without 'type' or 'interface'");  | 
75  | 0  |   return None;  | 
76  | 0  | }  | 
77  |  |  | 
78  | 0  | Optional<ESTree::Node *> JSParserImpl::parseDeclareFLow(SMLoc start) { | 
79  | 0  |   if (checkAndEat(typeIdent_)) { | 
80  | 0  |     return parseTypeAliasFlow(start, TypeAliasKind::Declare);  | 
81  | 0  |   }  | 
82  | 0  |   if (checkAndEat(opaqueIdent_)) { | 
83  | 0  |     if (!check(typeIdent_)) { | 
84  | 0  |       error(tok_->getStartLoc(), "'type' required in opaque type declaration");  | 
85  | 0  |       return None;  | 
86  | 0  |     }  | 
87  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
88  | 0  |     return parseTypeAliasFlow(start, TypeAliasKind::DeclareOpaque);  | 
89  | 0  |   }  | 
90  | 0  |   if (checkN(TokenKind::rw_interface, interfaceIdent_)) { | 
91  | 0  |     return parseInterfaceDeclarationFlow(start);  | 
92  | 0  |   }  | 
93  | 0  |   if (check(TokenKind::rw_class)) { | 
94  | 0  |     return parseDeclareClassFlow(start);  | 
95  | 0  |   }  | 
96  | 0  |   if (check(TokenKind::rw_function)) { | 
97  | 0  |     return parseDeclareFunctionFlow(start);  | 
98  | 0  |   }  | 
99  |  |  | 
100  | 0  |   if (context_.getParseFlowComponentSyntax() && checkHookDeclarationFlow()) { | 
101  | 0  |     return parseDeclareHookFlow(start);  | 
102  | 0  |   }  | 
103  |  |  | 
104  | 0  |   if (context_.getParseFlowComponentSyntax() &&  | 
105  | 0  |       checkComponentDeclarationFlow()) { | 
106  | 0  |     return parseComponentDeclarationFlow(start, /* declare */ true);  | 
107  | 0  |   }  | 
108  | 0  |   if (check(TokenKind::rw_enum)) { | 
109  | 0  |     return parseEnumDeclarationFlow(start, /* declare */ true);  | 
110  | 0  |   }  | 
111  | 0  |   if (check(moduleIdent_)) { | 
112  | 0  |     return parseDeclareModuleFlow(start);  | 
113  | 0  |   }  | 
114  | 0  |   if (check(namespaceIdent_)) { | 
115  | 0  |     return parseDeclareNamespaceFlow(start);  | 
116  | 0  |   }  | 
117  | 0  |   if (check(TokenKind::rw_var, TokenKind::rw_const) || check(letIdent_)) { | 
118  | 0  |     ESTree::NodeLabel kind = tok_->getResWordOrIdentifier();  | 
119  | 0  |     advance();  | 
120  | 0  |     auto optIdent = parseBindingIdentifier(Param{}); | 
121  | 0  |     if (!optIdent) { | 
122  | 0  |       errorExpected(  | 
123  | 0  |           TokenKind::identifier,  | 
124  | 0  |           "in var declaration",  | 
125  | 0  |           "start of declaration",  | 
126  | 0  |           start);  | 
127  | 0  |       return None;  | 
128  | 0  |     }  | 
129  | 0  |     if (!(*optIdent)->_typeAnnotation) { | 
130  | 0  |       error(  | 
131  | 0  |           (*optIdent)->getSourceRange(),  | 
132  | 0  |           "expected type annotation on declared var");  | 
133  | 0  |     }  | 
134  | 0  |     if (!eatSemi())  | 
135  | 0  |       return None;  | 
136  | 0  |     return setLocation(  | 
137  | 0  |         start,  | 
138  | 0  |         getPrevTokenEndLoc(),  | 
139  | 0  |         new (context_) ESTree::DeclareVariableNode(*optIdent, kind));  | 
140  | 0  |   }  | 
141  |  |  | 
142  | 0  |   if (!check(TokenKind::rw_export)) { | 
143  | 0  |     errorExpected(  | 
144  | 0  |         {TokenKind::rw_export, | 
145  | 0  |          TokenKind::rw_interface,  | 
146  | 0  |          TokenKind::rw_function,  | 
147  | 0  |          TokenKind::rw_class,  | 
148  | 0  |          TokenKind::rw_var},  | 
149  | 0  |         "in declared type",  | 
150  | 0  |         "start of declare",  | 
151  | 0  |         start);  | 
152  | 0  |     return None;  | 
153  | 0  |   }  | 
154  |  |  | 
155  | 0  |   return parseDeclareExportFlow(start);  | 
156  | 0  | }  | 
157  |  |  | 
158  | 0  | bool JSParserImpl::checkComponentDeclarationFlow() { | 
159  | 0  |   if (!check(componentIdent_))  | 
160  | 0  |     return false;  | 
161  |  |  | 
162  |  |   // Don't pass an `expectedToken` so we don't advance on a match. This allows  | 
163  |  |   // `parseComponentDeclarationFlow` to reparse the token and store useful  | 
164  |  |   // information. Additionally to be used within `checkDeclaration` this  | 
165  |  |   // function must be idempotent.  | 
166  | 0  |   OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
167  | 0  |   return optNext.hasValue() && *optNext == TokenKind::identifier;  | 
168  | 0  | }  | 
169  |  |  | 
170  |  | Optional<ESTree::Node *> JSParserImpl::parseComponentDeclarationFlow(  | 
171  |  |     SMLoc start,  | 
172  | 0  |     bool declare) { | 
173  |  |   // component  | 
174  | 0  |   assert(check(componentIdent_));  | 
175  | 0  |   advance();  | 
176  |  |  | 
177  |  |   // identifier  | 
178  | 0  |   auto optId = parseBindingIdentifier(Param{}); | 
179  |  |  | 
180  |  |   // Components always require a name identifier  | 
181  | 0  |   if (!optId) { | 
182  | 0  |     errorExpected(  | 
183  | 0  |         TokenKind::identifier,  | 
184  | 0  |         "after 'component'",  | 
185  | 0  |         "location of 'component'",  | 
186  | 0  |         start);  | 
187  | 0  |     return None;  | 
188  | 0  |   }  | 
189  |  |  | 
190  | 0  |   ESTree::Node *typeParams = nullptr;  | 
191  |  | 
  | 
192  | 0  |   if (check(TokenKind::less)) { | 
193  | 0  |     auto optTypeParams = parseTypeParamsFlow();  | 
194  | 0  |     if (!optTypeParams)  | 
195  | 0  |       return None;  | 
196  | 0  |     typeParams = *optTypeParams;  | 
197  | 0  |   }  | 
198  |  |  | 
199  | 0  |   if (!need(  | 
200  | 0  |           TokenKind::l_paren,  | 
201  | 0  |           "at start of component parameter list",  | 
202  | 0  |           "component declaration starts here",  | 
203  | 0  |           start)) { | 
204  | 0  |     return None;  | 
205  | 0  |   }  | 
206  |  |  | 
207  | 0  |   ESTree::NodeList paramList;  | 
208  | 0  |   ESTree::Node *rest = nullptr;  | 
209  |  | 
  | 
210  | 0  |   if (declare) { | 
211  | 0  |     auto restOpt = parseComponentTypeParametersFlow(Param{}, paramList); | 
212  | 0  |     if (!restOpt)  | 
213  | 0  |       return None;  | 
214  | 0  |     rest = *restOpt;  | 
215  | 0  |   } else { | 
216  | 0  |     if (!parseComponentParametersFlow(Param{}, paramList)) | 
217  | 0  |       return None;  | 
218  | 0  |   }  | 
219  |  |  | 
220  | 0  |   ESTree::Node *rendersType = nullptr;  | 
221  | 0  |   if (check(rendersIdent_)) { | 
222  | 0  |     auto optRenders = parseComponentRenderTypeFlow(false);  | 
223  | 0  |     if (!optRenders)  | 
224  | 0  |       return None;  | 
225  | 0  |     rendersType = *optRenders;  | 
226  | 0  |   }  | 
227  |  |  | 
228  | 0  |   if (declare) { | 
229  | 0  |     if (!eatSemi())  | 
230  | 0  |       return None;  | 
231  |  |  | 
232  | 0  |     return setLocation(  | 
233  | 0  |         start,  | 
234  | 0  |         getPrevTokenEndLoc(),  | 
235  | 0  |         new (context_) ESTree::DeclareComponentNode(  | 
236  | 0  |             *optId, std::move(paramList), rest, typeParams, rendersType));  | 
237  | 0  |   }  | 
238  |  |  | 
239  | 0  |   if (!need(  | 
240  | 0  |           TokenKind::l_brace,  | 
241  | 0  |           "in component declaration",  | 
242  | 0  |           "start of component declaration",  | 
243  | 0  |           start)) { | 
244  | 0  |     return None;  | 
245  | 0  |   }  | 
246  |  |  | 
247  | 0  |   SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this}; | 
248  |  | 
  | 
249  | 0  |   auto parsedBody = parseFunctionBody(  | 
250  | 0  |       Param{}, false, false, false, JSLexer::AllowRegExp, true); | 
251  | 0  |   if (!parsedBody)  | 
252  | 0  |     return None;  | 
253  | 0  |   auto *body = parsedBody.getValue();  | 
254  |  | 
  | 
255  | 0  |   return setLocation(  | 
256  | 0  |       start,  | 
257  | 0  |       body,  | 
258  | 0  |       new (context_) ESTree::ComponentDeclarationNode(  | 
259  | 0  |           *optId, std::move(paramList), body, typeParams, rendersType));  | 
260  | 0  | }  | 
261  |  |  | 
262  |  | bool JSParserImpl::parseComponentParametersFlow(  | 
263  |  |     Param param,  | 
264  | 0  |     ESTree::NodeList ¶mList) { | 
265  | 0  |   assert(  | 
266  | 0  |       check(TokenKind::l_paren) && "ComponentParameters must start with '('"); | 
267  |  |   // (  | 
268  | 0  |   SMLoc lparenLoc = advance().Start;  | 
269  |  | 
  | 
270  | 0  |   while (!check(TokenKind::r_paren)) { | 
271  | 0  |     if (check(TokenKind::dotdotdot)) { | 
272  |  |       // BindingRestElement.  | 
273  | 0  |       auto optRestElem = parseBindingRestElement(param);  | 
274  | 0  |       if (!optRestElem)  | 
275  | 0  |         return false;  | 
276  | 0  |       paramList.push_back(*optRestElem.getValue());  | 
277  | 0  |       checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);  | 
278  | 0  |       break;  | 
279  | 0  |     }  | 
280  |  |  | 
281  |  |     // ComponentParameter.  | 
282  | 0  |     auto optParam = parseComponentParameterFlow(param);  | 
283  | 0  |     if (!optParam)  | 
284  | 0  |       return false;  | 
285  |  |  | 
286  | 0  |     paramList.push_back(*optParam.getValue());  | 
287  |  | 
  | 
288  | 0  |     if (!checkAndEat(TokenKind::comma))  | 
289  | 0  |       break;  | 
290  | 0  |   }  | 
291  |  |  | 
292  |  |   // )  | 
293  | 0  |   if (!eat(  | 
294  | 0  |           TokenKind::r_paren,  | 
295  | 0  |           JSLexer::AllowRegExp,  | 
296  | 0  |           "at end of component parameter list",  | 
297  | 0  |           "start of component parameter list",  | 
298  | 0  |           lparenLoc)) { | 
299  | 0  |     return false;  | 
300  | 0  |   }  | 
301  |  |  | 
302  | 0  |   return true;  | 
303  | 0  | }  | 
304  |  |  | 
305  |  | Optional<ESTree::Node *> JSParserImpl::parseComponentParameterFlow(  | 
306  | 0  |     Param param) { | 
307  |  |   // ComponentParameter:  | 
308  |  |   //   StringLiteral as BindingElement  | 
309  |  |   //   IdentifierName  | 
310  |  |   //   IdentifierName as BindingElement  | 
311  |  | 
  | 
312  | 0  |   SMLoc paramStart = tok_->getStartLoc();  | 
313  | 0  |   ESTree::Node *nameElem;  | 
314  | 0  |   if (check(TokenKind::string_literal)) { | 
315  |  |     // StringLiteral as BindingElement  | 
316  |  |     // ^  | 
317  | 0  |     nameElem = setLocation(  | 
318  | 0  |         tok_,  | 
319  | 0  |         tok_,  | 
320  | 0  |         new (context_) ESTree::StringLiteralNode(tok_->getStringLiteral()));  | 
321  | 0  |     advance();  | 
322  |  | 
  | 
323  | 0  |     if (!checkAndEat(asIdent_)) { | 
324  | 0  |       error(  | 
325  | 0  |           nameElem->getSourceRange(),  | 
326  | 0  |           "string literal names require a local via `as`");  | 
327  | 0  |       return None;  | 
328  | 0  |     }  | 
329  |  |  | 
330  | 0  |     auto optBinding = parseBindingElement(Param{}); | 
331  | 0  |     if (!optBinding)  | 
332  | 0  |       return None;  | 
333  |  |  | 
334  | 0  |     return setLocation(  | 
335  | 0  |         paramStart,  | 
336  | 0  |         getPrevTokenEndLoc(),  | 
337  | 0  |         new (context_)  | 
338  | 0  |             ESTree::ComponentParameterNode(nameElem, *optBinding, false));  | 
339  | 0  |   }  | 
340  |  |  | 
341  | 0  |   if (check(TokenKind::identifier) || tok_->isResWord()) { | 
342  | 0  |     UniqueString *id = tok_->getResWordOrIdentifier();  | 
343  | 0  |     SMRange identRng = tok_->getSourceRange();  | 
344  | 0  |     TokenKind identKind = tok_->getKind();  | 
345  | 0  |     nameElem = setLocation(  | 
346  | 0  |         identRng,  | 
347  | 0  |         identRng,  | 
348  | 0  |         new (context_) ESTree::IdentifierNode(id, nullptr, false));  | 
349  |  | 
  | 
350  | 0  |     advance();  | 
351  | 0  |     if (checkAndEat(asIdent_)) { | 
352  |  |       // IdentifierName as BindingElement  | 
353  |  |       //                   ^  | 
354  | 0  |       auto optBinding = parseBindingElement(Param{}); | 
355  | 0  |       if (!optBinding)  | 
356  | 0  |         return None;  | 
357  |  |  | 
358  | 0  |       return setLocation(  | 
359  | 0  |           paramStart,  | 
360  | 0  |           getPrevTokenEndLoc(),  | 
361  | 0  |           new (context_)  | 
362  | 0  |               ESTree::ComponentParameterNode(nameElem, *optBinding, false));  | 
363  | 0  |     }  | 
364  |  |  | 
365  | 0  |     if (!validateBindingIdentifier(Param{}, identRng, id, identKind)) { | 
366  | 0  |       error(identRng, "Invalid local name for component");  | 
367  | 0  |     }  | 
368  |  | 
  | 
369  | 0  |     ESTree::Node *type = nullptr;  | 
370  | 0  |     bool optional = false;  | 
371  |  |  | 
372  |  |     // IdentifierName?: TypeParam  | 
373  |  |     //               ^  | 
374  | 0  |     if (check(TokenKind::question)) { | 
375  | 0  |       optional = true;  | 
376  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
377  | 0  |     }  | 
378  |  |  | 
379  |  |     // IdentifierName?: TypeParam  | 
380  |  |     //                ^  | 
381  | 0  |     if (check(TokenKind::colon)) { | 
382  | 0  |       SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;  | 
383  | 0  |       auto optType = parseTypeAnnotation(annotStart);  | 
384  | 0  |       if (!optType)  | 
385  | 0  |         return None;  | 
386  | 0  |       type = *optType;  | 
387  | 0  |     }  | 
388  |  |  | 
389  | 0  |     auto elem = setLocation(  | 
390  | 0  |         identRng,  | 
391  | 0  |         getPrevTokenEndLoc(),  | 
392  | 0  |         new (context_) ESTree::IdentifierNode(id, type, optional));  | 
393  | 0  |     ESTree::Node *localElem;  | 
394  |  |  | 
395  |  |     // IdentifierName?: TypeParam = expr  | 
396  |  |     //                            ^  | 
397  | 0  |     if (check(TokenKind::equal)) { | 
398  | 0  |       auto optInit = parseBindingInitializer(param, elem);  | 
399  | 0  |       if (!optInit)  | 
400  | 0  |         return None;  | 
401  | 0  |       localElem = *optInit;  | 
402  | 0  |     } else { | 
403  | 0  |       localElem = elem;  | 
404  | 0  |     }  | 
405  |  |  | 
406  | 0  |     return setLocation(  | 
407  | 0  |         paramStart,  | 
408  | 0  |         getPrevTokenEndLoc(),  | 
409  | 0  |         new (context_)  | 
410  | 0  |             ESTree::ComponentParameterNode(nameElem, localElem, true));  | 
411  | 0  |   }  | 
412  |  |  | 
413  | 0  |   error(  | 
414  | 0  |       tok_->getStartLoc(),  | 
415  | 0  |       "identifier or string literal expected in component parameter name");  | 
416  | 0  |   return None;  | 
417  | 0  | }  | 
418  |  |  | 
419  | 0  | Optional<UniqueString *> JSParserImpl::parseRenderTypeOperator() { | 
420  | 0  |   assert(tok_->getResWordOrIdentifier() == rendersIdent_);  | 
421  | 0  |   auto typeOperator = rendersIdent_;  | 
422  | 0  |   if (tok_->checkFollowingCharacter('?')) { | 
423  | 0  |     SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
424  | 0  |     if (!eat(  | 
425  | 0  |             TokenKind::question,  | 
426  | 0  |             JSLexer::GrammarContext::Type,  | 
427  | 0  |             "in render type annotation",  | 
428  | 0  |             "start of render type",  | 
429  | 0  |             start)) { | 
430  | 0  |       return None;  | 
431  | 0  |     }  | 
432  | 0  |     typeOperator = rendersMaybeOperator_;  | 
433  | 0  |   } else if (tok_->checkFollowingCharacter('*')) { | 
434  | 0  |     SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
435  | 0  |     if (!eat(  | 
436  | 0  |             TokenKind::star,  | 
437  | 0  |             JSLexer::GrammarContext::Type,  | 
438  | 0  |             "in render type annotation",  | 
439  | 0  |             "start of render type",  | 
440  | 0  |             start)) { | 
441  | 0  |       return None;  | 
442  | 0  |     }  | 
443  | 0  |     typeOperator = rendersStarOperator_;  | 
444  | 0  |   } else { | 
445  |  |     // Normal renders, but we must still eat the renders token. We don't just  | 
446  |  |     // eat unconditionally above because the checkFollowingCharacter calls must  | 
447  |  |     // have the renders ident as the current token, so we can't advance until  | 
448  |  |     // after those calls  | 
449  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
450  | 0  |   }  | 
451  |  |  | 
452  | 0  |   return typeOperator;  | 
453  | 0  | }  | 
454  |  |  | 
455  |  | Optional<ESTree::Node *> JSParserImpl::parseComponentRenderTypeFlow(  | 
456  | 0  |     bool componentType) { | 
457  | 0  |   SMLoc annotStart = tok_->getStartLoc();  | 
458  | 0  |   auto optTypeOperator = parseRenderTypeOperator();  | 
459  | 0  |   Optional<ESTree::Node *> optBody;  | 
460  |  |   // This is a weird part of the Flow render syntax design that we should  | 
461  |  |   // reconsider. Because unions have higher precedence than renders, we  | 
462  |  |   // parse `component() renders null | number` as  | 
463  |  |   // `(component() renders null) | number. But with declared components  | 
464  |  |   // and component declarations we parse the entirety of the RHS of  | 
465  |  |   // `renders` as a single type, so  | 
466  |  |   // `component A() renders null | number { ... }` parses the render type | 
467  |  |   // as a union of null | number. This was an intentional decision, and  | 
468  |  |   // prettier will make the discrepancy obvious, but it still feels  | 
469  |  |   // weird. If we give `renders` higher precedence than unions then this  | 
470  |  |   // is no longer a problem, but `keyof` has similar syntax and lower  | 
471  |  |   // precedence than a union type.  | 
472  | 0  |   if (componentType) { | 
473  | 0  |     optBody = parsePrefixTypeAnnotationFlow();  | 
474  | 0  |   } else { | 
475  | 0  |     optBody = parseTypeAnnotationFlow();  | 
476  | 0  |   }  | 
477  | 0  |   if (!optBody || !optTypeOperator)  | 
478  | 0  |     return None;  | 
479  | 0  |   return setLocation(  | 
480  | 0  |       annotStart,  | 
481  | 0  |       getPrevTokenEndLoc(),  | 
482  | 0  |       new (context_) ESTree::TypeOperatorNode(*optTypeOperator, *optBody));  | 
483  | 0  | }  | 
484  |  |  | 
485  | 0  | Optional<ESTree::Node *> JSParserImpl::parseComponentTypeAnnotationFlow() { | 
486  |  |   // component  | 
487  | 0  |   assert(check(componentIdent_));  | 
488  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
489  |  |  | 
490  |  |   // identifier  | 
491  | 0  |   if (check(TokenKind::identifier)) { | 
492  | 0  |     error(  | 
493  | 0  |         tok_->getSourceRange(),  | 
494  | 0  |         "component type annotations should not contain a name");  | 
495  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
496  | 0  |   }  | 
497  |  | 
  | 
498  | 0  |   ESTree::Node *typeParams = nullptr;  | 
499  |  | 
  | 
500  | 0  |   if (check(TokenKind::less)) { | 
501  | 0  |     auto optTypeParams = parseTypeParamsFlow();  | 
502  | 0  |     if (!optTypeParams)  | 
503  | 0  |       return None;  | 
504  | 0  |     typeParams = *optTypeParams;  | 
505  | 0  |   }  | 
506  |  |  | 
507  | 0  |   if (!need(  | 
508  | 0  |           TokenKind::l_paren,  | 
509  | 0  |           "at start of component parameter list",  | 
510  | 0  |           "component type annotation starts here",  | 
511  | 0  |           start)) { | 
512  | 0  |     return None;  | 
513  | 0  |   }  | 
514  |  |  | 
515  | 0  |   ESTree::NodeList paramList;  | 
516  | 0  |   auto restOpt = parseComponentTypeParametersFlow(Param{}, paramList); | 
517  | 0  |   if (!restOpt)  | 
518  | 0  |     return None;  | 
519  | 0  |   ESTree::Node *rest = *restOpt;  | 
520  |  | 
  | 
521  | 0  |   ESTree::Node *rendersType = nullptr;  | 
522  | 0  |   if (check(rendersIdent_)) { | 
523  | 0  |     auto optRenders = parseComponentRenderTypeFlow(true);  | 
524  | 0  |     if (!optRenders)  | 
525  | 0  |       return None;  | 
526  | 0  |     rendersType = *optRenders;  | 
527  | 0  |   }  | 
528  |  |  | 
529  | 0  |   return setLocation(  | 
530  | 0  |       start,  | 
531  | 0  |       getPrevTokenEndLoc(),  | 
532  | 0  |       new (context_) ESTree::ComponentTypeAnnotationNode(  | 
533  | 0  |           std::move(paramList), rest, typeParams, rendersType));  | 
534  | 0  | }  | 
535  |  |  | 
536  |  | Optional<ESTree::Node *> JSParserImpl::parseComponentTypeParametersFlow(  | 
537  |  |     Param param,  | 
538  | 0  |     ESTree::NodeList ¶mList) { | 
539  | 0  |   assert(  | 
540  | 0  |       check(TokenKind::l_paren) &&  | 
541  | 0  |       "ComponentTypeParameters must start with '('"); | 
542  |  |   // (  | 
543  | 0  |   SMLoc lparenLoc = advance(JSLexer::GrammarContext::Type).Start;  | 
544  | 0  |   ESTree::Node *rest = nullptr;  | 
545  |  | 
  | 
546  | 0  |   while (!check(TokenKind::r_paren)) { | 
547  | 0  |     if (check(TokenKind::dotdotdot)) { | 
548  |  |       // ComponentTypeRestParameter.  | 
549  | 0  |       auto optRest = parseComponentTypeRestParameterFlow(param);  | 
550  | 0  |       if (!optRest)  | 
551  | 0  |         return None;  | 
552  | 0  |       rest = *optRest;  | 
553  | 0  |       break;  | 
554  | 0  |     }  | 
555  |  |  | 
556  |  |     // ComponentTypeParameter.  | 
557  | 0  |     auto optParam = parseComponentTypeParameterFlow(param);  | 
558  | 0  |     if (!optParam)  | 
559  | 0  |       return None;  | 
560  |  |  | 
561  | 0  |     paramList.push_back(*optParam.getValue());  | 
562  |  | 
  | 
563  | 0  |     if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))  | 
564  | 0  |       break;  | 
565  | 0  |   }  | 
566  |  |  | 
567  |  |   // )  | 
568  | 0  |   if (!eat(  | 
569  | 0  |           TokenKind::r_paren,  | 
570  | 0  |           JSLexer::GrammarContext::Type,  | 
571  | 0  |           "at end of component type parameter list",  | 
572  | 0  |           "start of component type parameter list",  | 
573  | 0  |           lparenLoc)) { | 
574  | 0  |     return None;  | 
575  | 0  |   }  | 
576  |  |  | 
577  | 0  |   return rest;  | 
578  | 0  | }  | 
579  |  |  | 
580  |  | Optional<ESTree::Node *> JSParserImpl::parseComponentTypeRestParameterFlow(  | 
581  | 0  |     Param param) { | 
582  |  |   // ComponentTypeRestParameter:  | 
583  |  |   //   ...IdentifierName: TypeParam  | 
584  |  |   //   ...IdentifierName?: TypeParam  | 
585  |  |   //   ...TypeParam  | 
586  |  | 
  | 
587  | 0  |   assert(check(TokenKind::dotdotdot));  | 
588  |  |  | 
589  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
590  |  | 
  | 
591  | 0  |   auto optLeft = parseTypeAnnotationBeforeColonFlow();  | 
592  | 0  |   if (!optLeft)  | 
593  | 0  |     return None;  | 
594  |  |  | 
595  | 0  |   ESTree::Node *name = nullptr;  | 
596  | 0  |   ESTree::Node *typeAnnotation = nullptr;  | 
597  | 0  |   bool optional = false;  | 
598  |  | 
  | 
599  | 0  |   if (check(TokenKind::colon, TokenKind::question)) { | 
600  |  |     // The node is actually supposed to be an identifier, not a TypeAnnotation.  | 
601  | 0  |     auto optName = reparseTypeAnnotationAsIdentifierFlow(*optLeft);  | 
602  | 0  |     if (!optName)  | 
603  | 0  |       return None;  | 
604  | 0  |     name = *optName;  | 
605  | 0  |     optional = checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type);  | 
606  | 0  |     if (!eat(  | 
607  | 0  |             TokenKind::colon,  | 
608  | 0  |             JSLexer::GrammarContext::Type,  | 
609  | 0  |             "in component parameter type annotation",  | 
610  | 0  |             "start of parameter",  | 
611  | 0  |             start))  | 
612  | 0  |       return None;  | 
613  | 0  |     auto optType = parseTypeAnnotationFlow();  | 
614  | 0  |     if (!optType)  | 
615  | 0  |       return None;  | 
616  | 0  |     typeAnnotation = *optType;  | 
617  | 0  |   } else { | 
618  | 0  |     typeAnnotation = *optLeft;  | 
619  | 0  |   }  | 
620  |  |  | 
621  | 0  |   checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);  | 
622  |  | 
  | 
623  | 0  |   return setLocation(  | 
624  | 0  |       start,  | 
625  | 0  |       getPrevTokenEndLoc(),  | 
626  | 0  |       new (context_)  | 
627  | 0  |           ESTree::ComponentTypeParameterNode(name, typeAnnotation, optional));  | 
628  | 0  | }  | 
629  |  |  | 
630  |  | Optional<ESTree::Node *> JSParserImpl::parseComponentTypeParameterFlow(  | 
631  | 0  |     Param param) { | 
632  |  |   // ComponentTypeParameter:  | 
633  |  |   //   StringLiteral?: TypeParam  | 
634  |  |   //   IdentifierName?: TypeParam  | 
635  |  | 
  | 
636  | 0  |   SMLoc paramStart = tok_->getStartLoc();  | 
637  | 0  |   ESTree::Node *nameElem;  | 
638  | 0  |   if (check(TokenKind::string_literal)) { | 
639  |  |     // StringLiteral: TypeParam  | 
640  |  |     // ^  | 
641  | 0  |     nameElem = setLocation(  | 
642  | 0  |         tok_,  | 
643  | 0  |         tok_,  | 
644  | 0  |         new (context_) ESTree::StringLiteralNode(tok_->getStringLiteral()));  | 
645  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
646  | 0  |   } else if (check(TokenKind::identifier) || tok_->isResWord()) { | 
647  |  |     // IdentifierName: TypeParam  | 
648  |  |     // ^  | 
649  | 0  |     nameElem = setLocation(  | 
650  | 0  |         tok_,  | 
651  | 0  |         tok_,  | 
652  | 0  |         new (context_) ESTree::IdentifierNode(  | 
653  | 0  |             tok_->getResWordOrIdentifier(), nullptr, false));  | 
654  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
655  | 0  |   } else { | 
656  | 0  |     error(  | 
657  | 0  |         tok_->getStartLoc(),  | 
658  | 0  |         "identifier or string literal expected in component type parameter name");  | 
659  | 0  |     return None;  | 
660  | 0  |   }  | 
661  |  |  | 
662  | 0  |   if (check(asIdent_)) { | 
663  | 0  |     error(tok_->getStartLoc(), "'as' not allowed in component type parameter");  | 
664  | 0  |     return None;  | 
665  | 0  |   }  | 
666  |  |  | 
667  | 0  |   bool optional = false;  | 
668  |  |  | 
669  |  |   // Name?: TypeParam  | 
670  |  |   //     ^  | 
671  | 0  |   if (checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type)) { | 
672  | 0  |     optional = true;  | 
673  | 0  |   }  | 
674  |  |  | 
675  |  |   // Name?: TypeParam  | 
676  |  |   //      ^  | 
677  | 0  |   if (!eat(  | 
678  | 0  |           TokenKind::colon,  | 
679  | 0  |           JSLexer::GrammarContext::Type,  | 
680  | 0  |           "in component type parameter",  | 
681  | 0  |           "start of parameter",  | 
682  | 0  |           paramStart))  | 
683  | 0  |     return None;  | 
684  |  |  | 
685  |  |   // Name?: TypeParam  | 
686  |  |   //        ^  | 
687  | 0  |   auto optType = parseTypeAnnotation();  | 
688  | 0  |   if (!optType)  | 
689  | 0  |     return None;  | 
690  |  |  | 
691  | 0  |   return setLocation(  | 
692  | 0  |       paramStart,  | 
693  | 0  |       getPrevTokenEndLoc(),  | 
694  | 0  |       new (context_)  | 
695  | 0  |           ESTree::ComponentTypeParameterNode(nameElem, *optType, optional));  | 
696  | 0  | }  | 
697  |  |  | 
698  | 0  | bool JSParserImpl::checkHookDeclarationFlow() { | 
699  | 0  |   if (!check(hookIdent_))  | 
700  | 0  |     return false;  | 
701  |  |  | 
702  |  |   // Don't pass an `expectedToken` so we don't advance on a match. This allows  | 
703  |  |   // `parseHookDeclarationFlow` to reparse the token and store useful  | 
704  |  |   // information. Additionally to be used within `checkDeclaration` this  | 
705  |  |   // function must be idempotent.  | 
706  | 0  |   OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
707  | 0  |   return optNext.hasValue() && *optNext == TokenKind::identifier;  | 
708  | 0  | }  | 
709  |  |  | 
710  | 0  | Optional<ESTree::Node *> JSParserImpl::parseHookDeclarationFlow(SMLoc start) { | 
711  |  |   // hook  | 
712  | 0  |   assert(check(hookIdent_));  | 
713  | 0  |   advance();  | 
714  |  |  | 
715  |  |   // identifier  | 
716  | 0  |   auto optId = parseBindingIdentifier(Param{}); | 
717  |  |  | 
718  |  |   // Hooks always require a name identifier  | 
719  | 0  |   if (!optId) { | 
720  | 0  |     errorExpected(  | 
721  | 0  |         TokenKind::identifier, "after 'hook'", "location of 'hook'", start);  | 
722  | 0  |     return None;  | 
723  | 0  |   }  | 
724  |  |  | 
725  | 0  |   ESTree::Node *typeParams = nullptr;  | 
726  |  | 
  | 
727  | 0  |   if (check(TokenKind::less)) { | 
728  | 0  |     auto optTypeParams = parseTypeParamsFlow();  | 
729  | 0  |     if (!optTypeParams)  | 
730  | 0  |       return None;  | 
731  | 0  |     typeParams = *optTypeParams;  | 
732  | 0  |   }  | 
733  |  |  | 
734  | 0  |   if (!need(  | 
735  | 0  |           TokenKind::l_paren,  | 
736  | 0  |           "at start of hook parameter list",  | 
737  | 0  |           "hook declaration starts here",  | 
738  | 0  |           start)) { | 
739  | 0  |     return None;  | 
740  | 0  |   }  | 
741  |  |  | 
742  | 0  |   ESTree::NodeList paramList;  | 
743  |  | 
  | 
744  | 0  |   if (!parseFormalParameters(Param{}, paramList)) | 
745  | 0  |     return None;  | 
746  |  |  | 
747  | 0  |   ESTree::Node *returnType = nullptr;  | 
748  |  | 
  | 
749  | 0  |   if (check(TokenKind::colon)) { | 
750  | 0  |     SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;  | 
751  |  |     // %checks predicates are unsupported in hooks.  | 
752  | 0  |     if (!check(checksIdent_)) { | 
753  | 0  |       auto optRet = parseReturnTypeAnnotationFlow(annotStart);  | 
754  | 0  |       if (!optRet)  | 
755  | 0  |         return None;  | 
756  | 0  |       returnType = *optRet;  | 
757  | 0  |     } else { | 
758  | 0  |       error(tok_->getStartLoc(), "checks predicates unsupported with hooks");  | 
759  | 0  |       return None;  | 
760  | 0  |     }  | 
761  | 0  |   }  | 
762  |  |  | 
763  | 0  |   if (!need(  | 
764  | 0  |           TokenKind::l_brace,  | 
765  | 0  |           "in hook declaration",  | 
766  | 0  |           "start of hook declaration",  | 
767  | 0  |           start)) { | 
768  | 0  |     return None;  | 
769  | 0  |   }  | 
770  |  |  | 
771  | 0  |   SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this}; | 
772  |  | 
  | 
773  | 0  |   auto parsedBody = parseFunctionBody(  | 
774  | 0  |       Param{}, false, false, false, JSLexer::AllowRegExp, true); | 
775  | 0  |   if (!parsedBody)  | 
776  | 0  |     return None;  | 
777  | 0  |   auto *body = parsedBody.getValue();  | 
778  |  | 
  | 
779  | 0  |   return setLocation(  | 
780  | 0  |       start,  | 
781  | 0  |       body,  | 
782  | 0  |       new (context_) ESTree::HookDeclarationNode(  | 
783  | 0  |           *optId, std::move(paramList), body, typeParams, returnType));  | 
784  | 0  | }  | 
785  |  |  | 
786  | 0  | bool JSParserImpl::checkMaybeFlowMatchSlowPath() { | 
787  | 0  |   assert(check(matchIdent_));  | 
788  | 0  |   OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
789  | 0  |   return optNext.hasValue() && *optNext == TokenKind::l_paren;  | 
790  | 0  | }  | 
791  |  |  | 
792  |  | ESTree::Node *JSParserImpl::reparseArgumentsAsMatchArgumentFlow(  | 
793  |  |     SMRange range,  | 
794  | 0  |     ESTree::NodeList &&argList) { | 
795  | 0  |   if (argList.empty()) { | 
796  | 0  |     error(range, "'match' argument must not be empty");  | 
797  | 0  |   }  | 
798  | 0  |   for (const ESTree::Node &arg : argList) { | 
799  | 0  |     if (isa<ESTree::SpreadElementNode>(arg)) { | 
800  | 0  |       error(  | 
801  | 0  |           arg.getSourceRange(),  | 
802  | 0  |           "'match' argument cannot contain spread elements");  | 
803  | 0  |     }  | 
804  | 0  |   }  | 
805  | 0  |   if (argList.size() == 1) { | 
806  | 0  |     auto expr = &argList.front();  | 
807  | 0  |     argList.clear();  | 
808  | 0  |     return expr;  | 
809  | 0  |   }  | 
810  | 0  |   return setLocation(  | 
811  | 0  |       range,  | 
812  | 0  |       range,  | 
813  | 0  |       new (context_) ESTree::SequenceExpressionNode(std::move(argList)));  | 
814  | 0  | }  | 
815  |  |  | 
816  | 0  | Optional<ESTree::Node *> JSParserImpl::tryParseMatchStatementFlow(Param param) { | 
817  | 0  |   SMLoc startLoc;  | 
818  | 0  |   SMLoc argsStartLoc;  | 
819  | 0  |   SMLoc argsEndLoc;  | 
820  | 0  |   ESTree::NodeList argList;  | 
821  | 0  |   { | 
822  |  |     // This save point is required because Flow supports both match statements  | 
823  |  |     // and match expressions, and we do not reserve `match` as a keyword. If  | 
824  |  |     // either of those points change in the future, this could be removed - see  | 
825  |  |     // blame for discussion.  | 
826  |  |     // We don't need to suppress errors as the only place that could error  | 
827  |  |     // in this section is `parseArguments`, and it would equivalently error  | 
828  |  |     // if this was parsed as an expression.  | 
829  | 0  |     JSLexer::SavePoint savePoint{&lexer_}; | 
830  |  |  | 
831  |  |     // Checked already by `checkMaybeFlowMatch`  | 
832  | 0  |     assert(check(matchIdent_));  | 
833  | 0  |     startLoc = advance().Start;  | 
834  |  |     // Checked already by `checkMaybeFlowMatch`  | 
835  | 0  |     assert(!lexer_.isNewLineBeforeCurrentToken());  | 
836  |  |  | 
837  | 0  |     argsStartLoc = tok_->getStartLoc();  | 
838  | 0  |     if (!parseArguments(argList, argsEndLoc))  | 
839  | 0  |       return None;  | 
840  |  |  | 
841  | 0  |     if (lexer_.isNewLineBeforeCurrentToken() || !check(TokenKind::l_brace)) { | 
842  |  |       // This is not a match statement.  | 
843  | 0  |       savePoint.restore();  | 
844  | 0  |       return nullptr;  | 
845  | 0  |     }  | 
846  | 0  |   }  | 
847  |  |   // We are unambiguously parsing a match statement now.  | 
848  |  |  | 
849  | 0  |   auto arg = reparseArgumentsAsMatchArgumentFlow(  | 
850  | 0  |       SMRange{argsStartLoc, argsEndLoc}, std::move(argList)); | 
851  |  | 
  | 
852  | 0  |   assert(check(TokenKind::l_brace));  | 
853  | 0  |   SMLoc lbraceLoc = advance().Start;  | 
854  |  | 
  | 
855  | 0  |   ESTree::NodeList cases;  | 
856  |  | 
  | 
857  | 0  |   while (!check(TokenKind::r_brace)) { | 
858  | 0  |     SMLoc caseStartLoc = tok_->getStartLoc();  | 
859  |  | 
  | 
860  | 0  |     auto optPattern = parseMatchPatternFlow();  | 
861  | 0  |     if (!optPattern)  | 
862  | 0  |       return None;  | 
863  |  |  | 
864  | 0  |     ESTree::Node *guard = nullptr;  | 
865  | 0  |     if (checkAndEat(TokenKind::rw_if)) { | 
866  | 0  |       auto optGuard = parseExpression(ParamIn, CoverTypedParameters::No);  | 
867  | 0  |       if (!optGuard)  | 
868  | 0  |         return None;  | 
869  | 0  |       guard = optGuard.getValue();  | 
870  | 0  |     }  | 
871  |  |  | 
872  | 0  |     if (!eat(  | 
873  | 0  |             TokenKind::colon,  | 
874  | 0  |             JSLexer::AllowRegExp,  | 
875  | 0  |             "after match pattern",  | 
876  | 0  |             "location of pattern",  | 
877  | 0  |             caseStartLoc))  | 
878  | 0  |       return None;  | 
879  |  |  | 
880  | 0  |     auto optBody = parseBlock(param.get(ParamReturn));  | 
881  | 0  |     if (!optBody)  | 
882  | 0  |       return None;  | 
883  |  |  | 
884  | 0  |     cases.push_back(*setLocation(  | 
885  | 0  |         caseStartLoc,  | 
886  | 0  |         *optBody,  | 
887  | 0  |         new (context_) ESTree::MatchStatementCaseNode(  | 
888  | 0  |             optPattern.getValue(), optBody.getValue(), guard)));  | 
889  |  | 
  | 
890  | 0  |     if (check(TokenKind::comma, TokenKind::semi)) { | 
891  | 0  |       advance();  | 
892  | 0  |     }  | 
893  | 0  |   }  | 
894  |  |  | 
895  | 0  |   SMLoc endLoc = tok_->getEndLoc();  | 
896  | 0  |   if (!eat(  | 
897  | 0  |           TokenKind::r_brace,  | 
898  | 0  |           JSLexer::AllowRegExp,  | 
899  | 0  |           "at end of 'match' statement",  | 
900  | 0  |           "location of '{'", | 
901  | 0  |           lbraceLoc))  | 
902  | 0  |     return None;  | 
903  |  |  | 
904  | 0  |   return setLocation(  | 
905  | 0  |       startLoc,  | 
906  | 0  |       endLoc,  | 
907  | 0  |       new (context_) ESTree::MatchStatementNode(arg, std::move(cases)));  | 
908  | 0  | }  | 
909  |  |  | 
910  | 0  | Optional<ESTree::Node *> JSParserImpl::parseMatchCallOrMatchExpressionFlow() { | 
911  | 0  |   SMLoc startLoc = tok_->getStartLoc();  | 
912  | 0  |   ESTree::Node *matchIdentNode = setLocation(  | 
913  | 0  |       tok_,  | 
914  | 0  |       tok_,  | 
915  | 0  |       new (context_)  | 
916  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
917  | 0  |   advance();  | 
918  |  | 
  | 
919  | 0  |   auto parenLoc = tok_->getStartLoc();  | 
920  | 0  |   ESTree::NodeList argList;  | 
921  | 0  |   SMLoc endLoc;  | 
922  |  | 
  | 
923  | 0  |   if (!parseArguments(argList, endLoc))  | 
924  | 0  |     return None;  | 
925  |  |  | 
926  | 0  |   if (!lexer_.isNewLineBeforeCurrentToken() && check(TokenKind::l_brace)) { | 
927  | 0  |     auto arg = reparseArgumentsAsMatchArgumentFlow(  | 
928  | 0  |         SMRange{parenLoc, endLoc}, std::move(argList)); | 
929  | 0  |     return parseMatchExpressionFlow(startLoc, arg);  | 
930  | 0  |   }  | 
931  |  |  | 
932  | 0  |   auto callNode = setLocation(  | 
933  | 0  |       startLoc,  | 
934  | 0  |       endLoc,  | 
935  | 0  |       parenLoc,  | 
936  | 0  |       new (context_) ESTree::CallExpressionNode(  | 
937  | 0  |           matchIdentNode, nullptr, std::move(argList)));  | 
938  | 0  |   auto optExpr = parseOptionalExpressionExceptNew_tail(  | 
939  | 0  |       IsConstructorCall::No, startLoc, callNode);  | 
940  | 0  |   if (!optExpr) { | 
941  | 0  |     return None;  | 
942  | 0  |   }  | 
943  | 0  |   return parseLeftHandSideExpressionTail(startLoc, optExpr.getValue());  | 
944  | 0  | }  | 
945  |  |  | 
946  |  | Optional<ESTree::Node *> JSParserImpl::parseMatchExpressionFlow(  | 
947  |  |     SMLoc startLoc,  | 
948  | 0  |     ESTree::Node *argument) { | 
949  | 0  |   assert(check(TokenKind::l_brace));  | 
950  | 0  |   SMLoc lbraceLoc = advance().Start;  | 
951  |  | 
  | 
952  | 0  |   ESTree::NodeList cases;  | 
953  |  | 
  | 
954  | 0  |   while (!check(TokenKind::r_brace)) { | 
955  | 0  |     SMLoc caseStartLoc = tok_->getStartLoc();  | 
956  |  | 
  | 
957  | 0  |     auto optPattern = parseMatchPatternFlow();  | 
958  | 0  |     if (!optPattern)  | 
959  | 0  |       return None;  | 
960  |  |  | 
961  | 0  |     ESTree::Node *guard = nullptr;  | 
962  | 0  |     if (checkAndEat(TokenKind::rw_if)) { | 
963  | 0  |       auto optGuard = parseExpression(ParamIn, CoverTypedParameters::No);  | 
964  | 0  |       if (!optGuard)  | 
965  | 0  |         return None;  | 
966  | 0  |       guard = optGuard.getValue();  | 
967  | 0  |     }  | 
968  |  |  | 
969  | 0  |     if (!eat(  | 
970  | 0  |             TokenKind::colon,  | 
971  | 0  |             JSLexer::AllowRegExp,  | 
972  | 0  |             "after match pattern",  | 
973  | 0  |             "location of pattern",  | 
974  | 0  |             caseStartLoc))  | 
975  | 0  |       return None;  | 
976  |  |  | 
977  | 0  |     auto optBody = parseAssignmentExpression();  | 
978  | 0  |     if (!optBody)  | 
979  | 0  |       return None;  | 
980  |  |  | 
981  | 0  |     cases.push_back(*setLocation(  | 
982  | 0  |         caseStartLoc,  | 
983  | 0  |         *optBody,  | 
984  | 0  |         new (context_) ESTree::MatchExpressionCaseNode(  | 
985  | 0  |             optPattern.getValue(), optBody.getValue(), guard)));  | 
986  |  | 
  | 
987  | 0  |     if (!(checkAndEat(TokenKind::comma) || checkAndEat(TokenKind::semi)))  | 
988  | 0  |       break;  | 
989  | 0  |   }  | 
990  |  |  | 
991  | 0  |   SMLoc endLoc = tok_->getEndLoc();  | 
992  | 0  |   if (!eat(  | 
993  | 0  |           TokenKind::r_brace,  | 
994  | 0  |           JSLexer::AllowRegExp,  | 
995  | 0  |           "at end of 'match' expression",  | 
996  | 0  |           "location of '{'", | 
997  | 0  |           lbraceLoc))  | 
998  | 0  |     return None;  | 
999  |  |  | 
1000  | 0  |   return setLocation(  | 
1001  | 0  |       startLoc,  | 
1002  | 0  |       endLoc,  | 
1003  | 0  |       new (context_) ESTree::MatchExpressionNode(argument, std::move(cases)));  | 
1004  | 0  | }  | 
1005  |  |  | 
1006  | 0  | Optional<ESTree::Node *> JSParserImpl::parseMatchPatternFlow() { | 
1007  | 0  |   SMLoc startLoc = tok_->getStartLoc();  | 
1008  | 0  |   auto optFirstPattern = parseMatchSubpatternFlow();  | 
1009  | 0  |   if (!optFirstPattern)  | 
1010  | 0  |     return None;  | 
1011  | 0  |   ESTree::Node *pattern = optFirstPattern.getValue();  | 
1012  | 0  |   if (check(TokenKind::pipe)) { | 
1013  | 0  |     ESTree::NodeList patterns{}; | 
1014  | 0  |     patterns.push_back(*optFirstPattern.getValue());  | 
1015  | 0  |     while (checkAndEat(TokenKind::pipe)) { | 
1016  | 0  |       auto optPattern = parseMatchSubpatternFlow();  | 
1017  | 0  |       if (!optPattern)  | 
1018  | 0  |         return None;  | 
1019  | 0  |       patterns.push_back(*optPattern.getValue());  | 
1020  | 0  |     }  | 
1021  | 0  |     pattern = setLocation(  | 
1022  | 0  |         startLoc,  | 
1023  | 0  |         getPrevTokenEndLoc(),  | 
1024  | 0  |         new (context_) ESTree::MatchOrPatternNode(std::move(patterns)));  | 
1025  | 0  |   }  | 
1026  | 0  |   if (checkAndEat(asIdent_)) { | 
1027  | 0  |     ESTree::Node *target = nullptr;  | 
1028  | 0  |     if (checkN(TokenKind::rw_const, TokenKind::rw_var, letIdent_)) { | 
1029  | 0  |       auto optTarget = parseMatchBindingPatternFlow();  | 
1030  | 0  |       if (!optTarget)  | 
1031  | 0  |         return None;  | 
1032  | 0  |       target = optTarget.getValue();  | 
1033  | 0  |     } else if (check(TokenKind::identifier) || tok_->isResWord()) { | 
1034  | 0  |       auto optTarget = parseMatchBindingIdentifierFlow();  | 
1035  | 0  |       if (!optTarget)  | 
1036  | 0  |         return None;  | 
1037  | 0  |       target = optTarget.getValue();  | 
1038  | 0  |     } else { | 
1039  | 0  |       error(tok_->getSourceRange(), "expected identifier or binding pattern");  | 
1040  | 0  |       return None;  | 
1041  | 0  |     }  | 
1042  | 0  |     pattern = setLocation(  | 
1043  | 0  |         startLoc,  | 
1044  | 0  |         getPrevTokenEndLoc(),  | 
1045  | 0  |         new (context_) ESTree::MatchAsPatternNode(pattern, target));  | 
1046  | 0  |   }  | 
1047  | 0  |   return pattern;  | 
1048  | 0  | }  | 
1049  |  |  | 
1050  | 0  | Optional<ESTree::Node *> JSParserImpl::parseMatchSubpatternFlow() { | 
1051  | 0  |   switch (tok_->getKind()) { | 
1052  | 0  |     case TokenKind::rw_null: { | 
1053  | 0  |       auto *lit =  | 
1054  | 0  |           setLocation(tok_, tok_, new (context_) ESTree::NullLiteralNode());  | 
1055  | 0  |       auto *pat = setLocation(  | 
1056  | 0  |           tok_, tok_, new (context_) ESTree::MatchLiteralPatternNode(lit));  | 
1057  | 0  |       advance(JSLexer::AllowDiv);  | 
1058  | 0  |       return pat;  | 
1059  | 0  |     }  | 
1060  |  |  | 
1061  | 0  |     case TokenKind::rw_true:  | 
1062  | 0  |     case TokenKind::rw_false: { | 
1063  | 0  |       auto *lit = setLocation(  | 
1064  | 0  |           tok_,  | 
1065  | 0  |           tok_,  | 
1066  | 0  |           new (context_) ESTree::BooleanLiteralNode(  | 
1067  | 0  |               tok_->getKind() == TokenKind::rw_true));  | 
1068  | 0  |       auto *pat = setLocation(  | 
1069  | 0  |           tok_, tok_, new (context_) ESTree::MatchLiteralPatternNode(lit));  | 
1070  | 0  |       advance(JSLexer::AllowDiv);  | 
1071  | 0  |       return pat;  | 
1072  | 0  |     }  | 
1073  |  |  | 
1074  | 0  |     case TokenKind::numeric_literal: { | 
1075  | 0  |       auto *lit = setLocation(  | 
1076  | 0  |           tok_,  | 
1077  | 0  |           tok_,  | 
1078  | 0  |           new (context_) ESTree::NumericLiteralNode(tok_->getNumericLiteral()));  | 
1079  | 0  |       auto *pat = setLocation(  | 
1080  | 0  |           tok_, tok_, new (context_) ESTree::MatchLiteralPatternNode(lit));  | 
1081  | 0  |       advance(JSLexer::AllowDiv);  | 
1082  | 0  |       return pat;  | 
1083  | 0  |     }  | 
1084  |  |  | 
1085  | 0  |     case TokenKind::bigint_literal: { | 
1086  | 0  |       auto *lit = setLocation(  | 
1087  | 0  |           tok_,  | 
1088  | 0  |           tok_,  | 
1089  | 0  |           new (context_) ESTree::BigIntLiteralNode(tok_->getBigIntLiteral()));  | 
1090  | 0  |       auto *pat = setLocation(  | 
1091  | 0  |           tok_, tok_, new (context_) ESTree::MatchLiteralPatternNode(lit));  | 
1092  | 0  |       advance(JSLexer::AllowDiv);  | 
1093  | 0  |       return pat;  | 
1094  | 0  |     }  | 
1095  |  |  | 
1096  | 0  |     case TokenKind::string_literal: { | 
1097  | 0  |       auto *lit = setLocation(  | 
1098  | 0  |           tok_,  | 
1099  | 0  |           tok_,  | 
1100  | 0  |           new (context_) ESTree::StringLiteralNode(tok_->getStringLiteral()));  | 
1101  | 0  |       auto *pat = setLocation(  | 
1102  | 0  |           tok_, tok_, new (context_) ESTree::MatchLiteralPatternNode(lit));  | 
1103  | 0  |       advance(JSLexer::AllowDiv);  | 
1104  | 0  |       return pat;  | 
1105  | 0  |     }  | 
1106  |  |  | 
1107  | 0  |     case TokenKind::identifier: { | 
1108  | 0  |       if (check(underscoreIdent_)) { | 
1109  | 0  |         auto *pat = setLocation(  | 
1110  | 0  |             tok_, tok_, new (context_) ESTree::MatchWildcardPatternNode());  | 
1111  | 0  |         advance(JSLexer::AllowDiv);  | 
1112  | 0  |         return pat;  | 
1113  | 0  |       }  | 
1114  | 0  |       if (check(letIdent_)) { | 
1115  | 0  |         auto pat = parseMatchBindingPatternFlow();  | 
1116  | 0  |         if (!pat)  | 
1117  | 0  |           return None;  | 
1118  | 0  |         return pat.getValue();  | 
1119  | 0  |       }  | 
1120  | 0  |       SMLoc start_loc = tok_->getStartLoc();  | 
1121  | 0  |       auto *ident = setLocation(  | 
1122  | 0  |           tok_,  | 
1123  | 0  |           tok_,  | 
1124  | 0  |           new (context_)  | 
1125  | 0  |               ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
1126  | 0  |       ESTree::Node *pat = setLocation(  | 
1127  | 0  |           tok_, tok_, new (context_) ESTree::MatchIdentifierPatternNode(ident));  | 
1128  | 0  |       advance(JSLexer::AllowDiv);  | 
1129  |  | 
  | 
1130  | 0  |       while (check(TokenKind::period, TokenKind::l_square)) { | 
1131  | 0  |         if (checkAndEat(TokenKind::period)) { | 
1132  | 0  |           if (!need(  | 
1133  | 0  |                   TokenKind::identifier,  | 
1134  | 0  |                   "in match member pattern",  | 
1135  | 0  |                   nullptr,  | 
1136  | 0  |                   {})) | 
1137  | 0  |             return None;  | 
1138  | 0  |           auto *property = setLocation(  | 
1139  | 0  |               tok_,  | 
1140  | 0  |               tok_,  | 
1141  | 0  |               new (context_) ESTree::IdentifierNode(  | 
1142  | 0  |                   tok_->getIdentifier(), nullptr, false));  | 
1143  | 0  |           advance(JSLexer::AllowDiv);  | 
1144  | 0  |           pat = setLocation(  | 
1145  | 0  |               start_loc,  | 
1146  | 0  |               getPrevTokenEndLoc(),  | 
1147  | 0  |               new (context_) ESTree::MatchMemberPatternNode(pat, property));  | 
1148  | 0  |         } else { | 
1149  | 0  |           SMLoc computedStartLoc = advance().Start; // Eat `[`  | 
1150  | 0  |           ESTree::Node *property = nullptr;  | 
1151  | 0  |           switch (tok_->getKind()) { | 
1152  | 0  |             case TokenKind::numeric_literal: { | 
1153  | 0  |               property = setLocation(  | 
1154  | 0  |                   tok_,  | 
1155  | 0  |                   tok_,  | 
1156  | 0  |                   new (context_)  | 
1157  | 0  |                       ESTree::NumericLiteralNode(tok_->getNumericLiteral()));  | 
1158  | 0  |               advance(JSLexer::AllowDiv);  | 
1159  | 0  |               break;  | 
1160  | 0  |             }  | 
1161  | 0  |             case TokenKind::bigint_literal: { | 
1162  | 0  |               property = setLocation(  | 
1163  | 0  |                   tok_,  | 
1164  | 0  |                   tok_,  | 
1165  | 0  |                   new (context_)  | 
1166  | 0  |                       ESTree::BigIntLiteralNode(tok_->getBigIntLiteral()));  | 
1167  | 0  |               advance(JSLexer::AllowDiv);  | 
1168  | 0  |               break;  | 
1169  | 0  |             }  | 
1170  | 0  |             case TokenKind::string_literal: { | 
1171  | 0  |               property = setLocation(  | 
1172  | 0  |                   tok_,  | 
1173  | 0  |                   tok_,  | 
1174  | 0  |                   new (context_)  | 
1175  | 0  |                       ESTree::StringLiteralNode(tok_->getStringLiteral()));  | 
1176  | 0  |               advance(JSLexer::AllowDiv);  | 
1177  | 0  |               break;  | 
1178  | 0  |             }  | 
1179  | 0  |             default: { | 
1180  | 0  |               errorExpected(  | 
1181  | 0  |                   {TokenKind::numeric_literal, | 
1182  | 0  |                    TokenKind::bigint_literal,  | 
1183  | 0  |                    TokenKind::string_literal},  | 
1184  | 0  |                   "in match member pattern computed property",  | 
1185  | 0  |                   "start of computed property",  | 
1186  | 0  |                   computedStartLoc);  | 
1187  | 0  |               return None;  | 
1188  | 0  |             }  | 
1189  | 0  |           }  | 
1190  | 0  |           if (!eat(  | 
1191  | 0  |                   TokenKind::r_square,  | 
1192  | 0  |                   JSLexer::AllowDiv,  | 
1193  | 0  |                   "at end of computed member property",  | 
1194  | 0  |                   "location of '['",  | 
1195  | 0  |                   computedStartLoc))  | 
1196  | 0  |             return None;  | 
1197  | 0  |           pat = setLocation(  | 
1198  | 0  |               start_loc,  | 
1199  | 0  |               getPrevTokenEndLoc(),  | 
1200  | 0  |               new (context_) ESTree::MatchMemberPatternNode(pat, property));  | 
1201  | 0  |         }  | 
1202  | 0  |       }  | 
1203  | 0  |       return pat;  | 
1204  | 0  |     }  | 
1205  |  |  | 
1206  | 0  |     case TokenKind::plus:  | 
1207  | 0  |     case TokenKind::minus: { | 
1208  | 0  |       UniqueString *op = getTokenIdent(tok_->getKind());  | 
1209  | 0  |       SMLoc startLoc = advance().Start;  | 
1210  |  | 
  | 
1211  | 0  |       ESTree::Node *argument;  | 
1212  | 0  |       switch (tok_->getKind()) { | 
1213  | 0  |         case TokenKind::numeric_literal: { | 
1214  | 0  |           argument = setLocation(  | 
1215  | 0  |               tok_,  | 
1216  | 0  |               tok_,  | 
1217  | 0  |               new (context_)  | 
1218  | 0  |                   ESTree::NumericLiteralNode(tok_->getNumericLiteral()));  | 
1219  | 0  |           advance(JSLexer::AllowDiv);  | 
1220  | 0  |           break;  | 
1221  | 0  |         }  | 
1222  | 0  |         case TokenKind::bigint_literal: { | 
1223  | 0  |           argument = setLocation(  | 
1224  | 0  |               tok_,  | 
1225  | 0  |               tok_,  | 
1226  | 0  |               new (context_)  | 
1227  | 0  |                   ESTree::BigIntLiteralNode(tok_->getBigIntLiteral()));  | 
1228  | 0  |           advance(JSLexer::AllowDiv);  | 
1229  | 0  |           break;  | 
1230  | 0  |         }  | 
1231  | 0  |         default:  | 
1232  | 0  |           error(tok_->getStartLoc(), "invalid match unary pattern argument");  | 
1233  | 0  |           return None;  | 
1234  | 0  |       }  | 
1235  | 0  |       return setLocation(  | 
1236  | 0  |           startLoc,  | 
1237  | 0  |           getPrevTokenEndLoc(),  | 
1238  | 0  |           new (context_) ESTree::MatchUnaryPatternNode(argument, op));  | 
1239  | 0  |     }  | 
1240  |  |  | 
1241  | 0  |     case TokenKind::rw_const:  | 
1242  | 0  |     case TokenKind::rw_var: { | 
1243  | 0  |       auto pat = parseMatchBindingPatternFlow();  | 
1244  | 0  |       if (!pat)  | 
1245  | 0  |         return None;  | 
1246  | 0  |       return pat.getValue();  | 
1247  | 0  |     }  | 
1248  |  |  | 
1249  | 0  |     case TokenKind::l_paren: { | 
1250  | 0  |       SMLoc startLoc = advance().Start;  | 
1251  | 0  |       auto optPattern = parseMatchPatternFlow();  | 
1252  | 0  |       if (!optPattern)  | 
1253  | 0  |         return None;  | 
1254  |  |  | 
1255  | 0  |       if (!eat(  | 
1256  | 0  |               TokenKind::r_paren,  | 
1257  | 0  |               JSLexer::AllowDiv,  | 
1258  | 0  |               "at end of a match pattern group",  | 
1259  | 0  |               "location of '('", | 
1260  | 0  |               startLoc))  | 
1261  | 0  |         return None;  | 
1262  |  |  | 
1263  | 0  |       return optPattern.getValue();  | 
1264  | 0  |     }  | 
1265  |  |  | 
1266  | 0  |     case TokenKind::l_brace:  | 
1267  | 0  |       return parseMatchObjectPatternFlow();  | 
1268  |  |  | 
1269  | 0  |     case TokenKind::l_square:  | 
1270  | 0  |       return parseMatchArrayPatternFlow();  | 
1271  |  |  | 
1272  | 0  |     default:  | 
1273  | 0  |       error(tok_->getStartLoc(), "invalid match pattern");  | 
1274  | 0  |       return None;  | 
1275  | 0  |   }  | 
1276  | 0  | }  | 
1277  |  |  | 
1278  |  | Optional<ESTree::IdentifierNode *>  | 
1279  | 0  | JSParserImpl::parseMatchBindingIdentifierFlow() { | 
1280  | 0  |   UniqueString *id = tok_->getResWordOrIdentifier();  | 
1281  | 0  |   TokenKind kind = tok_->getKind();  | 
1282  | 0  |   if (!validateBindingIdentifier(Param{}, tok_->getSourceRange(), id, kind)) | 
1283  | 0  |     return None;  | 
1284  | 0  |   advance();  | 
1285  | 0  |   return setLocation(  | 
1286  | 0  |       tok_, tok_, new (context_) ESTree::IdentifierNode(id, nullptr, false));  | 
1287  | 0  | }  | 
1288  |  |  | 
1289  |  | Optional<ESTree::MatchBindingPatternNode *>  | 
1290  | 0  | JSParserImpl::parseMatchBindingPatternFlow() { | 
1291  | 0  |   assert(checkN(TokenKind::rw_const, TokenKind::rw_var, letIdent_));  | 
1292  | 0  |   auto kind = tok_->getResWordOrIdentifier();  | 
1293  | 0  |   SMLoc startLoc = advance().Start;  | 
1294  | 0  |   if (!check(TokenKind::identifier) && !tok_->isResWord()) { | 
1295  | 0  |     errorExpected(  | 
1296  | 0  |         TokenKind::identifier,  | 
1297  | 0  |         "in match binding pattern",  | 
1298  | 0  |         "start of binding pattern",  | 
1299  | 0  |         startLoc);  | 
1300  | 0  |   }  | 
1301  | 0  |   auto optIdent = parseMatchBindingIdentifierFlow();  | 
1302  | 0  |   if (!optIdent)  | 
1303  | 0  |     return None;  | 
1304  | 0  |   return setLocation(  | 
1305  | 0  |       startLoc,  | 
1306  | 0  |       getPrevTokenEndLoc(),  | 
1307  | 0  |       new (context_)  | 
1308  | 0  |           ESTree::MatchBindingPatternNode(optIdent.getValue(), kind));  | 
1309  | 0  | }  | 
1310  |  |  | 
1311  | 0  | Optional<ESTree::Node *> JSParserImpl::parseMatchRestPatternFlow() { | 
1312  | 0  |   assert(check(TokenKind::dotdotdot));  | 
1313  | 0  |   SMLoc restStartLoc = advance().Start;  | 
1314  | 0  |   ESTree::Node *arg = nullptr;  | 
1315  | 0  |   if (checkN(TokenKind::rw_const, TokenKind::rw_var, letIdent_)) { | 
1316  | 0  |     auto optArg = parseMatchBindingPatternFlow();  | 
1317  | 0  |     if (!optArg)  | 
1318  | 0  |       return None;  | 
1319  | 0  |     arg = optArg.getValue();  | 
1320  | 0  |   }  | 
1321  | 0  |   return setLocation(  | 
1322  | 0  |       restStartLoc,  | 
1323  | 0  |       getPrevTokenEndLoc(),  | 
1324  | 0  |       new (context_) ESTree::MatchRestPatternNode(arg));  | 
1325  | 0  | }  | 
1326  |  |  | 
1327  | 0  | Optional<ESTree::Node *> JSParserImpl::parseMatchObjectPatternFlow() { | 
1328  | 0  |   assert(check(TokenKind::l_brace));  | 
1329  | 0  |   auto startLoc = advance().Start;  | 
1330  | 0  |   ESTree::NodeList properties{}; | 
1331  | 0  |   ESTree::Node *rest = nullptr;  | 
1332  |  | 
  | 
1333  | 0  |   while (!check(TokenKind::r_brace)) { | 
1334  | 0  |     if (check(TokenKind::dotdotdot)) { | 
1335  | 0  |       auto optRest = parseMatchRestPatternFlow();  | 
1336  | 0  |       if (!optRest) { | 
1337  | 0  |         return None;  | 
1338  | 0  |       }  | 
1339  | 0  |       rest = optRest.getValue();  | 
1340  | 0  |       break;  | 
1341  | 0  |     }  | 
1342  |  |  | 
1343  | 0  |     ESTree::Node *prop = nullptr;  | 
1344  | 0  |     auto propStartLoc = tok_->getStartLoc();  | 
1345  | 0  |     if (checkN(TokenKind::rw_const, TokenKind::rw_var, letIdent_)) { | 
1346  |  |       // Shorthand syntax: e.g. `const x` is shorthand for `x: const x`  | 
1347  | 0  |       auto optBindingPattern = parseMatchBindingPatternFlow();  | 
1348  | 0  |       if (!optBindingPattern)  | 
1349  | 0  |         return None;  | 
1350  | 0  |       auto bindingPattern = optBindingPattern.getValue();  | 
1351  | 0  |       prop = setLocation(  | 
1352  | 0  |           propStartLoc,  | 
1353  | 0  |           getPrevTokenEndLoc(),  | 
1354  | 0  |           new (context_) ESTree::MatchObjectPatternPropertyNode(  | 
1355  | 0  |               bindingPattern->_id, bindingPattern, true));  | 
1356  | 0  |     } else { | 
1357  |  |       // Normal property  | 
1358  | 0  |       ESTree::Node *key = nullptr;  | 
1359  |  |       // Property key parsing  | 
1360  | 0  |       switch (tok_->getKind()) { | 
1361  | 0  |         case TokenKind::identifier: { | 
1362  | 0  |           key = setLocation(  | 
1363  | 0  |               tok_,  | 
1364  | 0  |               tok_,  | 
1365  | 0  |               new (context_) ESTree::IdentifierNode(  | 
1366  | 0  |                   tok_->getIdentifier(), nullptr, false));  | 
1367  | 0  |           advance(JSLexer::AllowDiv);  | 
1368  | 0  |           break;  | 
1369  | 0  |         }  | 
1370  | 0  |         case TokenKind::string_literal: { | 
1371  | 0  |           key = setLocation(  | 
1372  | 0  |               tok_,  | 
1373  | 0  |               tok_,  | 
1374  | 0  |               new (context_)  | 
1375  | 0  |                   ESTree::StringLiteralNode(tok_->getStringLiteral()));  | 
1376  | 0  |           advance(JSLexer::AllowDiv);  | 
1377  | 0  |           break;  | 
1378  | 0  |         }  | 
1379  | 0  |         case TokenKind::numeric_literal: { | 
1380  | 0  |           key = setLocation(  | 
1381  | 0  |               tok_,  | 
1382  | 0  |               tok_,  | 
1383  | 0  |               new (context_)  | 
1384  | 0  |                   ESTree::NumericLiteralNode(tok_->getNumericLiteral()));  | 
1385  | 0  |           advance(JSLexer::AllowDiv);  | 
1386  | 0  |           break;  | 
1387  | 0  |         }  | 
1388  | 0  |         case TokenKind::bigint_literal: { | 
1389  | 0  |           key = setLocation(  | 
1390  | 0  |               tok_,  | 
1391  | 0  |               tok_,  | 
1392  | 0  |               new (context_)  | 
1393  | 0  |                   ESTree::BigIntLiteralNode(tok_->getBigIntLiteral()));  | 
1394  | 0  |           advance(JSLexer::AllowDiv);  | 
1395  | 0  |           break;  | 
1396  | 0  |         }  | 
1397  | 0  |         default: { | 
1398  | 0  |           errorExpected(  | 
1399  | 0  |               {TokenKind::identifier, | 
1400  | 0  |                TokenKind::string_literal,  | 
1401  | 0  |                TokenKind::numeric_literal,  | 
1402  | 0  |                TokenKind::bigint_literal},  | 
1403  | 0  |               "in match object pattern property key",  | 
1404  | 0  |               "start of match object pattern property key",  | 
1405  | 0  |               propStartLoc);  | 
1406  | 0  |           return None;  | 
1407  | 0  |         }  | 
1408  | 0  |       }  | 
1409  | 0  |       if (!eat(  | 
1410  | 0  |               TokenKind::colon,  | 
1411  | 0  |               JSLexer::AllowRegExp,  | 
1412  | 0  |               "in match object pattern property",  | 
1413  | 0  |               "start of match object pattern property",  | 
1414  | 0  |               propStartLoc))  | 
1415  | 0  |         return None;  | 
1416  | 0  |       auto optPattern = parseMatchPatternFlow();  | 
1417  | 0  |       prop = setLocation(  | 
1418  | 0  |           propStartLoc,  | 
1419  | 0  |           getPrevTokenEndLoc(),  | 
1420  | 0  |           new (context_) ESTree::MatchObjectPatternPropertyNode(  | 
1421  | 0  |               key, optPattern.getValue(), false));  | 
1422  | 0  |     }  | 
1423  | 0  |     properties.push_back(*prop);  | 
1424  | 0  |     if (!checkAndEat(TokenKind::comma))  | 
1425  | 0  |       break;  | 
1426  | 0  |   }  | 
1427  | 0  |   if (!eat(  | 
1428  | 0  |           TokenKind::r_brace,  | 
1429  | 0  |           JSLexer::AllowDiv,  | 
1430  | 0  |           "at end of object match pattern",  | 
1431  | 0  |           "location of '{'", | 
1432  | 0  |           startLoc))  | 
1433  | 0  |     return None;  | 
1434  |  |  | 
1435  | 0  |   return setLocation(  | 
1436  | 0  |       startLoc,  | 
1437  | 0  |       getPrevTokenEndLoc(),  | 
1438  | 0  |       new (context_)  | 
1439  | 0  |           ESTree::MatchObjectPatternNode(std::move(properties), rest));  | 
1440  | 0  | }  | 
1441  |  |  | 
1442  | 0  | Optional<ESTree::Node *> JSParserImpl::parseMatchArrayPatternFlow() { | 
1443  | 0  |   assert(check(TokenKind::l_square));  | 
1444  | 0  |   auto startLoc = advance().Start;  | 
1445  | 0  |   ESTree::NodeList elements{}; | 
1446  | 0  |   ESTree::Node *rest = nullptr;  | 
1447  |  | 
  | 
1448  | 0  |   while (!check(TokenKind::r_square)) { | 
1449  | 0  |     if (check(TokenKind::dotdotdot)) { | 
1450  | 0  |       auto optRest = parseMatchRestPatternFlow();  | 
1451  | 0  |       if (!optRest) { | 
1452  | 0  |         return None;  | 
1453  | 0  |       }  | 
1454  | 0  |       rest = optRest.getValue();  | 
1455  | 0  |       break;  | 
1456  | 0  |     }  | 
1457  |  |  | 
1458  | 0  |     auto optPattern = parseMatchPatternFlow();  | 
1459  | 0  |     if (!optPattern)  | 
1460  | 0  |       return None;  | 
1461  | 0  |     elements.push_back(*optPattern.getValue());  | 
1462  | 0  |     if (!checkAndEat(TokenKind::comma))  | 
1463  | 0  |       break;  | 
1464  | 0  |   }  | 
1465  | 0  |   if (!eat(  | 
1466  | 0  |           TokenKind::r_square,  | 
1467  | 0  |           JSLexer::AllowDiv,  | 
1468  | 0  |           "at end of array match pattern",  | 
1469  | 0  |           "location of '['",  | 
1470  | 0  |           startLoc))  | 
1471  | 0  |     return None;  | 
1472  |  |  | 
1473  | 0  |   return setLocation(  | 
1474  | 0  |       startLoc,  | 
1475  | 0  |       getPrevTokenEndLoc(),  | 
1476  | 0  |       new (context_) ESTree::MatchArrayPatternNode(std::move(elements), rest));  | 
1477  | 0  | }  | 
1478  |  |  | 
1479  |  | Optional<ESTree::Node *> JSParserImpl::parseTypeAliasFlow(  | 
1480  |  |     SMLoc start,  | 
1481  | 0  |     TypeAliasKind kind) { | 
1482  | 0  |   if (!need(  | 
1483  | 0  |           TokenKind::identifier, "in type alias", "start of type alias", start))  | 
1484  | 0  |     return None;  | 
1485  |  |  | 
1486  | 0  |   ESTree::Node *id = setLocation(  | 
1487  | 0  |       tok_,  | 
1488  | 0  |       tok_,  | 
1489  | 0  |       new (context_)  | 
1490  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
1491  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1492  |  | 
  | 
1493  | 0  |   ESTree::Node *typeParams = nullptr;  | 
1494  | 0  |   if (check(TokenKind::less)) { | 
1495  | 0  |     auto optTypeParams = parseTypeParamsFlow();  | 
1496  | 0  |     if (!optTypeParams)  | 
1497  | 0  |       return None;  | 
1498  | 0  |     typeParams = *optTypeParams;  | 
1499  | 0  |   }  | 
1500  |  |  | 
1501  | 0  |   ESTree::Node *supertype = nullptr;  | 
1502  | 0  |   if ((kind == TypeAliasKind::Opaque || kind == TypeAliasKind::DeclareOpaque) &&  | 
1503  | 0  |       checkAndEat(TokenKind::colon, JSLexer::GrammarContext::Type)) { | 
1504  | 0  |     auto optSuper = parseTypeAnnotationFlow();  | 
1505  | 0  |     if (!optSuper)  | 
1506  | 0  |       return None;  | 
1507  | 0  |     supertype = *optSuper;  | 
1508  | 0  |   }  | 
1509  |  |  | 
1510  | 0  |   ESTree::Node *right = nullptr;  | 
1511  | 0  |   if (kind != TypeAliasKind::DeclareOpaque) { | 
1512  | 0  |     if (!eat(  | 
1513  | 0  |             TokenKind::equal,  | 
1514  | 0  |             JSLexer::GrammarContext::Type,  | 
1515  | 0  |             "in type alias",  | 
1516  | 0  |             "start of type alias",  | 
1517  | 0  |             start))  | 
1518  | 0  |       return None;  | 
1519  |  |  | 
1520  | 0  |     auto optRight = parseTypeAnnotationFlow();  | 
1521  | 0  |     if (!optRight)  | 
1522  | 0  |       return None;  | 
1523  | 0  |     right = *optRight;  | 
1524  | 0  |   }  | 
1525  |  |  | 
1526  | 0  |   if (!eatSemi())  | 
1527  | 0  |     return None;  | 
1528  |  |  | 
1529  | 0  |   if (kind == TypeAliasKind::DeclareOpaque) { | 
1530  | 0  |     return setLocation(  | 
1531  | 0  |         start,  | 
1532  | 0  |         getPrevTokenEndLoc(),  | 
1533  | 0  |         new (context_)  | 
1534  | 0  |             ESTree::DeclareOpaqueTypeNode(id, typeParams, right, supertype));  | 
1535  | 0  |   }  | 
1536  | 0  |   if (kind == TypeAliasKind::Declare) { | 
1537  | 0  |     return setLocation(  | 
1538  | 0  |         start,  | 
1539  | 0  |         getPrevTokenEndLoc(),  | 
1540  | 0  |         new (context_) ESTree::DeclareTypeAliasNode(id, typeParams, right));  | 
1541  | 0  |   }  | 
1542  | 0  |   if (kind == TypeAliasKind::Opaque) { | 
1543  | 0  |     return setLocation(  | 
1544  | 0  |         start,  | 
1545  | 0  |         getPrevTokenEndLoc(),  | 
1546  | 0  |         new (context_)  | 
1547  | 0  |             ESTree::OpaqueTypeNode(id, typeParams, right, supertype));  | 
1548  | 0  |   }  | 
1549  | 0  |   return setLocation(  | 
1550  | 0  |       start,  | 
1551  | 0  |       getPrevTokenEndLoc(),  | 
1552  | 0  |       new (context_) ESTree::TypeAliasNode(id, typeParams, right));  | 
1553  | 0  | }  | 
1554  |  |  | 
1555  |  | Optional<ESTree::Node *> JSParserImpl::parseInterfaceDeclarationFlow(  | 
1556  | 0  |     Optional<SMLoc> declareStart) { | 
1557  | 0  |   assert(checkN(TokenKind::rw_interface, interfaceIdent_));  | 
1558  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
1559  |  | 
  | 
1560  | 0  |   if (!need(  | 
1561  | 0  |           TokenKind::identifier,  | 
1562  | 0  |           "in interface declaration",  | 
1563  | 0  |           "start of interface",  | 
1564  | 0  |           start))  | 
1565  | 0  |     return None;  | 
1566  |  |  | 
1567  | 0  |   auto *id = setLocation(  | 
1568  | 0  |       tok_,  | 
1569  | 0  |       tok_,  | 
1570  | 0  |       new (context_)  | 
1571  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
1572  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1573  |  | 
  | 
1574  | 0  |   ESTree::Node *typeParams = nullptr;  | 
1575  | 0  |   if (check(TokenKind::less)) { | 
1576  | 0  |     auto optParams = parseTypeParamsFlow();  | 
1577  | 0  |     if (!optParams)  | 
1578  | 0  |       return None;  | 
1579  | 0  |     typeParams = *optParams;  | 
1580  | 0  |   }  | 
1581  |  |  | 
1582  | 0  |   ESTree::NodeList extends{}; | 
1583  |  | 
  | 
1584  | 0  |   auto optBody = parseInterfaceTailFlow(start, extends);  | 
1585  | 0  |   if (!optBody)  | 
1586  | 0  |     return None;  | 
1587  |  |  | 
1588  | 0  |   if (declareStart.hasValue()) { | 
1589  | 0  |     return setLocation(  | 
1590  | 0  |         *declareStart,  | 
1591  | 0  |         *optBody,  | 
1592  | 0  |         new (context_) ESTree::DeclareInterfaceNode(  | 
1593  | 0  |             id, typeParams, std::move(extends), *optBody));  | 
1594  | 0  |   }  | 
1595  | 0  |   return setLocation(  | 
1596  | 0  |       start,  | 
1597  | 0  |       *optBody,  | 
1598  | 0  |       new (context_) ESTree::InterfaceDeclarationNode(  | 
1599  | 0  |           id, typeParams, std::move(extends), *optBody));  | 
1600  | 0  | }  | 
1601  |  |  | 
1602  |  | Optional<ESTree::Node *> JSParserImpl::parseInterfaceTailFlow(  | 
1603  |  |     SMLoc start,  | 
1604  | 0  |     ESTree::NodeList &extends) { | 
1605  | 0  |   if (checkAndEat(TokenKind::rw_extends)) { | 
1606  | 0  |     do { | 
1607  | 0  |       if (!need(  | 
1608  | 0  |               TokenKind::identifier,  | 
1609  | 0  |               "in extends clause",  | 
1610  | 0  |               "location of interface",  | 
1611  | 0  |               start))  | 
1612  | 0  |         return None;  | 
1613  | 0  |       if (!parseInterfaceExtends(start, extends))  | 
1614  | 0  |         return None;  | 
1615  | 0  |     } while (checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type));  | 
1616  | 0  |   }  | 
1617  |  |  | 
1618  | 0  |   if (!need(TokenKind::l_brace, "in interface", "location of interface", start))  | 
1619  | 0  |     return None;  | 
1620  |  |  | 
1621  | 0  |   return parseObjectTypeAnnotationFlow(  | 
1622  | 0  |       AllowProtoProperty::No, AllowStaticProperty::No, AllowSpreadProperty::No);  | 
1623  | 0  | }  | 
1624  |  |  | 
1625  |  | bool JSParserImpl::parseInterfaceExtends(  | 
1626  |  |     SMLoc start,  | 
1627  | 0  |     ESTree::NodeList &extends) { | 
1628  | 0  |   assert(check(TokenKind::identifier));  | 
1629  | 0  |   auto optGeneric = parseGenericTypeFlow();  | 
1630  | 0  |   if (!optGeneric)  | 
1631  | 0  |     return false;  | 
1632  | 0  |   ESTree::GenericTypeAnnotationNode *generic = *optGeneric;  | 
1633  | 0  |   extends.push_back(*setLocation(  | 
1634  | 0  |       generic,  | 
1635  | 0  |       generic,  | 
1636  | 0  |       new (context_) ESTree::InterfaceExtendsNode(  | 
1637  | 0  |           generic->_id, generic->_typeParameters)));  | 
1638  | 0  |   return true;  | 
1639  | 0  | }  | 
1640  |  |  | 
1641  |  | Optional<ESTree::Node *> JSParserImpl::parseDeclareFunctionOrHookFlow(  | 
1642  |  |     SMLoc start,  | 
1643  | 0  |     bool hook) { | 
1644  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1645  |  | 
  | 
1646  | 0  |   if (!need(  | 
1647  | 0  |           TokenKind::identifier,  | 
1648  | 0  |           "in declare function type",  | 
1649  | 0  |           "location of declare",  | 
1650  | 0  |           start))  | 
1651  | 0  |     return None;  | 
1652  |  |  | 
1653  | 0  |   UniqueString *id = tok_->getIdentifier();  | 
1654  | 0  |   SMLoc idStart = advance(JSLexer::GrammarContext::Type).Start;  | 
1655  |  | 
  | 
1656  | 0  |   SMLoc funcStart = tok_->getStartLoc();  | 
1657  |  | 
  | 
1658  | 0  |   ESTree::Node *typeParams = nullptr;  | 
1659  | 0  |   if (check(TokenKind::less)) { | 
1660  | 0  |     auto optParams = parseTypeParamsFlow();  | 
1661  | 0  |     if (!optParams)  | 
1662  | 0  |       return None;  | 
1663  | 0  |     typeParams = *optParams;  | 
1664  | 0  |   }  | 
1665  |  |  | 
1666  | 0  |   if (!need(  | 
1667  | 0  |           TokenKind::l_paren,  | 
1668  | 0  |           "in declare function type",  | 
1669  | 0  |           "location of declare",  | 
1670  | 0  |           start))  | 
1671  | 0  |     return None;  | 
1672  |  |  | 
1673  | 0  |   ESTree::NodeList params{}; | 
1674  | 0  |   ESTree::Node *thisConstraint = nullptr;  | 
1675  | 0  |   auto optRest =  | 
1676  | 0  |       parseFunctionTypeAnnotationParamsFlow(params, thisConstraint, hook);  | 
1677  | 0  |   if (!optRest)  | 
1678  | 0  |     return None;  | 
1679  |  |  | 
1680  | 0  |   if (!eat(  | 
1681  | 0  |           TokenKind::colon,  | 
1682  | 0  |           JSLexer::GrammarContext::Type,  | 
1683  | 0  |           "in declare function type",  | 
1684  | 0  |           "location of declare",  | 
1685  | 0  |           start))  | 
1686  | 0  |     return None;  | 
1687  |  |  | 
1688  | 0  |   auto optReturn = parseReturnTypeAnnotationFlow();  | 
1689  | 0  |   if (!optReturn)  | 
1690  | 0  |     return None;  | 
1691  | 0  |   ESTree::Node *returnType = *optReturn;  | 
1692  | 0  |   SMLoc funcEnd = getPrevTokenEndLoc();  | 
1693  |  | 
  | 
1694  | 0  |   ESTree::Node *predicate = nullptr;  | 
1695  | 0  |   if (check(checksIdent_) && !hook) { | 
1696  | 0  |     auto optPred = parsePredicateFlow();  | 
1697  | 0  |     if (!optPred)  | 
1698  | 0  |       return None;  | 
1699  | 0  |     predicate = *optPred;  | 
1700  | 0  |   }  | 
1701  |  |  | 
1702  | 0  |   if (!eatSemi())  | 
1703  | 0  |     return None;  | 
1704  |  |  | 
1705  | 0  |   if (!hook) { | 
1706  | 0  |     auto *func = setLocation(  | 
1707  | 0  |         funcStart,  | 
1708  | 0  |         funcEnd,  | 
1709  | 0  |         new (context_) ESTree::TypeAnnotationNode(setLocation(  | 
1710  | 0  |             funcStart,  | 
1711  | 0  |             funcEnd,  | 
1712  | 0  |             new (context_) ESTree::FunctionTypeAnnotationNode(  | 
1713  | 0  |                 std::move(params),  | 
1714  | 0  |                 thisConstraint,  | 
1715  | 0  |                 returnType,  | 
1716  | 0  |                 *optRest,  | 
1717  | 0  |                 typeParams))));  | 
1718  | 0  |     auto *ident = setLocation(  | 
1719  | 0  |         idStart, func, new (context_) ESTree::IdentifierNode(id, func, false));  | 
1720  | 0  |     return setLocation(  | 
1721  | 0  |         start,  | 
1722  | 0  |         getPrevTokenEndLoc(),  | 
1723  | 0  |         new (context_) ESTree::DeclareFunctionNode(ident, predicate));  | 
1724  | 0  |   } else { | 
1725  | 0  |     auto *func = setLocation(  | 
1726  | 0  |         funcStart,  | 
1727  | 0  |         funcEnd,  | 
1728  | 0  |         new (context_) ESTree::TypeAnnotationNode(setLocation(  | 
1729  | 0  |             funcStart,  | 
1730  | 0  |             funcEnd,  | 
1731  | 0  |             new (context_) ESTree::HookTypeAnnotationNode(  | 
1732  | 0  |                 std::move(params), returnType, *optRest, typeParams))));  | 
1733  | 0  |     auto *ident = setLocation(  | 
1734  | 0  |         idStart, func, new (context_) ESTree::IdentifierNode(id, func, false));  | 
1735  | 0  |     return setLocation(  | 
1736  | 0  |         start,  | 
1737  | 0  |         getPrevTokenEndLoc(),  | 
1738  | 0  |         new (context_) ESTree::DeclareHookNode(ident));  | 
1739  | 0  |   }  | 
1740  | 0  | }  | 
1741  |  |  | 
1742  | 0  | Optional<ESTree::Node *> JSParserImpl::parseDeclareFunctionFlow(SMLoc start) { | 
1743  | 0  |   assert(check(TokenKind::rw_function));  | 
1744  | 0  |   return parseDeclareFunctionOrHookFlow(start, false);  | 
1745  | 0  | }  | 
1746  |  |  | 
1747  | 0  | Optional<ESTree::Node *> JSParserImpl::parseDeclareHookFlow(SMLoc start) { | 
1748  | 0  |   assert(check(hookIdent_));  | 
1749  | 0  |   return parseDeclareFunctionOrHookFlow(start, true);  | 
1750  | 0  | }  | 
1751  |  |  | 
1752  | 0  | Optional<ESTree::Node *> JSParserImpl::parseDeclareModuleFlow(SMLoc start) { | 
1753  | 0  |   assert(check(moduleIdent_));  | 
1754  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1755  |  | 
  | 
1756  | 0  |   if (checkAndEat(TokenKind::period, JSLexer::GrammarContext::Type)) { | 
1757  | 0  |     if (!checkAndEat(exportsIdent_, JSLexer::GrammarContext::Type)) { | 
1758  | 0  |       error(tok_->getSourceRange(), "expected module.exports declaration");  | 
1759  | 0  |       return None;  | 
1760  | 0  |     }  | 
1761  |  |  | 
1762  | 0  |     SMLoc annotStart = tok_->getStartLoc();  | 
1763  | 0  |     if (!eat(  | 
1764  | 0  |             TokenKind::colon,  | 
1765  | 0  |             JSLexer::GrammarContext::Type,  | 
1766  | 0  |             "in module.exports declaration",  | 
1767  | 0  |             "start of declaration",  | 
1768  | 0  |             start))  | 
1769  | 0  |       return None;  | 
1770  | 0  |     auto optType = parseTypeAnnotationFlow(annotStart);  | 
1771  | 0  |     if (!optType)  | 
1772  | 0  |       return None;  | 
1773  | 0  |     eatSemi(true);  | 
1774  | 0  |     return setLocation(  | 
1775  | 0  |         start,  | 
1776  | 0  |         getPrevTokenEndLoc(),  | 
1777  | 0  |         new (context_) ESTree::DeclareModuleExportsNode(*optType));  | 
1778  | 0  |   }  | 
1779  |  |  | 
1780  |  |   // declare module Identifier {[opt] | 
1781  |  |   //                ^  | 
1782  | 0  |   ESTree::Node *id = nullptr;  | 
1783  | 0  |   if (check(TokenKind::string_literal)) { | 
1784  | 0  |     id = setLocation(  | 
1785  | 0  |         tok_,  | 
1786  | 0  |         tok_,  | 
1787  | 0  |         new (context_) ESTree::StringLiteralNode(tok_->getStringLiteral()));  | 
1788  | 0  |   } else { | 
1789  | 0  |     if (!need(  | 
1790  | 0  |             TokenKind::identifier,  | 
1791  | 0  |             "in module declaration",  | 
1792  | 0  |             "start of declaration",  | 
1793  | 0  |             start))  | 
1794  | 0  |       return None;  | 
1795  | 0  |     id = setLocation(  | 
1796  | 0  |         tok_,  | 
1797  | 0  |         tok_,  | 
1798  | 0  |         new (context_)  | 
1799  | 0  |             ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
1800  | 0  |   }  | 
1801  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1802  |  |  | 
1803  |  |   // declare module Identifier { | 
1804  |  |   //                           ^  | 
1805  | 0  |   SMLoc bodyStart = tok_->getStartLoc();  | 
1806  | 0  |   if (!eat(  | 
1807  | 0  |           TokenKind::l_brace,  | 
1808  | 0  |           JSLexer::GrammarContext::Type,  | 
1809  | 0  |           "in module declaration",  | 
1810  | 0  |           "start of declaration",  | 
1811  | 0  |           start))  | 
1812  | 0  |     return None;  | 
1813  |  |  | 
1814  | 0  |   ESTree::NodeList declarations{}; | 
1815  |  | 
  | 
1816  | 0  |   while (!check(TokenKind::r_brace)) { | 
1817  | 0  |     if (!parseStatementListItem(Param{}, AllowImportExport::Yes, declarations)) | 
1818  | 0  |       return None;  | 
1819  | 0  |   }  | 
1820  |  |  | 
1821  | 0  |   SMLoc bodyEnd = advance(JSLexer::GrammarContext::Type).End;  | 
1822  |  | 
  | 
1823  | 0  |   ESTree::Node *body = setLocation(  | 
1824  | 0  |       bodyStart,  | 
1825  | 0  |       bodyEnd,  | 
1826  | 0  |       new (context_) ESTree::BlockStatementNode(std::move(declarations)));  | 
1827  |  | 
  | 
1828  | 0  |   return setLocation(  | 
1829  | 0  |       start, body, new (context_) ESTree::DeclareModuleNode(id, body));  | 
1830  | 0  | }  | 
1831  |  |  | 
1832  | 0  | Optional<ESTree::Node *> JSParserImpl::parseDeclareNamespaceFlow(SMLoc start) { | 
1833  | 0  |   assert(check(namespaceIdent_));  | 
1834  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1835  |  |  | 
1836  |  |   // declare namespace Identifier {[opt] | 
1837  |  |   //                   ^  | 
1838  | 0  |   if (!need(  | 
1839  | 0  |           TokenKind::identifier,  | 
1840  | 0  |           "in namespace declaration",  | 
1841  | 0  |           "start of declaration",  | 
1842  | 0  |           start))  | 
1843  | 0  |     return None;  | 
1844  | 0  |   ESTree::Node *id = setLocation(  | 
1845  | 0  |       tok_,  | 
1846  | 0  |       tok_,  | 
1847  | 0  |       new (context_)  | 
1848  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
1849  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1850  |  |  | 
1851  |  |   // declare namespace Identifier { | 
1852  |  |   //                              ^  | 
1853  | 0  |   SMLoc bodyStart = tok_->getStartLoc();  | 
1854  | 0  |   if (!eat(  | 
1855  | 0  |           TokenKind::l_brace,  | 
1856  | 0  |           JSLexer::GrammarContext::Type,  | 
1857  | 0  |           "in namespace declaration",  | 
1858  | 0  |           "start of declaration",  | 
1859  | 0  |           start))  | 
1860  | 0  |     return None;  | 
1861  |  |  | 
1862  | 0  |   ESTree::NodeList declarations{}; | 
1863  |  | 
  | 
1864  | 0  |   while (!check(TokenKind::r_brace)) { | 
1865  | 0  |     if (!parseStatementListItem(Param{}, AllowImportExport::Yes, declarations)) | 
1866  | 0  |       return None;  | 
1867  | 0  |   }  | 
1868  |  |  | 
1869  | 0  |   SMLoc bodyEnd = advance(JSLexer::GrammarContext::Type).End;  | 
1870  |  | 
  | 
1871  | 0  |   ESTree::Node *body = setLocation(  | 
1872  | 0  |       bodyStart,  | 
1873  | 0  |       bodyEnd,  | 
1874  | 0  |       new (context_) ESTree::BlockStatementNode(std::move(declarations)));  | 
1875  |  | 
  | 
1876  | 0  |   return setLocation(  | 
1877  | 0  |       start, body, new (context_) ESTree::DeclareNamespaceNode(id, body));  | 
1878  | 0  | }  | 
1879  |  |  | 
1880  | 0  | Optional<ESTree::Node *> JSParserImpl::parseDeclareClassFlow(SMLoc start) { | 
1881  | 0  |   assert(check(TokenKind::rw_class));  | 
1882  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1883  |  |  | 
1884  |  |   // NOTE: Class definition is always strict mode code.  | 
1885  | 0  |   SaveStrictModeAndSeenDirectives saveStrictMode{this}; | 
1886  | 0  |   setStrictMode(true);  | 
1887  |  | 
  | 
1888  | 0  |   if (!need(  | 
1889  | 0  |           TokenKind::identifier,  | 
1890  | 0  |           "in class declaration",  | 
1891  | 0  |           "start of declaration",  | 
1892  | 0  |           start))  | 
1893  | 0  |     return None;  | 
1894  |  |  | 
1895  | 0  |   auto *id = setLocation(  | 
1896  | 0  |       tok_,  | 
1897  | 0  |       tok_,  | 
1898  | 0  |       new (context_)  | 
1899  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
1900  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
1901  |  | 
  | 
1902  | 0  |   ESTree::Node *typeParams = nullptr;  | 
1903  | 0  |   if (check(TokenKind::less)) { | 
1904  | 0  |     auto optParams = parseTypeParamsFlow();  | 
1905  | 0  |     if (!optParams)  | 
1906  | 0  |       return None;  | 
1907  | 0  |     typeParams = *optParams;  | 
1908  | 0  |   }  | 
1909  |  |  | 
1910  | 0  |   ESTree::NodeList extends{}; | 
1911  | 0  |   if (checkAndEat(TokenKind::rw_extends)) { | 
1912  | 0  |     if (!need(  | 
1913  | 0  |             TokenKind::identifier,  | 
1914  | 0  |             "in class 'extends'",  | 
1915  | 0  |             "start of declaration",  | 
1916  | 0  |             start))  | 
1917  | 0  |       return None;  | 
1918  | 0  |     if (!parseInterfaceExtends(start, extends))  | 
1919  | 0  |       return None;  | 
1920  | 0  |   }  | 
1921  |  |  | 
1922  | 0  |   ESTree::NodeList mixins{}; | 
1923  | 0  |   if (checkAndEat(mixinsIdent_)) { | 
1924  | 0  |     do { | 
1925  | 0  |       if (!need(  | 
1926  | 0  |               TokenKind::identifier,  | 
1927  | 0  |               "in class 'mixins'",  | 
1928  | 0  |               "start of declaration",  | 
1929  | 0  |               start))  | 
1930  | 0  |         return None;  | 
1931  | 0  |       if (!parseInterfaceExtends(start, mixins))  | 
1932  | 0  |         return None;  | 
1933  | 0  |     } while (checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type));  | 
1934  | 0  |   }  | 
1935  |  |  | 
1936  | 0  |   ESTree::NodeList implements{}; | 
1937  | 0  |   if (checkAndEat(TokenKind::rw_implements)) { | 
1938  | 0  |     do { | 
1939  | 0  |       if (!need(  | 
1940  | 0  |               TokenKind::identifier,  | 
1941  | 0  |               "in class 'implements'",  | 
1942  | 0  |               "start of declaration",  | 
1943  | 0  |               start))  | 
1944  | 0  |         return None;  | 
1945  | 0  |       auto optImpl = parseClassImplementsFlow();  | 
1946  | 0  |       if (!optImpl)  | 
1947  | 0  |         return None;  | 
1948  | 0  |       implements.push_back(**optImpl);  | 
1949  | 0  |     } while (checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type));  | 
1950  | 0  |   }  | 
1951  |  |  | 
1952  | 0  |   if (!need(  | 
1953  | 0  |           TokenKind::l_brace,  | 
1954  | 0  |           "in declared class",  | 
1955  | 0  |           "start of declaration",  | 
1956  | 0  |           start))  | 
1957  | 0  |     return None;  | 
1958  |  |  | 
1959  | 0  |   auto optBody = parseObjectTypeAnnotationFlow(  | 
1960  | 0  |       AllowProtoProperty::Yes,  | 
1961  | 0  |       AllowStaticProperty::Yes,  | 
1962  | 0  |       AllowSpreadProperty::No);  | 
1963  | 0  |   if (!optBody)  | 
1964  | 0  |     return None;  | 
1965  |  |  | 
1966  | 0  |   return setLocation(  | 
1967  | 0  |       start,  | 
1968  | 0  |       *optBody,  | 
1969  | 0  |       new (context_) ESTree::DeclareClassNode(  | 
1970  | 0  |           id,  | 
1971  | 0  |           typeParams,  | 
1972  | 0  |           std::move(extends),  | 
1973  | 0  |           std::move(implements),  | 
1974  | 0  |           std::move(mixins),  | 
1975  | 0  |           *optBody));  | 
1976  | 0  | }  | 
1977  |  |  | 
1978  |  | Optional<ESTree::Node *> JSParserImpl::parseExportTypeDeclarationFlow(  | 
1979  | 0  |     SMLoc startLoc) { | 
1980  | 0  |   assert(check(typeIdent_));  | 
1981  | 0  |   SMLoc typeIdentLoc = advance().Start;  | 
1982  |  | 
  | 
1983  | 0  |   if (checkAndEat(TokenKind::star)) { | 
1984  |  |     // export type * FromClause;  | 
1985  |  |     //               ^  | 
1986  | 0  |     auto optFromClause = parseFromClause();  | 
1987  | 0  |     if (!optFromClause) { | 
1988  | 0  |       return None;  | 
1989  | 0  |     }  | 
1990  | 0  |     if (!eatSemi()) { | 
1991  | 0  |       return None;  | 
1992  | 0  |     }  | 
1993  | 0  |     return setLocation(  | 
1994  | 0  |         startLoc,  | 
1995  | 0  |         getPrevTokenEndLoc(),  | 
1996  | 0  |         new (context_)  | 
1997  | 0  |             ESTree::ExportAllDeclarationNode(*optFromClause, typeIdent_));  | 
1998  | 0  |   }  | 
1999  |  |  | 
2000  | 0  |   if (check(TokenKind::l_brace)) { | 
2001  | 0  |     ESTree::NodeList specifiers{}; | 
2002  | 0  |     llvh::SmallVector<SMRange, 2> invalids{}; | 
2003  |  | 
  | 
2004  | 0  |     auto optExportClause = parseExportClause(specifiers, invalids);  | 
2005  | 0  |     if (!optExportClause) { | 
2006  | 0  |       return None;  | 
2007  | 0  |     }  | 
2008  |  |  | 
2009  | 0  |     ESTree::Node *source = nullptr;  | 
2010  | 0  |     if (check(fromIdent_)) { | 
2011  |  |       // export ExportClause FromClause ;  | 
2012  | 0  |       auto optFromClause = parseFromClause();  | 
2013  | 0  |       if (!optFromClause) { | 
2014  | 0  |         return None;  | 
2015  | 0  |       }  | 
2016  | 0  |       source = *optFromClause;  | 
2017  | 0  |     } else { | 
2018  |  |       // export ExportClause ;  | 
2019  |  |       // ES9.0 15.2.3.1  | 
2020  |  |       // When there is no FromClause, any ranges added to invalids are  | 
2021  |  |       // actually invalid, and should be reported as errors.  | 
2022  | 0  |       for (const SMRange &range : invalids) { | 
2023  | 0  |         error(range, "Invalid exported name");  | 
2024  | 0  |       }  | 
2025  | 0  |     }  | 
2026  |  |  | 
2027  | 0  |     if (!eatSemi()) { | 
2028  | 0  |       return None;  | 
2029  | 0  |     }  | 
2030  |  |  | 
2031  | 0  |     return setLocation(  | 
2032  | 0  |         startLoc,  | 
2033  | 0  |         getPrevTokenEndLoc(),  | 
2034  | 0  |         new (context_) ESTree::ExportNamedDeclarationNode(  | 
2035  | 0  |             nullptr, std::move(specifiers), source, typeIdent_));  | 
2036  | 0  |   }  | 
2037  |  |  | 
2038  | 0  |   if (check(TokenKind::identifier)) { | 
2039  | 0  |     auto optAlias = parseTypeAliasFlow(typeIdentLoc, TypeAliasKind::None);  | 
2040  | 0  |     if (!optAlias)  | 
2041  | 0  |       return None;  | 
2042  | 0  |     return setLocation(  | 
2043  | 0  |         startLoc,  | 
2044  | 0  |         *optAlias,  | 
2045  | 0  |         new (context_) ESTree::ExportNamedDeclarationNode(  | 
2046  | 0  |             *optAlias, {}, nullptr, typeIdent_)); | 
2047  | 0  |   }  | 
2048  |  |  | 
2049  | 0  |   errorExpected(  | 
2050  | 0  |       {TokenKind::star, TokenKind::l_brace, TokenKind::identifier}, | 
2051  | 0  |       "in export type declaration",  | 
2052  | 0  |       "start of export",  | 
2053  | 0  |       startLoc);  | 
2054  | 0  |   return None;  | 
2055  | 0  | }  | 
2056  |  |  | 
2057  | 0  | Optional<ESTree::Node *> JSParserImpl::parseDeclareExportFlow(SMLoc start) { | 
2058  | 0  |   assert(check(TokenKind::rw_export));  | 
2059  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
2060  | 0  |   SMLoc declareStart = tok_->getStartLoc();  | 
2061  |  | 
  | 
2062  | 0  |   if (checkAndEat(TokenKind::rw_default, JSLexer::GrammarContext::Type)) { | 
2063  | 0  |     declareStart = tok_->getStartLoc();  | 
2064  | 0  |     if (check(TokenKind::rw_function)) { | 
2065  | 0  |       auto optFunc = parseDeclareFunctionFlow(declareStart);  | 
2066  | 0  |       if (!optFunc)  | 
2067  | 0  |         return None;  | 
2068  | 0  |       return setLocation(  | 
2069  | 0  |           start,  | 
2070  | 0  |           *optFunc,  | 
2071  | 0  |           new (context_) ESTree::DeclareExportDeclarationNode(  | 
2072  | 0  |               *optFunc, {}, nullptr, true)); | 
2073  | 0  |     }  | 
2074  | 0  |     if (context_.getParseFlowComponentSyntax() && checkHookDeclarationFlow()) { | 
2075  | 0  |       auto optFunc = parseDeclareHookFlow(declareStart);  | 
2076  | 0  |       if (!optFunc)  | 
2077  | 0  |         return None;  | 
2078  | 0  |       return setLocation(  | 
2079  | 0  |           start,  | 
2080  | 0  |           *optFunc,  | 
2081  | 0  |           new (context_) ESTree::DeclareExportDeclarationNode(  | 
2082  | 0  |               *optFunc, {}, nullptr, true)); | 
2083  | 0  |     }  | 
2084  | 0  |     if (context_.getParseFlowComponentSyntax() &&  | 
2085  | 0  |         checkComponentDeclarationFlow()) { | 
2086  | 0  |       auto optComponent =  | 
2087  | 0  |           parseComponentDeclarationFlow(start, /* declare */ true);  | 
2088  | 0  |       if (!optComponent)  | 
2089  | 0  |         return None;  | 
2090  | 0  |       return setLocation(  | 
2091  | 0  |           start,  | 
2092  | 0  |           *optComponent,  | 
2093  | 0  |           new (context_) ESTree::DeclareExportDeclarationNode(  | 
2094  | 0  |               *optComponent, {}, nullptr, true)); | 
2095  | 0  |     }  | 
2096  | 0  |     if (check(TokenKind::rw_class)) { | 
2097  | 0  |       auto optClass = parseDeclareClassFlow(declareStart);  | 
2098  | 0  |       if (!optClass)  | 
2099  | 0  |         return None;  | 
2100  | 0  |       return setLocation(  | 
2101  | 0  |           start,  | 
2102  | 0  |           *optClass,  | 
2103  | 0  |           new (context_) ESTree::DeclareExportDeclarationNode(  | 
2104  | 0  |               *optClass, {}, nullptr, true)); | 
2105  | 0  |     }  | 
2106  | 0  |     auto optType = parseTypeAnnotationFlow();  | 
2107  | 0  |     if (!optType)  | 
2108  | 0  |       return None;  | 
2109  | 0  |     if (!eatSemi())  | 
2110  | 0  |       return None;  | 
2111  | 0  |     return setLocation(  | 
2112  | 0  |         start,  | 
2113  | 0  |         getPrevTokenEndLoc(),  | 
2114  | 0  |         new (context_)  | 
2115  | 0  |             ESTree::DeclareExportDeclarationNode(*optType, {}, nullptr, true)); | 
2116  | 0  |   }  | 
2117  |  |  | 
2118  | 0  |   if (check(TokenKind::rw_function)) { | 
2119  | 0  |     auto optFunc = parseDeclareFunctionFlow(declareStart);  | 
2120  | 0  |     if (!optFunc)  | 
2121  | 0  |       return None;  | 
2122  | 0  |     return setLocation(  | 
2123  | 0  |         start,  | 
2124  | 0  |         *optFunc,  | 
2125  | 0  |         new (context_)  | 
2126  | 0  |             ESTree::DeclareExportDeclarationNode(*optFunc, {}, nullptr, false)); | 
2127  | 0  |   }  | 
2128  |  |  | 
2129  | 0  |   if (context_.getParseFlowComponentSyntax() && checkHookDeclarationFlow()) { | 
2130  | 0  |     auto optFunc = parseDeclareHookFlow(declareStart);  | 
2131  | 0  |     if (!optFunc)  | 
2132  | 0  |       return None;  | 
2133  | 0  |     return setLocation(  | 
2134  | 0  |         start,  | 
2135  | 0  |         *optFunc,  | 
2136  | 0  |         new (context_)  | 
2137  | 0  |             ESTree::DeclareExportDeclarationNode(*optFunc, {}, nullptr, false)); | 
2138  | 0  |   }  | 
2139  |  |  | 
2140  | 0  |   if (check(TokenKind::rw_class)) { | 
2141  | 0  |     auto optClass = parseDeclareClassFlow(declareStart);  | 
2142  | 0  |     if (!optClass)  | 
2143  | 0  |       return None;  | 
2144  | 0  |     return setLocation(  | 
2145  | 0  |         start,  | 
2146  | 0  |         *optClass,  | 
2147  | 0  |         new (context_) ESTree::DeclareExportDeclarationNode(  | 
2148  | 0  |             *optClass, {}, nullptr, false)); | 
2149  | 0  |   }  | 
2150  |  |  | 
2151  | 0  |   if (context_.getParseFlowComponentSyntax() &&  | 
2152  | 0  |       checkComponentDeclarationFlow()) { | 
2153  | 0  |     auto optComponent =  | 
2154  | 0  |         parseComponentDeclarationFlow(start, /* declare */ true);  | 
2155  | 0  |     if (!optComponent)  | 
2156  | 0  |       return None;  | 
2157  | 0  |     return setLocation(  | 
2158  | 0  |         start,  | 
2159  | 0  |         *optComponent,  | 
2160  | 0  |         new (context_) ESTree::DeclareExportDeclarationNode(  | 
2161  | 0  |             *optComponent, {}, nullptr, false)); | 
2162  | 0  |   }  | 
2163  |  |  | 
2164  | 0  |   if (check(TokenKind::rw_enum)) { | 
2165  | 0  |     auto optEnum = parseEnumDeclarationFlow(start, /* declare */ true);  | 
2166  | 0  |     if (!optEnum)  | 
2167  | 0  |       return None;  | 
2168  | 0  |     return setLocation(  | 
2169  | 0  |         start,  | 
2170  | 0  |         *optEnum,  | 
2171  | 0  |         new (context_)  | 
2172  | 0  |             ESTree::DeclareExportDeclarationNode(*optEnum, {}, nullptr, false)); | 
2173  | 0  |   }  | 
2174  |  |  | 
2175  | 0  |   if (checkN(TokenKind::rw_var, TokenKind::rw_const, letIdent_)) { | 
2176  | 0  |     ESTree::NodeLabel kind = tok_->getResWordOrIdentifier();  | 
2177  | 0  |     SMLoc varStart = advance(JSLexer::GrammarContext::Type).Start;  | 
2178  | 0  |     auto optIdent = parseBindingIdentifier(Param{}); | 
2179  | 0  |     if (!optIdent) { | 
2180  | 0  |       errorExpected(  | 
2181  | 0  |           TokenKind::identifier,  | 
2182  | 0  |           "in var declaration",  | 
2183  | 0  |           "start of declaration",  | 
2184  | 0  |           start);  | 
2185  | 0  |       return None;  | 
2186  | 0  |     }  | 
2187  | 0  |     if (!(*optIdent)->_typeAnnotation) { | 
2188  | 0  |       error(  | 
2189  | 0  |           (*optIdent)->getSourceRange(),  | 
2190  | 0  |           "expected type annotation on declared var");  | 
2191  | 0  |     }  | 
2192  | 0  |     if (!eatSemi())  | 
2193  | 0  |       return None;  | 
2194  |  |  | 
2195  | 0  |     SMLoc end = getPrevTokenEndLoc();  | 
2196  | 0  |     return setLocation(  | 
2197  | 0  |         start,  | 
2198  | 0  |         end,  | 
2199  | 0  |         new (context_) ESTree::DeclareExportDeclarationNode(  | 
2200  | 0  |             setLocation(  | 
2201  | 0  |                 varStart,  | 
2202  | 0  |                 end,  | 
2203  | 0  |                 new (context_) ESTree::DeclareVariableNode(*optIdent, kind)),  | 
2204  | 0  |             {}, | 
2205  | 0  |             nullptr,  | 
2206  | 0  |             false));  | 
2207  | 0  |   }  | 
2208  |  |  | 
2209  | 0  |   if (checkAndEat(opaqueIdent_, JSLexer::GrammarContext::Type)) { | 
2210  | 0  |     if (!check(typeIdent_)) { | 
2211  | 0  |       error(tok_->getStartLoc(), "'type' required in opaque type declaration");  | 
2212  | 0  |       return None;  | 
2213  | 0  |     }  | 
2214  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
2215  | 0  |     auto optType =  | 
2216  | 0  |         parseTypeAliasFlow(declareStart, TypeAliasKind::DeclareOpaque);  | 
2217  | 0  |     if (!optType)  | 
2218  | 0  |       return None;  | 
2219  | 0  |     return setLocation(  | 
2220  | 0  |         start,  | 
2221  | 0  |         *optType,  | 
2222  | 0  |         new (context_)  | 
2223  | 0  |             ESTree::DeclareExportDeclarationNode(*optType, {}, nullptr, false)); | 
2224  | 0  |   }  | 
2225  |  |  | 
2226  | 0  |   if (check(typeIdent_)) { | 
2227  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
2228  | 0  |     auto optType = parseTypeAliasFlow(declareStart, TypeAliasKind::None);  | 
2229  | 0  |     if (!optType)  | 
2230  | 0  |       return None;  | 
2231  | 0  |     return setLocation(  | 
2232  | 0  |         start,  | 
2233  | 0  |         *optType,  | 
2234  | 0  |         new (context_)  | 
2235  | 0  |             ESTree::DeclareExportDeclarationNode(*optType, {}, nullptr, false)); | 
2236  | 0  |   }  | 
2237  |  |  | 
2238  | 0  |   if (checkN(TokenKind::rw_interface, interfaceIdent_)) { | 
2239  | 0  |     auto optInterface = parseInterfaceDeclarationFlow();  | 
2240  | 0  |     if (!optInterface)  | 
2241  | 0  |       return None;  | 
2242  | 0  |     return setLocation(  | 
2243  | 0  |         start,  | 
2244  | 0  |         *optInterface,  | 
2245  | 0  |         new (context_) ESTree::DeclareExportDeclarationNode(  | 
2246  | 0  |             *optInterface, {}, nullptr, false)); | 
2247  | 0  |   }  | 
2248  |  |  | 
2249  | 0  |   if (checkAndEat(TokenKind::star, JSLexer::GrammarContext::Type)) { | 
2250  |  |     // declare export * from 'foo';  | 
2251  |  |     //                  ^  | 
2252  | 0  |     if (!check(fromIdent_)) { | 
2253  | 0  |       error(  | 
2254  | 0  |           tok_->getStartLoc(), "expected 'from' clause in export declaration");  | 
2255  | 0  |       return None;  | 
2256  | 0  |     }  | 
2257  | 0  |     auto optSource = parseFromClause();  | 
2258  | 0  |     if (!optSource)  | 
2259  | 0  |       return None;  | 
2260  | 0  |     if (!eatSemi())  | 
2261  | 0  |       return None;  | 
2262  | 0  |     return setLocation(  | 
2263  | 0  |         start,  | 
2264  | 0  |         getPrevTokenEndLoc(),  | 
2265  | 0  |         new (context_) ESTree::DeclareExportAllDeclarationNode(*optSource));  | 
2266  | 0  |   }  | 
2267  |  |  | 
2268  | 0  |   if (!need(  | 
2269  | 0  |           TokenKind::l_brace, "in export specifier", "start of declare", start))  | 
2270  | 0  |     return None;  | 
2271  |  |  | 
2272  | 0  |   ESTree::NodeList specifiers{}; | 
2273  | 0  |   llvh::SmallVector<SMRange, 2> invalids{}; | 
2274  | 0  |   if (!parseExportClause(specifiers, invalids))  | 
2275  | 0  |     return None;  | 
2276  |  |  | 
2277  | 0  |   ESTree::Node *source = nullptr;  | 
2278  | 0  |   if (check(fromIdent_)) { | 
2279  | 0  |     auto optSource = parseFromClause();  | 
2280  | 0  |     if (!optSource)  | 
2281  | 0  |       return None;  | 
2282  | 0  |     source = *optSource;  | 
2283  | 0  |   }  | 
2284  |  |  | 
2285  | 0  |   if (!eatSemi())  | 
2286  | 0  |     return None;  | 
2287  |  |  | 
2288  | 0  |   return setLocation(  | 
2289  | 0  |       start,  | 
2290  | 0  |       getPrevTokenEndLoc(),  | 
2291  | 0  |       new (context_) ESTree::DeclareExportDeclarationNode(  | 
2292  | 0  |           nullptr, std::move(specifiers), source, false));  | 
2293  | 0  | }  | 
2294  |  |  | 
2295  |  | Optional<ESTree::Node *> JSParserImpl::parseReturnTypeAnnotationFlow(  | 
2296  |  |     Optional<SMLoc> wrappedStart,  | 
2297  | 0  |     AllowAnonFunctionType allowAnonFunctionType) { | 
2298  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2299  | 0  |   ESTree::Node *returnType = nullptr;  | 
2300  | 0  |   if (check(assertsIdent_)) { | 
2301  |  |     // TypePredicate (asserts = true) or TypeAnnotation:  | 
2302  |  |     //   TypeAnnotation  | 
2303  |  |     //   asserts IdentifierName  | 
2304  |  |     //   asserts IdentifierName is TypeAnnotation  | 
2305  | 0  |     auto optType = parseTypeAnnotationFlow(None, allowAnonFunctionType);  | 
2306  | 0  |     if (!optType)  | 
2307  | 0  |       return None;  | 
2308  |  |  | 
2309  | 0  |     if (check(TokenKind::identifier)) { | 
2310  |  |       // Validate the "asserts" token was an identifier not a more complex type.  | 
2311  | 0  |       auto optId = reparseTypeAnnotationAsIdentifierFlow(*optType);  | 
2312  | 0  |       if (!optId)  | 
2313  | 0  |         return None;  | 
2314  | 0  |       ESTree::Node *id = setLocation(  | 
2315  | 0  |           tok_,  | 
2316  | 0  |           tok_,  | 
2317  | 0  |           new (context_)  | 
2318  | 0  |               ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
2319  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
2320  | 0  |       ESTree::Node *typeAnnotation = nullptr;  | 
2321  | 0  |       if (checkAndEat(isIdent_, JSLexer::GrammarContext::Type)) { | 
2322  |  |         // assert IdentifierName is TypeAnnotation  | 
2323  |  |         //                          ^  | 
2324  | 0  |         auto optType = parseTypeAnnotationFlow(None, allowAnonFunctionType);  | 
2325  | 0  |         if (!optType)  | 
2326  | 0  |           return None;  | 
2327  | 0  |         typeAnnotation = *optType;  | 
2328  | 0  |       }  | 
2329  | 0  |       returnType = setLocation(  | 
2330  | 0  |           start,  | 
2331  | 0  |           getPrevTokenEndLoc(),  | 
2332  | 0  |           new (context_)  | 
2333  | 0  |               ESTree::TypePredicateNode(id, typeAnnotation, assertsIdent_));  | 
2334  | 0  |     } else { | 
2335  | 0  |       returnType = *optType;  | 
2336  | 0  |     }  | 
2337  | 0  |   } else if (check(impliesIdent_)) { | 
2338  |  |     // TypePredicate (implies = true) or TypeAnnotation:  | 
2339  |  |     //   TypeAnnotation  | 
2340  |  |     //   implies IdentifierName is TypeAnnotation  | 
2341  |  |  | 
2342  |  |     //   implies IdentifierName is TypeAnnotation  | 
2343  |  |     //   ^  | 
2344  | 0  |     auto optType = parseTypeAnnotationFlow(None, allowAnonFunctionType);  | 
2345  | 0  |     if (!optType)  | 
2346  | 0  |       return None;  | 
2347  |  |  | 
2348  | 0  |     if (check(TokenKind::identifier, TokenKind::rw_this)) { | 
2349  |  |       // Validate the "implies" token was an identifier not a more complex type.  | 
2350  | 0  |       if (auto *generic = dyn_cast<ESTree::GenericTypeAnnotationNode>(*optType);  | 
2351  | 0  |           !(generic && !generic->_typeParameters)) { | 
2352  | 0  |         error(  | 
2353  | 0  |             tok_->getStartLoc(),  | 
2354  | 0  |             "invalid return annotation. 'implies' type guard needs to be followed by identifier");  | 
2355  | 0  |         return None;  | 
2356  | 0  |       }  | 
2357  |  |  | 
2358  |  |       //   implies IdentifierName is TypeAnnotation  | 
2359  |  |       //           ^  | 
2360  | 0  |       ESTree::Node *id = setLocation(  | 
2361  | 0  |           tok_,  | 
2362  | 0  |           tok_,  | 
2363  | 0  |           new (context_) ESTree::IdentifierNode(  | 
2364  | 0  |               tok_->getResWordOrIdentifier(), nullptr, false));  | 
2365  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
2366  |  |  | 
2367  |  |       //   implies IdentifierName is TypeAnnotation  | 
2368  |  |       //                          ^  | 
2369  | 0  |       if (!checkAndEat(isIdent_, JSLexer::GrammarContext::Type)) { | 
2370  | 0  |         error(  | 
2371  | 0  |             tok_->getStartLoc(),  | 
2372  | 0  |             "expecting 'is' after parameter of 'implies' type guard");  | 
2373  | 0  |         return None;  | 
2374  | 0  |       }  | 
2375  |  |       //   implies IdentifierName is TypeAnnotation  | 
2376  |  |       //                             ^  | 
2377  | 0  |       auto optTypeT = parseTypeAnnotationFlow(None, allowAnonFunctionType);  | 
2378  | 0  |       if (!optTypeT)  | 
2379  | 0  |         return None;  | 
2380  | 0  |       returnType = setLocation(  | 
2381  | 0  |           start,  | 
2382  | 0  |           getPrevTokenEndLoc(),  | 
2383  | 0  |           new (context_)  | 
2384  | 0  |               ESTree::TypePredicateNode(id, *optTypeT, impliesIdent_));  | 
2385  | 0  |     } else { | 
2386  |  |       // implies (as type -- okay)  | 
2387  | 0  |       returnType = *optType;  | 
2388  | 0  |     }  | 
2389  | 0  |   } else { | 
2390  |  |     // TypePredicate (asserts = false && implies = false) or TypeAnnotation:  | 
2391  |  |     //   TypeAnnotation  | 
2392  |  |     //   IdentifierName is TypeAnnotation  | 
2393  |  | 
  | 
2394  | 0  |     auto optType = parseTypeAnnotationFlow(None, allowAnonFunctionType);  | 
2395  | 0  |     if (!optType)  | 
2396  | 0  |       return None;  | 
2397  |  |  | 
2398  | 0  |     if (checkAndEat(isIdent_, JSLexer::GrammarContext::Type)) { | 
2399  | 0  |       auto optId = reparseTypeAnnotationAsIdentifierFlow(*optType);  | 
2400  | 0  |       if (!optId)  | 
2401  | 0  |         return None;  | 
2402  | 0  |       auto optType = parseTypeAnnotationFlow(None, allowAnonFunctionType);  | 
2403  | 0  |       if (!optType)  | 
2404  | 0  |         return None;  | 
2405  | 0  |       returnType = setLocation(  | 
2406  | 0  |           start,  | 
2407  | 0  |           getPrevTokenEndLoc(),  | 
2408  | 0  |           new (context_) ESTree::TypePredicateNode(*optId, *optType, nullptr));  | 
2409  | 0  |     } else { | 
2410  | 0  |       returnType = *optType;  | 
2411  | 0  |     }  | 
2412  | 0  |   }  | 
2413  |  |  | 
2414  | 0  |   if (wrappedStart) { | 
2415  | 0  |     return setLocation(  | 
2416  | 0  |         *wrappedStart,  | 
2417  | 0  |         getPrevTokenEndLoc(),  | 
2418  | 0  |         new (context_) ESTree::TypeAnnotationNode(returnType));  | 
2419  | 0  |   }  | 
2420  | 0  |   return returnType;  | 
2421  | 0  | }  | 
2422  |  |  | 
2423  | 0  | Optional<ESTree::Node *> JSParserImpl::parseTypeAnnotationBeforeColonFlow() { | 
2424  |  |   // If the identifier name is a known keyword we need to lookahead to see if  | 
2425  |  |   // its a type or an identifier otherwise it could fail to parse.  | 
2426  | 0  |   if (check(TokenKind::identifier) &&  | 
2427  | 0  |       (context_.getParseFlowComponentSyntax())) { | 
2428  | 0  |     if ((tok_->getResWordOrIdentifier() == componentIdent_) ||  | 
2429  | 0  |         (tok_->getResWordOrIdentifier() == hookIdent_) ||  | 
2430  | 0  |         (tok_->getResWordOrIdentifier() == rendersIdent_ &&  | 
2431  | 0  |          !tok_->checkFollowingCharacter('?'))) { | 
2432  | 0  |       OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
2433  | 0  |       if (optNext.hasValue() &&  | 
2434  | 0  |           (*optNext == TokenKind::colon || *optNext == TokenKind::question)) { | 
2435  | 0  |         auto id = setLocation(  | 
2436  | 0  |             tok_,  | 
2437  | 0  |             tok_,  | 
2438  | 0  |             new (context_) ESTree::GenericTypeAnnotationNode(  | 
2439  | 0  |                 setLocation(  | 
2440  | 0  |                     tok_,  | 
2441  | 0  |                     tok_,  | 
2442  | 0  |                     new (context_) ESTree::IdentifierNode(  | 
2443  | 0  |                         tok_->getResWordOrIdentifier(), nullptr, false)),  | 
2444  | 0  |                 nullptr));  | 
2445  | 0  |         advance(JSLexer::GrammarContext::Type);  | 
2446  | 0  |         return id;  | 
2447  | 0  |       }  | 
2448  | 0  |     } else if (  | 
2449  | 0  |         tok_->getResWordOrIdentifier() == rendersIdent_ &&  | 
2450  | 0  |         tok_->checkFollowingCharacter('?')) { | 
2451  | 0  |       SMLoc startLoc = tok_->getStartLoc();  | 
2452  | 0  |       auto id = setLocation(  | 
2453  | 0  |           tok_,  | 
2454  | 0  |           tok_,  | 
2455  | 0  |           new (context_) ESTree::GenericTypeAnnotationNode(  | 
2456  | 0  |               setLocation(  | 
2457  | 0  |                   tok_,  | 
2458  | 0  |                   tok_,  | 
2459  | 0  |                   new (context_) ESTree::IdentifierNode(  | 
2460  | 0  |                       tok_->getResWordOrIdentifier(), nullptr, false)),  | 
2461  | 0  |               nullptr));  | 
2462  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
2463  | 0  |       OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
2464  | 0  |       if (optNext.hasValue() && (*optNext == TokenKind::colon)) { | 
2465  | 0  |         return id;  | 
2466  | 0  |       } else { | 
2467  | 0  |         if (!eat(  | 
2468  | 0  |                 TokenKind::question,  | 
2469  | 0  |                 JSLexer::GrammarContext::Type,  | 
2470  | 0  |                 "in render type annotation",  | 
2471  | 0  |                 "start of render type",  | 
2472  | 0  |                 startLoc)) { | 
2473  | 0  |           return None;  | 
2474  | 0  |         }  | 
2475  | 0  |         auto optBody = parsePrefixTypeAnnotationFlow();  | 
2476  | 0  |         if (!optBody)  | 
2477  | 0  |           return None;  | 
2478  | 0  |         return setLocation(  | 
2479  | 0  |             startLoc,  | 
2480  | 0  |             getPrevTokenEndLoc(),  | 
2481  | 0  |             new (context_)  | 
2482  | 0  |                 ESTree::TypeOperatorNode(rendersMaybeOperator_, *optBody));  | 
2483  | 0  |       }  | 
2484  | 0  |     }  | 
2485  | 0  |   }  | 
2486  |  |  | 
2487  | 0  |   return parseTypeAnnotationFlow();  | 
2488  | 0  | }  | 
2489  |  |  | 
2490  |  | Optional<ESTree::Node *> JSParserImpl::parseTypeAnnotationFlow(  | 
2491  |  |     Optional<SMLoc> wrappedStart,  | 
2492  | 0  |     AllowAnonFunctionType allowAnonFunctionType) { | 
2493  | 0  |   llvh::SaveAndRestore<bool> saveParam(  | 
2494  | 0  |       allowAnonFunctionType_,  | 
2495  | 0  |       allowAnonFunctionType == AllowAnonFunctionType::Yes);  | 
2496  | 0  |   auto optType = parseConditionalTypeAnnotationFlow();  | 
2497  | 0  |   if (!optType)  | 
2498  | 0  |     return None;  | 
2499  | 0  |   if (wrappedStart) { | 
2500  | 0  |     return setLocation(  | 
2501  | 0  |         *wrappedStart,  | 
2502  | 0  |         getPrevTokenEndLoc(),  | 
2503  | 0  |         new (context_) ESTree::TypeAnnotationNode(*optType));  | 
2504  | 0  |   }  | 
2505  | 0  |   return *optType;  | 
2506  | 0  | }  | 
2507  |  |  | 
2508  | 0  | Optional<ESTree::Node *> JSParserImpl::parseConditionalTypeAnnotationFlow() { | 
2509  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2510  | 0  |   llvh::SaveAndRestore<bool> saveParam(allowConditionalType_, true);  | 
2511  | 0  |   auto optCheck = parseUnionTypeAnnotationFlow();  | 
2512  | 0  |   if (!optCheck)  | 
2513  | 0  |     return None;  | 
2514  | 0  |   if (!checkAndEat(TokenKind::rw_extends, JSLexer::GrammarContext::Type)) { | 
2515  | 0  |     return optCheck;  | 
2516  | 0  |   }  | 
2517  | 0  |   Optional<ESTree::Node *> optExtends;  | 
2518  | 0  |   { | 
2519  |  |     // We need to enter the state of parsing the extends_type disallowing  | 
2520  |  |     // conditional types not wrapped by parantheses, so that the following  | 
2521  |  |     // sequence `A extends infer B extends C ? D : E` will be interpreted  | 
2522  |  |     // as `A extends (infer B extends C) ? D : E`.  | 
2523  | 0  |     llvh::SaveAndRestore<bool> saveParam(allowConditionalType_, false);  | 
2524  | 0  |     optExtends = parseUnionTypeAnnotationFlow();  | 
2525  | 0  |   }  | 
2526  | 0  |   if (!optExtends)  | 
2527  | 0  |     return None;  | 
2528  |  |  | 
2529  | 0  |   if (!eat(  | 
2530  | 0  |           TokenKind::question,  | 
2531  | 0  |           JSLexer::GrammarContext::Type,  | 
2532  | 0  |           "in conditional type",  | 
2533  | 0  |           "start of type",  | 
2534  | 0  |           start))  | 
2535  | 0  |     return None;  | 
2536  |  |  | 
2537  | 0  |   auto optTrue = parseTypeAnnotationFlow();  | 
2538  | 0  |   if (!optTrue)  | 
2539  | 0  |     return None;  | 
2540  | 0  |   if (!eat(  | 
2541  | 0  |           TokenKind::colon,  | 
2542  | 0  |           JSLexer::GrammarContext::Type,  | 
2543  | 0  |           "in conditional type",  | 
2544  | 0  |           "start of type",  | 
2545  | 0  |           start))  | 
2546  | 0  |     return None;  | 
2547  |  |  | 
2548  | 0  |   auto optFalse = parseTypeAnnotationFlow();  | 
2549  | 0  |   if (!optFalse)  | 
2550  | 0  |     return None;  | 
2551  |  |  | 
2552  | 0  |   return setLocation(  | 
2553  | 0  |       *optCheck,  | 
2554  | 0  |       getPrevTokenEndLoc(),  | 
2555  | 0  |       new (context_) ESTree::ConditionalTypeAnnotationNode(  | 
2556  | 0  |           *optCheck, *optExtends, *optTrue, *optFalse));  | 
2557  | 0  | }  | 
2558  |  |  | 
2559  | 0  | Optional<ESTree::Node *> JSParserImpl::parseUnionTypeAnnotationFlow() { | 
2560  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2561  | 0  |   checkAndEat(TokenKind::pipe, JSLexer::GrammarContext::Type);  | 
2562  |  | 
  | 
2563  | 0  |   auto optFirst = parseIntersectionTypeAnnotationFlow();  | 
2564  | 0  |   if (!optFirst)  | 
2565  | 0  |     return None;  | 
2566  |  |  | 
2567  | 0  |   if (!check(TokenKind::pipe)) { | 
2568  |  |     // Done with the union, move on.  | 
2569  | 0  |     return *optFirst;  | 
2570  | 0  |   }  | 
2571  |  |  | 
2572  | 0  |   ESTree::NodeList types{}; | 
2573  | 0  |   types.push_back(**optFirst);  | 
2574  |  | 
  | 
2575  | 0  |   while (checkAndEat(TokenKind::pipe, JSLexer::GrammarContext::Type)) { | 
2576  | 0  |     auto optInt = parseIntersectionTypeAnnotationFlow();  | 
2577  | 0  |     if (!optInt)  | 
2578  | 0  |       return None;  | 
2579  | 0  |     types.push_back(**optInt);  | 
2580  | 0  |   }  | 
2581  |  |  | 
2582  | 0  |   return setLocation(  | 
2583  | 0  |       start,  | 
2584  | 0  |       getPrevTokenEndLoc(),  | 
2585  | 0  |       new (context_) ESTree::UnionTypeAnnotationNode(std::move(types)));  | 
2586  | 0  | }  | 
2587  |  |  | 
2588  | 0  | Optional<ESTree::Node *> JSParserImpl::parseIntersectionTypeAnnotationFlow() { | 
2589  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2590  | 0  |   checkAndEat(TokenKind::amp, JSLexer::GrammarContext::Type);  | 
2591  |  | 
  | 
2592  | 0  |   auto optFirst = parseAnonFunctionWithoutParensTypeAnnotationFlow();  | 
2593  | 0  |   if (!optFirst)  | 
2594  | 0  |     return None;  | 
2595  |  |  | 
2596  | 0  |   if (!check(TokenKind::amp)) { | 
2597  |  |     // Done with the union, move on.  | 
2598  | 0  |     return *optFirst;  | 
2599  | 0  |   }  | 
2600  |  |  | 
2601  | 0  |   ESTree::NodeList types{}; | 
2602  | 0  |   types.push_back(**optFirst);  | 
2603  |  | 
  | 
2604  | 0  |   while (checkAndEat(TokenKind::amp, JSLexer::GrammarContext::Type)) { | 
2605  | 0  |     auto optInt = parseAnonFunctionWithoutParensTypeAnnotationFlow();  | 
2606  | 0  |     if (!optInt)  | 
2607  | 0  |       return None;  | 
2608  | 0  |     types.push_back(**optInt);  | 
2609  | 0  |   }  | 
2610  |  |  | 
2611  | 0  |   return setLocation(  | 
2612  | 0  |       start,  | 
2613  | 0  |       getPrevTokenEndLoc(),  | 
2614  | 0  |       new (context_) ESTree::IntersectionTypeAnnotationNode(std::move(types)));  | 
2615  | 0  | }  | 
2616  |  |  | 
2617  |  | Optional<ESTree::Node *>  | 
2618  | 0  | JSParserImpl::parseAnonFunctionWithoutParensTypeAnnotationFlow() { | 
2619  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2620  | 0  |   auto optParam = parsePrefixTypeAnnotationFlow();  | 
2621  | 0  |   if (!optParam)  | 
2622  | 0  |     return None;  | 
2623  |  |  | 
2624  | 0  |   if (allowAnonFunctionType_ && check(TokenKind::equalgreater)) { | 
2625  |  |     // ParamType => ReturnType  | 
2626  |  |     //           ^  | 
2627  | 0  |     ESTree::NodeList params{}; | 
2628  |  |     // "Reparse" the param into a FunctionTypeParam so it can be used for  | 
2629  |  |     // parseFunctionTypeAnnotationWithParamsFlow.  | 
2630  | 0  |     params.push_back(*setLocation(  | 
2631  | 0  |         *optParam,  | 
2632  | 0  |         *optParam,  | 
2633  | 0  |         new (context_) ESTree::FunctionTypeParamNode(  | 
2634  | 0  |             /* name */ nullptr, *optParam, /* optional */ false)));  | 
2635  | 0  |     ESTree::Node *rest = nullptr;  | 
2636  | 0  |     ESTree::Node *typeParams = nullptr;  | 
2637  | 0  |     return parseFunctionTypeAnnotationWithParamsFlow(  | 
2638  | 0  |         start, std::move(params), nullptr, rest, typeParams, /* hook */ false);  | 
2639  | 0  |   }  | 
2640  |  |  | 
2641  | 0  |   return *optParam;  | 
2642  | 0  | }  | 
2643  |  |  | 
2644  | 0  | Optional<ESTree::Node *> JSParserImpl::parsePrefixTypeAnnotationFlow() { | 
2645  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2646  | 0  |   if (checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type)) { | 
2647  | 0  |     auto optPrefix = parsePrefixTypeAnnotationFlow();  | 
2648  | 0  |     if (!optPrefix)  | 
2649  | 0  |       return None;  | 
2650  | 0  |     return setLocation(  | 
2651  | 0  |         start,  | 
2652  | 0  |         getPrevTokenEndLoc(),  | 
2653  | 0  |         new (context_) ESTree::NullableTypeAnnotationNode(*optPrefix));  | 
2654  | 0  |   }  | 
2655  | 0  |   return parsePostfixTypeAnnotationFlow();  | 
2656  | 0  | }  | 
2657  |  |  | 
2658  | 0  | Optional<ESTree::Node *> JSParserImpl::parsePostfixTypeAnnotationFlow() { | 
2659  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2660  | 0  |   auto optPrimary = parsePrimaryTypeAnnotationFlow();  | 
2661  | 0  |   if (!optPrimary)  | 
2662  | 0  |     return None;  | 
2663  |  |  | 
2664  | 0  |   ESTree::Node *result = *optPrimary;  | 
2665  | 0  |   bool seenOptionalIndexedAccess = false;  | 
2666  |  | 
  | 
2667  | 0  |   while (check(TokenKind::l_square, TokenKind::questiondot) &&  | 
2668  | 0  |          !lexer_.isNewLineBeforeCurrentToken()) { | 
2669  | 0  |     bool optional = checkAndEat(TokenKind::questiondot);  | 
2670  | 0  |     seenOptionalIndexedAccess = seenOptionalIndexedAccess || optional;  | 
2671  |  | 
  | 
2672  | 0  |     if (!eat(  | 
2673  | 0  |             TokenKind::l_square,  | 
2674  | 0  |             JSLexer::GrammarContext::Type,  | 
2675  | 0  |             "in indexed access type or postfix array type syntax",  | 
2676  | 0  |             "start of a type",  | 
2677  | 0  |             start))  | 
2678  | 0  |       return None;  | 
2679  |  |  | 
2680  | 0  |     if (!optional &&  | 
2681  | 0  |         checkAndEat(TokenKind::r_square, JSLexer::GrammarContext::Type)) { | 
2682  |  |       // Legacy Array syntax `T[]`  | 
2683  | 0  |       result = setLocation(  | 
2684  | 0  |           start,  | 
2685  | 0  |           getPrevTokenEndLoc(),  | 
2686  | 0  |           new (context_) ESTree::ArrayTypeAnnotationNode(result));  | 
2687  | 0  |     } else { | 
2688  |  |       // Indexed Access `T[K]` (`T?.[K]` if `optional`)  | 
2689  | 0  |       auto optIndexType = parseTypeAnnotationFlow();  | 
2690  | 0  |       if (!optIndexType)  | 
2691  | 0  |         return None;  | 
2692  | 0  |       if (!need(  | 
2693  | 0  |               TokenKind::r_square,  | 
2694  | 0  |               "in indexed access type",  | 
2695  | 0  |               "start of type",  | 
2696  | 0  |               start))  | 
2697  | 0  |         return None;  | 
2698  | 0  |       if (seenOptionalIndexedAccess) { | 
2699  | 0  |         result = setLocation(  | 
2700  | 0  |             start,  | 
2701  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2702  | 0  |             new (context_) ESTree::OptionalIndexedAccessTypeNode(  | 
2703  | 0  |                 result, *optIndexType, optional));  | 
2704  | 0  |       } else { | 
2705  | 0  |         result = setLocation(  | 
2706  | 0  |             start,  | 
2707  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2708  | 0  |             new (context_)  | 
2709  | 0  |                 ESTree::IndexedAccessTypeNode(result, *optIndexType));  | 
2710  | 0  |       }  | 
2711  | 0  |     }  | 
2712  | 0  |   }  | 
2713  |  |  | 
2714  | 0  |   return result;  | 
2715  | 0  | }  | 
2716  |  |  | 
2717  | 0  | Optional<ESTree::Node *> JSParserImpl::parsePrimaryTypeAnnotationFlow() { | 
2718  | 0  |   SMLoc start = tok_->getStartLoc();  | 
2719  | 0  |   switch (tok_->getKind()) { | 
2720  | 0  |     case TokenKind::star:  | 
2721  | 0  |       return setLocation(  | 
2722  | 0  |           start,  | 
2723  | 0  |           advance(JSLexer::GrammarContext::Type).End,  | 
2724  | 0  |           new (context_) ESTree::ExistsTypeAnnotationNode());  | 
2725  | 0  |     case TokenKind::less:  | 
2726  | 0  |       return parseFunctionTypeAnnotationFlow();  | 
2727  | 0  |     case TokenKind::l_paren:  | 
2728  | 0  |       return parseFunctionOrGroupTypeAnnotationFlow();  | 
2729  | 0  |     case TokenKind::l_brace:  | 
2730  | 0  |     case TokenKind::l_bracepipe:  | 
2731  | 0  |       return parseObjectTypeAnnotationFlow(  | 
2732  | 0  |           AllowProtoProperty::No,  | 
2733  | 0  |           AllowStaticProperty::No,  | 
2734  | 0  |           AllowSpreadProperty::Yes);  | 
2735  | 0  |     case TokenKind::rw_interface: { | 
2736  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
2737  | 0  |       ESTree::NodeList extends{}; | 
2738  | 0  |       auto optBody = parseInterfaceTailFlow(start, extends);  | 
2739  | 0  |       if (!optBody)  | 
2740  | 0  |         return None;  | 
2741  | 0  |       return setLocation(  | 
2742  | 0  |           start,  | 
2743  | 0  |           *optBody,  | 
2744  | 0  |           new (context_) ESTree::InterfaceTypeAnnotationNode(  | 
2745  | 0  |               std::move(extends), *optBody));  | 
2746  | 0  |     }  | 
2747  | 0  |     case TokenKind::rw_typeof:  | 
2748  | 0  |       return parseTypeofTypeAnnotationFlow();  | 
2749  |  |  | 
2750  | 0  |     case TokenKind::l_square:  | 
2751  | 0  |       return parseTupleTypeAnnotationFlow();  | 
2752  | 0  |     case TokenKind::rw_static:  | 
2753  | 0  |     case TokenKind::rw_this:  | 
2754  | 0  |     case TokenKind::identifier:  | 
2755  | 0  |       if (tok_->getResWordOrIdentifier() == anyIdent_) { | 
2756  | 0  |         return setLocation(  | 
2757  | 0  |             start,  | 
2758  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2759  | 0  |             new (context_) ESTree::AnyTypeAnnotationNode());  | 
2760  | 0  |       }  | 
2761  | 0  |       if (tok_->getResWordOrIdentifier() == mixedIdent_) { | 
2762  | 0  |         return setLocation(  | 
2763  | 0  |             start,  | 
2764  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2765  | 0  |             new (context_) ESTree::MixedTypeAnnotationNode());  | 
2766  | 0  |       }  | 
2767  | 0  |       if (tok_->getResWordOrIdentifier() == emptyIdent_) { | 
2768  | 0  |         return setLocation(  | 
2769  | 0  |             start,  | 
2770  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2771  | 0  |             new (context_) ESTree::EmptyTypeAnnotationNode());  | 
2772  | 0  |       }  | 
2773  | 0  |       if (tok_->getResWordOrIdentifier() == booleanIdent_ ||  | 
2774  | 0  |           tok_->getResWordOrIdentifier() == boolIdent_) { | 
2775  | 0  |         return setLocation(  | 
2776  | 0  |             start,  | 
2777  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2778  | 0  |             new (context_) ESTree::BooleanTypeAnnotationNode());  | 
2779  | 0  |       }  | 
2780  | 0  |       if (tok_->getResWordOrIdentifier() == numberIdent_) { | 
2781  | 0  |         return setLocation(  | 
2782  | 0  |             start,  | 
2783  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2784  | 0  |             new (context_) ESTree::NumberTypeAnnotationNode());  | 
2785  | 0  |       }  | 
2786  | 0  |       if (tok_->getResWordOrIdentifier() == symbolIdent_) { | 
2787  | 0  |         return setLocation(  | 
2788  | 0  |             start,  | 
2789  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2790  | 0  |             new (context_) ESTree::SymbolTypeAnnotationNode());  | 
2791  | 0  |       }  | 
2792  | 0  |       if (tok_->getResWordOrIdentifier() == stringIdent_) { | 
2793  | 0  |         return setLocation(  | 
2794  | 0  |             start,  | 
2795  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2796  | 0  |             new (context_) ESTree::StringTypeAnnotationNode());  | 
2797  | 0  |       }  | 
2798  | 0  |       if (tok_->getResWordOrIdentifier() == bigintIdent_) { | 
2799  | 0  |         return setLocation(  | 
2800  | 0  |             start,  | 
2801  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2802  | 0  |             new (context_) ESTree::BigIntTypeAnnotationNode());  | 
2803  | 0  |       }  | 
2804  | 0  |       if (tok_->getResWordOrIdentifier() == keyofIdent_) { | 
2805  | 0  |         advance(JSLexer::GrammarContext::Type);  | 
2806  | 0  |         auto optBody = parsePrefixTypeAnnotationFlow();  | 
2807  | 0  |         if (!optBody)  | 
2808  | 0  |           return None;  | 
2809  | 0  |         return setLocation(  | 
2810  | 0  |             start,  | 
2811  | 0  |             getPrevTokenEndLoc(),  | 
2812  | 0  |             new (context_) ESTree::KeyofTypeAnnotationNode(*optBody));  | 
2813  | 0  |       }  | 
2814  | 0  |       if (context_.getParseFlowComponentSyntax() &&  | 
2815  | 0  |           tok_->getResWordOrIdentifier() == rendersIdent_) { | 
2816  | 0  |         auto optTypeOperator = parseRenderTypeOperator();  | 
2817  | 0  |         auto optBody = parsePrefixTypeAnnotationFlow();  | 
2818  | 0  |         if (!optBody || !optTypeOperator)  | 
2819  | 0  |           return None;  | 
2820  | 0  |         return setLocation(  | 
2821  | 0  |             start,  | 
2822  | 0  |             getPrevTokenEndLoc(),  | 
2823  | 0  |             new (context_)  | 
2824  | 0  |                 ESTree::TypeOperatorNode(*optTypeOperator, *optBody));  | 
2825  | 0  |       }  | 
2826  | 0  |       if (context_.getParseFlowComponentSyntax() &&  | 
2827  | 0  |           tok_->getResWordOrIdentifier() == componentIdent_) { | 
2828  | 0  |         auto optComponent = parseComponentTypeAnnotationFlow();  | 
2829  | 0  |         if (!optComponent)  | 
2830  | 0  |           return None;  | 
2831  | 0  |         return *optComponent;  | 
2832  | 0  |       }  | 
2833  | 0  |       if (context_.getParseFlowComponentSyntax() &&  | 
2834  | 0  |           tok_->getResWordOrIdentifier() == hookIdent_) { | 
2835  | 0  |         auto optHook = parseHookTypeAnnotationFlow();  | 
2836  | 0  |         if (!optHook)  | 
2837  | 0  |           return None;  | 
2838  | 0  |         return *optHook;  | 
2839  | 0  |       }  | 
2840  | 0  |       if (tok_->getResWordOrIdentifier() == interfaceIdent_) { | 
2841  | 0  |         advance(JSLexer::GrammarContext::Type);  | 
2842  | 0  |         ESTree::NodeList extends{}; | 
2843  | 0  |         auto optBody = parseInterfaceTailFlow(start, extends);  | 
2844  | 0  |         if (!optBody)  | 
2845  | 0  |           return None;  | 
2846  | 0  |         return setLocation(  | 
2847  | 0  |             start,  | 
2848  | 0  |             *optBody,  | 
2849  | 0  |             new (context_) ESTree::InterfaceTypeAnnotationNode(  | 
2850  | 0  |                 std::move(extends), *optBody));  | 
2851  | 0  |       }  | 
2852  | 0  |       if (tok_->getResWordOrIdentifier() == inferIdent_) { | 
2853  | 0  |         advance(JSLexer::GrammarContext::Type);  | 
2854  |  | 
  | 
2855  | 0  |         if (!need(TokenKind::identifier, "in type parameter", nullptr, {})) | 
2856  | 0  |           return None;  | 
2857  | 0  |         UniqueString *name = tok_->getIdentifier();  | 
2858  | 0  |         advance(JSLexer::GrammarContext::Type);  | 
2859  |  | 
  | 
2860  | 0  |         ESTree::Node *bound = nullptr;  | 
2861  | 0  |         if (check(TokenKind::rw_extends)) { | 
2862  |  |           // When we see an extends keyword,  | 
2863  |  |           // we enter the parsing logic that might need backtracking.  | 
2864  |  |           //  | 
2865  |  |           // For `infer A extends B ...`, is the `extends B` part of an infer  | 
2866  |  |           // type, or part of a larger conditional type like `infer A extends B  | 
2867  |  |           // ? C : D`?  | 
2868  |  |           //  | 
2869  |  |           // We don't know, so we assume it's part of the infer type for now,  | 
2870  |  |           // and later backtrack if the assumption is wrong.  | 
2871  | 0  |           JSLexer::SavePoint savePoint{&lexer_}; | 
2872  | 0  |           advance(JSLexer::GrammarContext::Type);  | 
2873  | 0  |           auto parsedBound = parseUnionTypeAnnotationFlow();  | 
2874  | 0  |           if ((allowConditionalType_ && check(TokenKind::question)) ||  | 
2875  | 0  |               !parsedBound) { | 
2876  |  |             // If we look ahead and see `?`, it might be the case that we are  | 
2877  |  |             // parsing a conditional type like `infer A extends B ? C : D`. If  | 
2878  |  |             // the current context allow parsing conditional type, then we must  | 
2879  |  |             // backtrack so that only `infer A` is treated as part of the infer  | 
2880  |  |             // type.  | 
2881  |  |             //  | 
2882  |  |             // Of course, if we fail to parse the type after extends, we also  | 
2883  |  |             // need to backtrack.  | 
2884  | 0  |             savePoint.restore();  | 
2885  | 0  |           } else { | 
2886  | 0  |             bound = *parsedBound;  | 
2887  | 0  |           }  | 
2888  | 0  |         }  | 
2889  |  | 
  | 
2890  | 0  |         return setLocation(  | 
2891  | 0  |             start,  | 
2892  | 0  |             getPrevTokenEndLoc(),  | 
2893  | 0  |             new (context_) ESTree::InferTypeAnnotationNode(setLocation(  | 
2894  | 0  |                 start,  | 
2895  | 0  |                 getPrevTokenEndLoc(),  | 
2896  | 0  |                 new (context_) ESTree::TypeParameterNode(  | 
2897  | 0  |                     name, false, bound, nullptr, nullptr, true))));  | 
2898  | 0  |       }  | 
2899  |  |  | 
2900  | 0  |       { | 
2901  | 0  |         auto optGeneric = parseGenericTypeFlow();  | 
2902  | 0  |         if (!optGeneric)  | 
2903  | 0  |           return None;  | 
2904  | 0  |         return *optGeneric;  | 
2905  | 0  |       }  | 
2906  |  |  | 
2907  | 0  |     case TokenKind::rw_null:  | 
2908  | 0  |       return setLocation(  | 
2909  | 0  |           start,  | 
2910  | 0  |           advance(JSLexer::GrammarContext::Type).End,  | 
2911  | 0  |           new (context_) ESTree::NullLiteralTypeAnnotationNode());  | 
2912  |  |  | 
2913  | 0  |     case TokenKind::rw_void:  | 
2914  | 0  |       return setLocation(  | 
2915  | 0  |           start,  | 
2916  | 0  |           advance(JSLexer::GrammarContext::Type).End,  | 
2917  | 0  |           new (context_) ESTree::VoidTypeAnnotationNode());  | 
2918  |  |  | 
2919  | 0  |     case TokenKind::string_literal: { | 
2920  | 0  |       UniqueString *str = tok_->getStringLiteral();  | 
2921  | 0  |       UniqueString *raw = lexer_.getStringLiteral(tok_->inputStr());  | 
2922  | 0  |       return setLocation(  | 
2923  | 0  |           start,  | 
2924  | 0  |           advance(JSLexer::GrammarContext::Type).End,  | 
2925  | 0  |           new (context_) ESTree::StringLiteralTypeAnnotationNode(str, raw));  | 
2926  | 0  |     }  | 
2927  |  |  | 
2928  | 0  |     case TokenKind::numeric_literal: { | 
2929  | 0  |       double value = tok_->getNumericLiteral();  | 
2930  | 0  |       UniqueString *raw = lexer_.getStringLiteral(tok_->inputStr());  | 
2931  | 0  |       return setLocation(  | 
2932  | 0  |           start,  | 
2933  | 0  |           advance(JSLexer::GrammarContext::Type).End,  | 
2934  | 0  |           new (context_) ESTree::NumberLiteralTypeAnnotationNode(value, raw));  | 
2935  | 0  |     }  | 
2936  |  |  | 
2937  | 0  |     case TokenKind::bigint_literal: { | 
2938  | 0  |       UniqueString *raw = tok_->getBigIntLiteral();  | 
2939  | 0  |       return setLocation(  | 
2940  | 0  |           start,  | 
2941  | 0  |           advance(JSLexer::GrammarContext::Type).End,  | 
2942  | 0  |           new (context_) ESTree::BigIntLiteralTypeAnnotationNode(raw));  | 
2943  | 0  |     }  | 
2944  |  |  | 
2945  | 0  |     case TokenKind::minus: { | 
2946  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
2947  | 0  |       if (check(TokenKind::numeric_literal)) { | 
2948  |  |         // Negate the literal.  | 
2949  | 0  |         double value = -tok_->getNumericLiteral();  | 
2950  | 0  |         UniqueString *raw = lexer_.getStringLiteral(llvh::StringRef(  | 
2951  | 0  |             start.getPointer(),  | 
2952  | 0  |             tok_->getEndLoc().getPointer() - start.getPointer()));  | 
2953  | 0  |         return setLocation(  | 
2954  | 0  |             start,  | 
2955  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2956  | 0  |             new (context_) ESTree::NumberLiteralTypeAnnotationNode(value, raw));  | 
2957  | 0  |       } else if (check(TokenKind::bigint_literal)) { | 
2958  | 0  |         UniqueString *raw = lexer_.getStringLiteral(llvh::StringRef(  | 
2959  | 0  |             start.getPointer(),  | 
2960  | 0  |             tok_->getEndLoc().getPointer() - start.getPointer()));  | 
2961  | 0  |         return setLocation(  | 
2962  | 0  |             start,  | 
2963  | 0  |             advance(JSLexer::GrammarContext::Type).End,  | 
2964  | 0  |             new (context_) ESTree::BigIntLiteralTypeAnnotationNode(raw));  | 
2965  | 0  |       } else { | 
2966  | 0  |         errorExpected(  | 
2967  | 0  |             TokenKind::numeric_literal,  | 
2968  | 0  |             "in type annotation",  | 
2969  | 0  |             "start of annotation",  | 
2970  | 0  |             start);  | 
2971  | 0  |         return None;  | 
2972  | 0  |       }  | 
2973  | 0  |     }  | 
2974  |  |  | 
2975  | 0  |     case TokenKind::rw_true:  | 
2976  | 0  |     case TokenKind::rw_false: { | 
2977  | 0  |       bool value = check(TokenKind::rw_true);  | 
2978  | 0  |       auto *raw = tok_->getResWordIdentifier();  | 
2979  | 0  |       return setLocation(  | 
2980  | 0  |           start,  | 
2981  | 0  |           advance(JSLexer::GrammarContext::Type).End,  | 
2982  | 0  |           new (context_) ESTree::BooleanLiteralTypeAnnotationNode(value, raw));  | 
2983  | 0  |     }  | 
2984  | 0  |     default:  | 
2985  | 0  |       if (tok_->isResWord()) { | 
2986  | 0  |         auto optGeneric = parseGenericTypeFlow();  | 
2987  | 0  |         if (!optGeneric)  | 
2988  | 0  |           return None;  | 
2989  | 0  |         return *optGeneric;  | 
2990  | 0  |       }  | 
2991  | 0  |       error(tok_->getStartLoc(), "unexpected token in type annotation");  | 
2992  | 0  |       return None;  | 
2993  | 0  |   }  | 
2994  | 0  | }  | 
2995  |  |  | 
2996  | 0  | Optional<ESTree::Node *> JSParserImpl::parseTypeofTypeAnnotationFlow() { | 
2997  | 0  |   assert(check(TokenKind::rw_typeof));  | 
2998  | 0  |   SMLoc startLoc = advance().Start;  | 
2999  | 0  |   uint32_t parenCount = 0;  | 
3000  |  | 
  | 
3001  | 0  |   while (checkAndEat(TokenKind::l_paren))  | 
3002  | 0  |     ++parenCount;  | 
3003  |  | 
  | 
3004  | 0  |   if (!need(TokenKind::identifier, "in typeof type", "start of type", startLoc))  | 
3005  | 0  |     return None;  | 
3006  |  |  | 
3007  | 0  |   ESTree::Node *ident = setLocation(  | 
3008  | 0  |       tok_,  | 
3009  | 0  |       tok_,  | 
3010  | 0  |       new (context_)  | 
3011  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
3012  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
3013  |  | 
  | 
3014  | 0  |   while (checkAndEat(TokenKind::period)) { | 
3015  | 0  |     if (!check(TokenKind::identifier) && !tok_->isResWord()) { | 
3016  | 0  |       errorExpected(  | 
3017  | 0  |           TokenKind::identifier,  | 
3018  | 0  |           "in qualified typeof type",  | 
3019  | 0  |           "start of type",  | 
3020  | 0  |           startLoc);  | 
3021  | 0  |       return None;  | 
3022  | 0  |     }  | 
3023  | 0  |     ESTree::Node *next = setLocation(  | 
3024  | 0  |         tok_,  | 
3025  | 0  |         tok_,  | 
3026  | 0  |         new (context_) ESTree::IdentifierNode(  | 
3027  | 0  |             tok_->getResWordOrIdentifier(), nullptr, false));  | 
3028  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
3029  | 0  |     ident = setLocation(  | 
3030  | 0  |         ident,  | 
3031  | 0  |         next,  | 
3032  | 0  |         new (context_) ESTree::QualifiedTypeofIdentifierNode(ident, next));  | 
3033  | 0  |   }  | 
3034  |  |  | 
3035  | 0  |   for (; parenCount > 0; --parenCount) { | 
3036  | 0  |     if (!eat(  | 
3037  | 0  |             TokenKind::r_paren,  | 
3038  | 0  |             JSLexer::GrammarContext::Type,  | 
3039  | 0  |             "in typeof type",  | 
3040  | 0  |             "start of type",  | 
3041  | 0  |             startLoc))  | 
3042  | 0  |       return None;  | 
3043  | 0  |     ident->incParens();  | 
3044  | 0  |   }  | 
3045  |  |  | 
3046  | 0  |   ESTree::Node *typeArguments = nullptr;  | 
3047  | 0  |   if (check(TokenKind::less) && !lexer_.isNewLineBeforeCurrentToken()) { | 
3048  | 0  |     auto optTypeArgs = parseTypeArgsFlow();  | 
3049  | 0  |     if (!optTypeArgs)  | 
3050  | 0  |       return None;  | 
3051  | 0  |     typeArguments = *optTypeArgs;  | 
3052  | 0  |   }  | 
3053  |  |  | 
3054  | 0  |   return setLocation(  | 
3055  | 0  |       startLoc,  | 
3056  | 0  |       getPrevTokenEndLoc(),  | 
3057  | 0  |       new (context_) ESTree::TypeofTypeAnnotationNode(ident, typeArguments));  | 
3058  | 0  | }  | 
3059  |  |  | 
3060  | 0  | Optional<ESTree::Node *> JSParserImpl::parseTupleTypeAnnotationFlow() { | 
3061  | 0  |   assert(check(TokenKind::l_square));  | 
3062  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
3063  |  | 
  | 
3064  | 0  |   ESTree::NodeList types{}; | 
3065  | 0  |   bool inexact = false;  | 
3066  |  | 
  | 
3067  | 0  |   while (!check(TokenKind::r_square)) { | 
3068  | 0  |     SMLoc startLoc = tok_->getStartLoc();  | 
3069  | 0  |     bool startsWithDotDotDot =  | 
3070  | 0  |         checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type);  | 
3071  |  |  | 
3072  |  |     // ...]  | 
3073  | 0  |     if (startsWithDotDotDot && check(TokenKind::r_square)) { | 
3074  | 0  |       inexact = true;  | 
3075  |  |       // ...,  | 
3076  | 0  |     } else if (startsWithDotDotDot && check(TokenKind::comma)) { | 
3077  | 0  |       error(  | 
3078  | 0  |           tok_->getSourceRange(),  | 
3079  | 0  |           "trailing commas after inexact tuple types are not allowed");  | 
3080  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
3081  | 0  |     } else { | 
3082  | 0  |       auto optType = parseTupleElementFlow(startLoc, startsWithDotDotDot);  | 
3083  | 0  |       if (!optType)  | 
3084  | 0  |         return None;  | 
3085  | 0  |       types.push_back(**optType);  | 
3086  |  | 
  | 
3087  | 0  |       if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))  | 
3088  | 0  |         break;  | 
3089  | 0  |     }  | 
3090  | 0  |   }  | 
3091  |  |  | 
3092  | 0  |   if (!need(  | 
3093  | 0  |           TokenKind::r_square,  | 
3094  | 0  |           "at end of tuple type annotation",  | 
3095  | 0  |           "start of tuple",  | 
3096  | 0  |           start))  | 
3097  | 0  |     return None;  | 
3098  |  |  | 
3099  | 0  |   return setLocation(  | 
3100  | 0  |       start,  | 
3101  | 0  |       advance(JSLexer::GrammarContext::Type).End,  | 
3102  | 0  |       new (context_)  | 
3103  | 0  |           ESTree::TupleTypeAnnotationNode(std::move(types), inexact));  | 
3104  | 0  | }  | 
3105  |  |  | 
3106  |  | Optional<ESTree::Node *> JSParserImpl::parseTupleElementFlow(  | 
3107  |  |     SMLoc startLoc,  | 
3108  | 0  |     bool startsWithDotDotDot) { | 
3109  | 0  |   ESTree::Node *label = nullptr;  | 
3110  | 0  |   ESTree::Node *elementType = nullptr;  | 
3111  | 0  |   ESTree::Node *variance = nullptr;  | 
3112  |  |  | 
3113  |  |   // ...Identifier : Type  | 
3114  |  |   // ...Type  | 
3115  |  |   // ^  | 
3116  | 0  |   if (startsWithDotDotDot) { | 
3117  | 0  |     auto optType = parseTypeAnnotationBeforeColonFlow();  | 
3118  | 0  |     if (!optType)  | 
3119  | 0  |       return None;  | 
3120  | 0  |     if (checkAndEat(TokenKind::colon, JSLexer::GrammarContext::Type)) { | 
3121  | 0  |       auto optLabel = reparseTypeAnnotationAsIdentifierFlow(*optType);  | 
3122  | 0  |       if (!optLabel)  | 
3123  | 0  |         return None;  | 
3124  | 0  |       label = *optLabel;  | 
3125  | 0  |       auto optType = parseTypeAnnotationFlow();  | 
3126  | 0  |       if (!optType)  | 
3127  | 0  |         return None;  | 
3128  | 0  |       elementType = *optType;  | 
3129  | 0  |       return setLocation(  | 
3130  | 0  |           startLoc,  | 
3131  | 0  |           getPrevTokenEndLoc(),  | 
3132  | 0  |           new (context_)  | 
3133  | 0  |               ESTree::TupleTypeSpreadElementNode(label, elementType));  | 
3134  | 0  |     }  | 
3135  |  |  | 
3136  | 0  |     return setLocation(  | 
3137  | 0  |         startLoc,  | 
3138  | 0  |         getPrevTokenEndLoc(),  | 
3139  | 0  |         new (context_) ESTree::TupleTypeSpreadElementNode(label, *optType));  | 
3140  | 0  |   }  | 
3141  |  |  | 
3142  |  |   /// +Identifier : Type  | 
3143  |  |   /// -Identifier : Type  | 
3144  |  |   /// ^  | 
3145  | 0  |   if (check(TokenKind::plus, TokenKind::minus)) { | 
3146  | 0  |     variance = setLocation(  | 
3147  | 0  |         tok_,  | 
3148  | 0  |         tok_,  | 
3149  | 0  |         new (context_) ESTree::VarianceNode(  | 
3150  | 0  |             check(TokenKind::plus) ? plusIdent_ : minusIdent_));  | 
3151  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
3152  | 0  |   }  | 
3153  |  |  | 
3154  |  |   /// Identifier [?] : Type  | 
3155  |  |   /// Type  | 
3156  |  |   /// ^  | 
3157  | 0  |   auto optType = parseTypeAnnotationBeforeColonFlow();  | 
3158  | 0  |   if (!optType)  | 
3159  | 0  |     return None;  | 
3160  |  |  | 
3161  |  |   /// Identifier [?] : Type  | 
3162  |  |   ///             ^  | 
3163  | 0  |   if (check(TokenKind::colon, TokenKind::question)) { | 
3164  | 0  |     bool optional =  | 
3165  | 0  |         checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type);  | 
3166  |  | 
  | 
3167  | 0  |     if (!eat(  | 
3168  | 0  |             TokenKind::colon,  | 
3169  | 0  |             JSLexer::GrammarContext::Type,  | 
3170  | 0  |             "in labeled tuple type element",  | 
3171  | 0  |             "location of tuple",  | 
3172  | 0  |             startLoc))  | 
3173  | 0  |       return None;  | 
3174  |  |  | 
3175  | 0  |     auto optLabel = reparseTypeAnnotationAsIdentifierFlow(*optType);  | 
3176  | 0  |     if (!optLabel)  | 
3177  | 0  |       return None;  | 
3178  | 0  |     label = *optLabel;  | 
3179  | 0  |     auto optType = parseTypeAnnotationFlow();  | 
3180  | 0  |     if (!optType)  | 
3181  | 0  |       return None;  | 
3182  | 0  |     elementType = *optType;  | 
3183  |  | 
  | 
3184  | 0  |     return setLocation(  | 
3185  | 0  |         startLoc,  | 
3186  | 0  |         getPrevTokenEndLoc(),  | 
3187  | 0  |         new (context_) ESTree::TupleTypeLabeledElementNode(  | 
3188  | 0  |             label, elementType, optional, variance));  | 
3189  | 0  |   }  | 
3190  |  |  | 
3191  | 0  |   if (variance) { | 
3192  | 0  |     error(  | 
3193  | 0  |         variance->getSourceRange(),  | 
3194  | 0  |         "Variance can only be used with labeled tuple elements");  | 
3195  | 0  |   }  | 
3196  |  | 
  | 
3197  | 0  |   return *optType;  | 
3198  | 0  | }  | 
3199  |  |  | 
3200  | 0  | Optional<ESTree::Node *> JSParserImpl::parseHookTypeAnnotationFlow() { | 
3201  |  |   // hook  | 
3202  | 0  |   assert(check(hookIdent_));  | 
3203  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
3204  | 0  |   return parseFunctionOrHookTypeAnnotationFlow(true);  | 
3205  | 0  | }  | 
3206  |  |  | 
3207  | 0  | Optional<ESTree::Node *> JSParserImpl::parseFunctionTypeAnnotationFlow() { | 
3208  | 0  |   return parseFunctionOrHookTypeAnnotationFlow(false);  | 
3209  | 0  | }  | 
3210  |  |  | 
3211  |  | Optional<ESTree::Node *> JSParserImpl::parseFunctionOrHookTypeAnnotationFlow(  | 
3212  | 0  |     bool hook) { | 
3213  | 0  |   SMLoc start = tok_->getStartLoc();  | 
3214  |  | 
  | 
3215  | 0  |   ESTree::Node *typeParams = nullptr;  | 
3216  | 0  |   if (check(TokenKind::less)) { | 
3217  | 0  |     auto optParams = parseTypeParamsFlow();  | 
3218  | 0  |     if (!optParams)  | 
3219  | 0  |       return None;  | 
3220  | 0  |     typeParams = *optParams;  | 
3221  | 0  |   }  | 
3222  |  |  | 
3223  | 0  |   if (!need(  | 
3224  | 0  |           TokenKind::l_paren,  | 
3225  | 0  |           "in function type annotation",  | 
3226  | 0  |           "start of annotation",  | 
3227  | 0  |           start))  | 
3228  | 0  |     return None;  | 
3229  |  |  | 
3230  | 0  |   ESTree::NodeList params{}; | 
3231  | 0  |   ESTree::Node *thisConstraint = nullptr;  | 
3232  | 0  |   auto optRest =  | 
3233  | 0  |       parseFunctionTypeAnnotationParamsFlow(params, thisConstraint, hook);  | 
3234  | 0  |   if (!optRest)  | 
3235  | 0  |     return None;  | 
3236  | 0  |   ESTree::Node *rest = *optRest;  | 
3237  |  | 
  | 
3238  | 0  |   if (!need(  | 
3239  | 0  |           TokenKind::equalgreater,  | 
3240  | 0  |           "in function type annotation",  | 
3241  | 0  |           "start of annotation",  | 
3242  | 0  |           start))  | 
3243  | 0  |     return None;  | 
3244  |  |  | 
3245  | 0  |   return parseFunctionTypeAnnotationWithParamsFlow(  | 
3246  | 0  |       start, std::move(params), thisConstraint, rest, typeParams, hook);  | 
3247  | 0  | }  | 
3248  |  |  | 
3249  |  | Optional<ESTree::Node *>  | 
3250  |  | JSParserImpl::parseFunctionTypeAnnotationWithParamsFlow(  | 
3251  |  |     SMLoc start,  | 
3252  |  |     ESTree::NodeList &¶ms,  | 
3253  |  |     ESTree::Node *thisConstraint,  | 
3254  |  |     ESTree::Node *rest,  | 
3255  |  |     ESTree::Node *typeParams,  | 
3256  | 0  |     bool hook) { | 
3257  | 0  |   assert(check(TokenKind::equalgreater));  | 
3258  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
3259  |  | 
  | 
3260  | 0  |   auto optReturnType = parseReturnTypeAnnotationFlow();  | 
3261  | 0  |   if (!optReturnType)  | 
3262  | 0  |     return None;  | 
3263  |  |  | 
3264  | 0  |   if (!hook) { | 
3265  | 0  |     return setLocation(  | 
3266  | 0  |         start,  | 
3267  | 0  |         getPrevTokenEndLoc(),  | 
3268  | 0  |         new (context_) ESTree::FunctionTypeAnnotationNode(  | 
3269  | 0  |             std::move(params),  | 
3270  | 0  |             thisConstraint,  | 
3271  | 0  |             *optReturnType,  | 
3272  | 0  |             rest,  | 
3273  | 0  |             typeParams));  | 
3274  | 0  |   } else { | 
3275  | 0  |     return setLocation(  | 
3276  | 0  |         start,  | 
3277  | 0  |         getPrevTokenEndLoc(),  | 
3278  | 0  |         new (context_) ESTree::HookTypeAnnotationNode(  | 
3279  | 0  |             std::move(params), *optReturnType, rest, typeParams));  | 
3280  | 0  |   }  | 
3281  | 0  | }  | 
3282  |  |  | 
3283  |  | Optional<ESTree::Node *>  | 
3284  | 0  | JSParserImpl::parseFunctionOrGroupTypeAnnotationFlow() { | 
3285  | 0  |   assert(check(TokenKind::l_paren));  | 
3286  |  |   // This is either  | 
3287  |  |   // ( Type )  | 
3288  |  |   // ^  | 
3289  |  |   // or  | 
3290  |  |   // ( ParamList ) => Type  | 
3291  |  |   // ^  | 
3292  |  |   // so we use a similar approach to arrow function parameters by keeping track  | 
3293  |  |   // and reparsing in certain cases.  | 
3294  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
3295  |  | 
  | 
3296  | 0  |   bool isFunction = false;  | 
3297  | 0  |   ESTree::Node *type = nullptr;  | 
3298  | 0  |   ESTree::Node *rest = nullptr;  | 
3299  | 0  |   ESTree::NodeList params{}; | 
3300  | 0  |   ESTree::Node *thisConstraint = nullptr;  | 
3301  |  | 
  | 
3302  | 0  |   if (check(TokenKind::rw_this)) { | 
3303  | 0  |     OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
3304  | 0  |     if (optNext.hasValue() && *optNext == TokenKind::colon) { | 
3305  | 0  |       SMLoc thisStart = advance(JSLexer::GrammarContext::Type).Start;  | 
3306  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
3307  | 0  |       auto optType = parseTypeAnnotationFlow();  | 
3308  | 0  |       if (!optType)  | 
3309  | 0  |         return None;  | 
3310  | 0  |       ESTree::Node *typeAnnotation = *optType;  | 
3311  |  | 
  | 
3312  | 0  |       thisConstraint = setLocation(  | 
3313  | 0  |           thisStart,  | 
3314  | 0  |           getPrevTokenEndLoc(),  | 
3315  | 0  |           new (context_) ESTree::FunctionTypeParamNode(  | 
3316  | 0  |               /* name */ nullptr, typeAnnotation, /* optional */ false));  | 
3317  | 0  |       checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);  | 
3318  | 0  |     } else if (optNext.hasValue() && *optNext == TokenKind::question) { | 
3319  | 0  |       error(tok_->getSourceRange(), "'this' constraint may not be optional");  | 
3320  | 0  |     }  | 
3321  | 0  |   }  | 
3322  |  |  | 
3323  | 0  |   if (allowAnonFunctionType_ &&  | 
3324  | 0  |       checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type)) { | 
3325  | 0  |     isFunction = true;  | 
3326  |  |     // Must be parameters, and this must be the last one.  | 
3327  | 0  |     auto optParam = parseFunctionTypeAnnotationParamFlow();  | 
3328  | 0  |     if (!optParam)  | 
3329  | 0  |       return None;  | 
3330  |  |     // Rest param must be the last param.  | 
3331  | 0  |     rest = *optParam;  | 
3332  | 0  |   } else if (check(TokenKind::r_paren)) { | 
3333  | 0  |     isFunction = true;  | 
3334  |  |     // ( )  | 
3335  |  |     //   ^  | 
3336  |  |     // No parameters, but this must be an empty param list.  | 
3337  | 0  |   } else { | 
3338  |  |     // Not sure yet whether this is a param or simply a type.  | 
3339  | 0  |     auto optParam = parseFunctionTypeAnnotationParamFlow();  | 
3340  | 0  |     if (!optParam)  | 
3341  | 0  |       return None;  | 
3342  | 0  |     ESTree::FunctionTypeParamNode *param = *optParam;  | 
3343  | 0  |     type = param->_typeAnnotation;  | 
3344  | 0  |     if (param->_name || param->_optional) { | 
3345  |  |       // Must be a param if it has a name.or if it was optional.  | 
3346  | 0  |       isFunction = true;  | 
3347  | 0  |     }  | 
3348  | 0  |     params.push_back(*param);  | 
3349  | 0  |   }  | 
3350  |  |  | 
3351  |  |   // If isFunction was already forced by something previously then we  | 
3352  |  |   // have no choice but to attempt to parse as a function type annotation.  | 
3353  | 0  |   if ((isFunction || allowAnonFunctionType_) &&  | 
3354  | 0  |       checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type)) { | 
3355  | 0  |     isFunction = true;  | 
3356  | 0  |     while (!check(TokenKind::r_paren)) { | 
3357  | 0  |       bool isRest = !rest &&  | 
3358  | 0  |           checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type);  | 
3359  |  | 
  | 
3360  | 0  |       auto optParam = parseFunctionTypeAnnotationParamFlow();  | 
3361  | 0  |       if (!optParam)  | 
3362  | 0  |         return None;  | 
3363  | 0  |       if (isRest) { | 
3364  | 0  |         rest = *optParam;  | 
3365  | 0  |         checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);  | 
3366  | 0  |         break;  | 
3367  | 0  |       } else { | 
3368  | 0  |         params.push_back(**optParam);  | 
3369  | 0  |       }  | 
3370  |  |  | 
3371  | 0  |       if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))  | 
3372  | 0  |         break;  | 
3373  | 0  |     }  | 
3374  | 0  |   }  | 
3375  |  |  | 
3376  | 0  |   if (!eat(  | 
3377  | 0  |           TokenKind::r_paren,  | 
3378  | 0  |           JSLexer::GrammarContext::Type,  | 
3379  | 0  |           "at end of function annotation parameters",  | 
3380  | 0  |           "start of parameters",  | 
3381  | 0  |           start))  | 
3382  | 0  |     return None;  | 
3383  |  |  | 
3384  | 0  |   if (isFunction) { | 
3385  | 0  |     if (!eat(  | 
3386  | 0  |             TokenKind::equalgreater,  | 
3387  | 0  |             JSLexer::GrammarContext::Type,  | 
3388  | 0  |             "in function type annotation",  | 
3389  | 0  |             "start of function",  | 
3390  | 0  |             start))  | 
3391  | 0  |       return None;  | 
3392  | 0  |   } else if (allowAnonFunctionType_) { | 
3393  | 0  |     if (checkAndEat(TokenKind::equalgreater, JSLexer::GrammarContext::Type)) { | 
3394  | 0  |       isFunction = true;  | 
3395  | 0  |     }  | 
3396  | 0  |   }  | 
3397  |  |  | 
3398  | 0  |   if (!isFunction) { | 
3399  | 0  |     type->incParens();  | 
3400  | 0  |     return type;  | 
3401  | 0  |   }  | 
3402  |  |  | 
3403  | 0  |   auto optReturnType = parseReturnTypeAnnotationFlow(  | 
3404  | 0  |       None,  | 
3405  | 0  |       allowAnonFunctionType_ ? AllowAnonFunctionType::Yes  | 
3406  | 0  |                              : AllowAnonFunctionType::No);  | 
3407  | 0  |   if (!optReturnType)  | 
3408  | 0  |     return None;  | 
3409  |  |  | 
3410  | 0  |   ESTree::Node *typeParams = nullptr;  | 
3411  | 0  |   return setLocation(  | 
3412  | 0  |       start,  | 
3413  | 0  |       getPrevTokenEndLoc(),  | 
3414  | 0  |       new (context_) ESTree::FunctionTypeAnnotationNode(  | 
3415  | 0  |           std::move(params), thisConstraint, *optReturnType, rest, typeParams));  | 
3416  | 0  | }  | 
3417  |  |  | 
3418  |  | Optional<ESTree::Node *> JSParserImpl::parseObjectTypeAnnotationFlow(  | 
3419  |  |     AllowProtoProperty allowProtoProperty,  | 
3420  |  |     AllowStaticProperty allowStaticProperty,  | 
3421  | 0  |     AllowSpreadProperty allowSpreadProperty) { | 
3422  | 0  |   assert(check(TokenKind::l_brace, TokenKind::l_bracepipe));  | 
3423  | 0  |   bool exact = check(TokenKind::l_bracepipe);  | 
3424  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
3425  |  | 
  | 
3426  | 0  |   ESTree::NodeList properties{}; | 
3427  | 0  |   ESTree::NodeList indexers{}; | 
3428  | 0  |   ESTree::NodeList callProperties{}; | 
3429  | 0  |   ESTree::NodeList internalSlots{}; | 
3430  | 0  |   bool inexact = false;  | 
3431  |  | 
  | 
3432  | 0  |   if (!parseObjectTypePropertiesFlow(  | 
3433  | 0  |           allowProtoProperty,  | 
3434  | 0  |           allowStaticProperty,  | 
3435  | 0  |           allowSpreadProperty,  | 
3436  | 0  |           properties,  | 
3437  | 0  |           indexers,  | 
3438  | 0  |           callProperties,  | 
3439  | 0  |           internalSlots,  | 
3440  | 0  |           inexact))  | 
3441  | 0  |     return None;  | 
3442  |  |  | 
3443  | 0  |   if (exact && inexact) { | 
3444  |  |     // Doesn't prevent parsing from continuing, but it is an error.  | 
3445  | 0  |     error(  | 
3446  | 0  |         start,  | 
3447  | 0  |         "Explicit inexact syntax cannot appear inside an explicit exact object type");  | 
3448  | 0  |   }  | 
3449  |  | 
  | 
3450  | 0  |   SMLoc end = tok_->getEndLoc();  | 
3451  | 0  |   if (!eat(  | 
3452  | 0  |           exact ? TokenKind::piper_brace : TokenKind::r_brace,  | 
3453  | 0  |           JSLexer::GrammarContext::Type,  | 
3454  | 0  |           "at end of exact object type annotation",  | 
3455  | 0  |           "start of object",  | 
3456  | 0  |           start))  | 
3457  | 0  |     return None;  | 
3458  |  |  | 
3459  | 0  |   return setLocation(  | 
3460  | 0  |       start,  | 
3461  | 0  |       end,  | 
3462  | 0  |       new (context_) ESTree::ObjectTypeAnnotationNode(  | 
3463  | 0  |           std::move(properties),  | 
3464  | 0  |           std::move(indexers),  | 
3465  | 0  |           std::move(callProperties),  | 
3466  | 0  |           std::move(internalSlots),  | 
3467  | 0  |           inexact,  | 
3468  | 0  |           exact));  | 
3469  | 0  | }  | 
3470  |  |  | 
3471  |  | bool JSParserImpl::parseObjectTypePropertiesFlow(  | 
3472  |  |     AllowProtoProperty allowProtoProperty,  | 
3473  |  |     AllowStaticProperty allowStaticProperty,  | 
3474  |  |     AllowSpreadProperty allowSpreadProperty,  | 
3475  |  |     ESTree::NodeList &properties,  | 
3476  |  |     ESTree::NodeList &indexers,  | 
3477  |  |     ESTree::NodeList &callProperties,  | 
3478  |  |     ESTree::NodeList &internalSlots,  | 
3479  | 0  |     bool &inexact) { | 
3480  | 0  |   while (!check(TokenKind::r_brace, TokenKind::piper_brace)) { | 
3481  | 0  |     SMLoc start = tok_->getStartLoc();  | 
3482  | 0  |     if (check(TokenKind::dotdotdot)) { | 
3483  |  |       // Spread property or explicit '...' for inexact.  | 
3484  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
3485  | 0  |       if (check(TokenKind::comma, TokenKind::semi)) { | 
3486  | 0  |         inexact = true;  | 
3487  | 0  |         advance(JSLexer::GrammarContext::Type);  | 
3488  |  |         // Explicit '...' must be the last element in the type annotation.  | 
3489  | 0  |         return true;  | 
3490  | 0  |       } else if (check(TokenKind::r_brace, TokenKind::piper_brace)) { | 
3491  | 0  |         inexact = true;  | 
3492  | 0  |         return true;  | 
3493  | 0  |       } else { | 
3494  | 0  |         if (allowSpreadProperty == AllowSpreadProperty::No) { | 
3495  | 0  |           error(  | 
3496  | 0  |               start, "Spreading a type is only allowed inside an object type");  | 
3497  | 0  |         }  | 
3498  | 0  |         auto optType = parseTypeAnnotationFlow();  | 
3499  | 0  |         if (!optType)  | 
3500  | 0  |           return false;  | 
3501  | 0  |         properties.push_back(*setLocation(  | 
3502  | 0  |             start,  | 
3503  | 0  |             getPrevTokenEndLoc(),  | 
3504  | 0  |             new (context_) ESTree::ObjectTypeSpreadPropertyNode(*optType)));  | 
3505  | 0  |       }  | 
3506  | 0  |     } else { | 
3507  | 0  |       if (!parsePropertyTypeAnnotationFlow(  | 
3508  | 0  |               allowProtoProperty,  | 
3509  | 0  |               allowStaticProperty,  | 
3510  | 0  |               properties,  | 
3511  | 0  |               indexers,  | 
3512  | 0  |               callProperties,  | 
3513  | 0  |               internalSlots))  | 
3514  | 0  |         return false;  | 
3515  | 0  |     }  | 
3516  |  |  | 
3517  | 0  |     if (check(TokenKind::comma, TokenKind::semi)) { | 
3518  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
3519  | 0  |     } else if (check(TokenKind::r_brace, TokenKind::piper_brace)) { | 
3520  | 0  |       return true;  | 
3521  | 0  |     } else { | 
3522  | 0  |       errorExpected(  | 
3523  | 0  |           {TokenKind::comma, | 
3524  | 0  |            TokenKind::semi,  | 
3525  | 0  |            TokenKind::r_brace,  | 
3526  | 0  |            TokenKind::piper_brace},  | 
3527  | 0  |           "after property",  | 
3528  | 0  |           "start of property",  | 
3529  | 0  |           start);  | 
3530  | 0  |       return false;  | 
3531  | 0  |     }  | 
3532  | 0  |   }  | 
3533  |  |  | 
3534  | 0  |   return true;  | 
3535  | 0  | }  | 
3536  |  |  | 
3537  |  | bool JSParserImpl::parsePropertyTypeAnnotationFlow(  | 
3538  |  |     AllowProtoProperty allowProtoProperty,  | 
3539  |  |     AllowStaticProperty allowStaticProperty,  | 
3540  |  |     ESTree::NodeList &properties,  | 
3541  |  |     ESTree::NodeList &indexers,  | 
3542  |  |     ESTree::NodeList &callProperties,  | 
3543  | 0  |     ESTree::NodeList &internalSlots) { | 
3544  | 0  |   SMRange startRange = tok_->getSourceRange();  | 
3545  | 0  |   SMLoc start = startRange.Start;  | 
3546  |  | 
  | 
3547  | 0  |   ESTree::Node *variance = nullptr;  | 
3548  | 0  |   bool isStatic = false;  | 
3549  | 0  |   bool proto = false;  | 
3550  |  | 
  | 
3551  | 0  |   if (check(protoIdent_)) { | 
3552  | 0  |     proto = true;  | 
3553  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
3554  | 0  |   }  | 
3555  |  | 
  | 
3556  | 0  |   if (!proto && (check(TokenKind::rw_static) || check(staticIdent_))) { | 
3557  | 0  |     isStatic = true;  | 
3558  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
3559  | 0  |   }  | 
3560  |  | 
  | 
3561  | 0  |   if (check(TokenKind::plus, TokenKind::minus)) { | 
3562  | 0  |     variance = setLocation(  | 
3563  | 0  |         tok_,  | 
3564  | 0  |         tok_,  | 
3565  | 0  |         new (context_) ESTree::VarianceNode(  | 
3566  | 0  |             check(TokenKind::plus) ? plusIdent_ : minusIdent_));  | 
3567  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
3568  | 0  |   }  | 
3569  |  | 
  | 
3570  | 0  |   if (checkAndEat(TokenKind::l_square, JSLexer::GrammarContext::Type)) { | 
3571  | 0  |     if (checkAndEat(TokenKind::l_square, JSLexer::GrammarContext::Type)) { | 
3572  | 0  |       if (variance) { | 
3573  | 0  |         error(variance->getSourceRange(), "Unexpected variance sigil");  | 
3574  | 0  |       }  | 
3575  | 0  |       if (proto) { | 
3576  | 0  |         error(startRange, "invalid 'proto' modifier");  | 
3577  | 0  |       }  | 
3578  | 0  |       if (isStatic && allowStaticProperty == AllowStaticProperty::No) { | 
3579  | 0  |         error(startRange, "invalid 'static' modifier");  | 
3580  | 0  |       }  | 
3581  |  |       // Internal slot  | 
3582  | 0  |       if (!check(TokenKind::identifier) && !tok_->isResWord()) { | 
3583  | 0  |         errorExpected(  | 
3584  | 0  |             TokenKind::identifier,  | 
3585  | 0  |             "in internal slot",  | 
3586  | 0  |             "start of internal slot",  | 
3587  | 0  |             start);  | 
3588  | 0  |         return false;  | 
3589  | 0  |       }  | 
3590  | 0  |       ESTree::IdentifierNode *id = setLocation(  | 
3591  | 0  |           tok_,  | 
3592  | 0  |           tok_,  | 
3593  | 0  |           new (context_) ESTree::IdentifierNode(  | 
3594  | 0  |               tok_->getResWordOrIdentifier(), nullptr, false));  | 
3595  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
3596  |  | 
  | 
3597  | 0  |       if (!eat(  | 
3598  | 0  |               TokenKind::r_square,  | 
3599  | 0  |               JSLexer::GrammarContext::Type,  | 
3600  | 0  |               "at end of internal slot",  | 
3601  | 0  |               "start of internal slot",  | 
3602  | 0  |               start))  | 
3603  | 0  |         return false;  | 
3604  | 0  |       if (!eat(  | 
3605  | 0  |               TokenKind::r_square,  | 
3606  | 0  |               JSLexer::GrammarContext::Type,  | 
3607  | 0  |               "at end of internal slot",  | 
3608  | 0  |               "start of internal slot",  | 
3609  | 0  |               start))  | 
3610  | 0  |         return false;  | 
3611  |  |  | 
3612  | 0  |       bool optional = false;  | 
3613  | 0  |       bool method = false;  | 
3614  | 0  |       ESTree::Node *value = nullptr;  | 
3615  |  | 
  | 
3616  | 0  |       if (check(TokenKind::less, TokenKind::l_paren)) { | 
3617  |  |         // Type params and method.  | 
3618  | 0  |         method = true;  | 
3619  | 0  |         ESTree::Node *typeParams = nullptr;  | 
3620  | 0  |         if (check(TokenKind::less)) { | 
3621  | 0  |           auto optParams = parseTypeParamsFlow();  | 
3622  | 0  |           if (!optParams)  | 
3623  | 0  |             return false;  | 
3624  | 0  |           typeParams = *optParams;  | 
3625  | 0  |         }  | 
3626  | 0  |         auto optMethodish = parseMethodishTypeAnnotationFlow(start, typeParams);  | 
3627  | 0  |         if (!optMethodish)  | 
3628  | 0  |           return false;  | 
3629  | 0  |         value = *optMethodish;  | 
3630  | 0  |       } else { | 
3631  |  |         // Standard type annotation.  | 
3632  | 0  |         optional =  | 
3633  | 0  |             checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type);  | 
3634  | 0  |         if (!eat(  | 
3635  | 0  |                 TokenKind::colon,  | 
3636  | 0  |                 JSLexer::GrammarContext::Type,  | 
3637  | 0  |                 "in type annotation",  | 
3638  | 0  |                 "start of annotation",  | 
3639  | 0  |                 start))  | 
3640  | 0  |           return false;  | 
3641  | 0  |         auto optValue = parseTypeAnnotationFlow();  | 
3642  | 0  |         if (!optValue)  | 
3643  | 0  |           return false;  | 
3644  | 0  |         value = *optValue;  | 
3645  | 0  |       }  | 
3646  |  |  | 
3647  | 0  |       assert(value && "value must be set by a branch");  | 
3648  | 0  |       internalSlots.push_back(*setLocation(  | 
3649  | 0  |           start,  | 
3650  | 0  |           getPrevTokenEndLoc(),  | 
3651  | 0  |           new (context_) ESTree::ObjectTypeInternalSlotNode(  | 
3652  | 0  |               id, value, optional, isStatic, method)));  | 
3653  | 0  |     } else { | 
3654  |  |       // Indexer or Mapped Type  | 
3655  |  |       // We can have  | 
3656  |  |       // [ Identifier : TypeAnnotation ]  | 
3657  |  |       //   ^  | 
3658  |  |       // or  | 
3659  |  |       // [ TypeAnnotation ]  | 
3660  |  |       //   ^  | 
3661  |  |       // or  | 
3662  |  |       // [ TypeParameter in TypeAnnotation ]  | 
3663  |  |       //   ^  | 
3664  |  |       // Because we cannot differentiate without looking ahead for the `in`  | 
3665  |  |       // or `:`, we call `parseTypeAnnotation`, check for the next token  | 
3666  |  |       // and then convert the TypeAnnotation to the appropriate node.  | 
3667  | 0  |       auto optLeft = parseTypeAnnotationBeforeColonFlow();  | 
3668  | 0  |       if (!optLeft)  | 
3669  | 0  |         return false;  | 
3670  | 0  |       ESTree::Node *left = *optLeft;  | 
3671  |  | 
  | 
3672  | 0  |       if (checkAndEat(TokenKind::rw_in, JSLexer::GrammarContext::Type)) { | 
3673  | 0  |         auto optProp = parseTypeMappedTypePropertyFlow(start, left, variance);  | 
3674  | 0  |         if (!optProp)  | 
3675  | 0  |           return false;  | 
3676  | 0  |         properties.push_back(**optProp);  | 
3677  | 0  |       } else { | 
3678  | 0  |         auto optIndexer =  | 
3679  | 0  |             parseTypeIndexerPropertyFlow(start, left, variance, isStatic);  | 
3680  | 0  |         if (!optIndexer)  | 
3681  | 0  |           return false;  | 
3682  | 0  |         indexers.push_back(**optIndexer);  | 
3683  | 0  |       }  | 
3684  |  |  | 
3685  | 0  |       if (proto) { | 
3686  | 0  |         error(startRange, "invalid 'proto' modifier");  | 
3687  | 0  |       }  | 
3688  | 0  |       if (isStatic && allowStaticProperty == AllowStaticProperty::No) { | 
3689  | 0  |         error(startRange, "invalid 'static' modifier");  | 
3690  | 0  |       }  | 
3691  | 0  |     }  | 
3692  | 0  |     return true;  | 
3693  | 0  |   }  | 
3694  |  |  | 
3695  | 0  |   ESTree::Node *key = nullptr;  | 
3696  |  | 
  | 
3697  | 0  |   if (check(TokenKind::less, TokenKind::l_paren)) { | 
3698  | 0  |     if ((isStatic && allowStaticProperty == AllowStaticProperty::No) ||  | 
3699  | 0  |         (proto && allowProtoProperty == AllowProtoProperty::No)) { | 
3700  | 0  |       key = setLocation(  | 
3701  | 0  |           startRange,  | 
3702  | 0  |           startRange,  | 
3703  | 0  |           new (context_) ESTree::IdentifierNode(  | 
3704  | 0  |               isStatic ? staticIdent_ : protoIdent_, nullptr, false));  | 
3705  | 0  |       isStatic = false;  | 
3706  | 0  |       proto = false;  | 
3707  | 0  |       if (variance) { | 
3708  | 0  |         error(variance->getSourceRange(), "Unexpected variance sigil");  | 
3709  | 0  |       }  | 
3710  | 0  |       auto optProp = parseMethodTypePropertyFlow(start, isStatic, key);  | 
3711  | 0  |       if (!optProp)  | 
3712  | 0  |         return false;  | 
3713  | 0  |       properties.push_back(**optProp);  | 
3714  | 0  |       return true;  | 
3715  | 0  |     }  | 
3716  | 0  |     if (variance != nullptr) { | 
3717  | 0  |       error(  | 
3718  | 0  |           variance->getSourceRange(),  | 
3719  | 0  |           "call property must not specify variance");  | 
3720  | 0  |     }  | 
3721  | 0  |     if (proto) { | 
3722  | 0  |       error(startRange, "invalid 'proto' modifier");  | 
3723  | 0  |     }  | 
3724  | 0  |     auto optCall = parseTypeCallPropertyFlow(start, isStatic);  | 
3725  | 0  |     if (!optCall)  | 
3726  | 0  |       return false;  | 
3727  | 0  |     callProperties.push_back(**optCall);  | 
3728  | 0  |     return true;  | 
3729  | 0  |   }  | 
3730  |  |  | 
3731  | 0  |   if ((isStatic || proto) && check(TokenKind::colon, TokenKind::question)) { | 
3732  | 0  |     if (variance) { | 
3733  | 0  |       error(variance->getSourceRange(), "Unexpected variance sigil");  | 
3734  | 0  |     }  | 
3735  | 0  |     key = setLocation(  | 
3736  | 0  |         startRange,  | 
3737  | 0  |         startRange,  | 
3738  | 0  |         new (context_) ESTree::IdentifierNode(  | 
3739  | 0  |             isStatic ? staticIdent_ : protoIdent_, nullptr, false));  | 
3740  | 0  |     isStatic = false;  | 
3741  | 0  |     proto = false;  | 
3742  | 0  |     auto optProp = parseTypePropertyFlow(start, variance, isStatic, proto, key);  | 
3743  | 0  |     if (!optProp)  | 
3744  | 0  |       return false;  | 
3745  | 0  |     properties.push_back(**optProp);  | 
3746  | 0  |     return true;  | 
3747  | 0  |   }  | 
3748  |  |  | 
3749  | 0  |   auto optKey = parsePropertyName();  | 
3750  | 0  |   if (!optKey)  | 
3751  | 0  |     return false;  | 
3752  | 0  |   key = *optKey;  | 
3753  |  | 
  | 
3754  | 0  |   if (check(TokenKind::less, TokenKind::l_paren)) { | 
3755  | 0  |     if (variance) { | 
3756  | 0  |       error(variance->getSourceRange(), "Unexpected variance sigil");  | 
3757  | 0  |     }  | 
3758  | 0  |     if (proto) { | 
3759  | 0  |       error(startRange, "invalid 'proto' modifier");  | 
3760  | 0  |     }  | 
3761  | 0  |     if (isStatic && allowStaticProperty == AllowStaticProperty::No) { | 
3762  | 0  |       error(startRange, "invalid 'static' modifier");  | 
3763  | 0  |     }  | 
3764  | 0  |     auto optProp = parseMethodTypePropertyFlow(start, isStatic, key);  | 
3765  | 0  |     if (!optProp)  | 
3766  | 0  |       return false;  | 
3767  | 0  |     properties.push_back(**optProp);  | 
3768  | 0  |     return true;  | 
3769  | 0  |   }  | 
3770  |  |  | 
3771  | 0  |   if (check(TokenKind::colon, TokenKind::question)) { | 
3772  | 0  |     if (proto && allowProtoProperty == AllowProtoProperty::No) { | 
3773  | 0  |       error(startRange, "invalid 'proto' modifier");  | 
3774  | 0  |     }  | 
3775  | 0  |     if (isStatic && allowStaticProperty == AllowStaticProperty::No) { | 
3776  | 0  |       error(startRange, "invalid 'static' modifier");  | 
3777  | 0  |     }  | 
3778  | 0  |     auto optProp = parseTypePropertyFlow(start, variance, isStatic, proto, key);  | 
3779  | 0  |     if (!optProp)  | 
3780  | 0  |       return false;  | 
3781  | 0  |     properties.push_back(**optProp);  | 
3782  | 0  |     return true;  | 
3783  | 0  |   }  | 
3784  |  |  | 
3785  | 0  |   if (auto *ident = dyn_cast<ESTree::IdentifierNode>(key)) { | 
3786  | 0  |     if (ident->_name == getIdent_ || ident->_name == setIdent_) { | 
3787  | 0  |       if (variance != nullptr) { | 
3788  | 0  |         error(  | 
3789  | 0  |             variance->getSourceRange(),  | 
3790  | 0  |             "accessor property must not specify variance");  | 
3791  | 0  |       }  | 
3792  | 0  |       if (proto) { | 
3793  | 0  |         error(startRange, "invalid 'proto' modifier");  | 
3794  | 0  |       }  | 
3795  | 0  |       if (isStatic && allowStaticProperty == AllowStaticProperty::No) { | 
3796  | 0  |         error(startRange, "invalid 'static' modifier");  | 
3797  | 0  |       }  | 
3798  | 0  |       auto optKey = parsePropertyName();  | 
3799  | 0  |       if (!optKey)  | 
3800  | 0  |         return false;  | 
3801  | 0  |       key = *optKey;  | 
3802  | 0  |       auto optGetSet = parseGetOrSetTypePropertyFlow(  | 
3803  | 0  |           start, isStatic, ident->_name == getIdent_, key);  | 
3804  | 0  |       if (!optGetSet)  | 
3805  | 0  |         return false;  | 
3806  | 0  |       properties.push_back(**optGetSet);  | 
3807  | 0  |       return true;  | 
3808  | 0  |     }  | 
3809  | 0  |   }  | 
3810  |  |  | 
3811  | 0  |   errorExpected(  | 
3812  | 0  |       {TokenKind::colon, TokenKind::question}, | 
3813  | 0  |       "in property type annotation",  | 
3814  | 0  |       "start of properties",  | 
3815  | 0  |       start);  | 
3816  | 0  |   return false;  | 
3817  | 0  | }  | 
3818  |  |  | 
3819  |  | Optional<ESTree::Node *> JSParserImpl::parseTypePropertyFlow(  | 
3820  |  |     SMLoc start,  | 
3821  |  |     ESTree::Node *variance,  | 
3822  |  |     bool isStatic,  | 
3823  |  |     bool proto,  | 
3824  | 0  |     ESTree::Node *key) { | 
3825  | 0  |   assert(check(TokenKind::colon, TokenKind::question));  | 
3826  |  |  | 
3827  | 0  |   bool optional =  | 
3828  | 0  |       checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type);  | 
3829  | 0  |   if (!eat(  | 
3830  | 0  |           TokenKind::colon,  | 
3831  | 0  |           JSLexer::GrammarContext::Type,  | 
3832  | 0  |           "in type property",  | 
3833  | 0  |           "start of property",  | 
3834  | 0  |           start))  | 
3835  | 0  |     return None;  | 
3836  |  |  | 
3837  | 0  |   auto optValue = parseTypeAnnotationFlow();  | 
3838  | 0  |   if (!optValue)  | 
3839  | 0  |     return None;  | 
3840  | 0  |   ESTree::Node *value = *optValue;  | 
3841  |  | 
  | 
3842  | 0  |   bool method = false;  | 
3843  | 0  |   UniqueString *kind = initIdent_;  | 
3844  |  | 
  | 
3845  | 0  |   return setLocation(  | 
3846  | 0  |       start,  | 
3847  | 0  |       getPrevTokenEndLoc(),  | 
3848  | 0  |       new (context_) ESTree::ObjectTypePropertyNode(  | 
3849  | 0  |           key, value, method, optional, isStatic, proto, variance, kind));  | 
3850  | 0  | }  | 
3851  |  |  | 
3852  |  | Optional<ESTree::Node *> JSParserImpl::parseMethodTypePropertyFlow(  | 
3853  |  |     SMLoc start,  | 
3854  |  |     bool isStatic,  | 
3855  | 0  |     ESTree::Node *key) { | 
3856  | 0  |   assert(check(TokenKind::less, TokenKind::l_paren));  | 
3857  |  |  | 
3858  | 0  |   ESTree::Node *typeParams = nullptr;  | 
3859  | 0  |   if (check(TokenKind::less)) { | 
3860  | 0  |     auto optTypeParams = parseTypeParamsFlow();  | 
3861  | 0  |     if (!optTypeParams)  | 
3862  | 0  |       return None;  | 
3863  | 0  |     typeParams = *optTypeParams;  | 
3864  | 0  |   }  | 
3865  |  |  | 
3866  | 0  |   auto optValue = parseMethodishTypeAnnotationFlow(start, typeParams);  | 
3867  | 0  |   if (!optValue)  | 
3868  | 0  |     return None;  | 
3869  | 0  |   ESTree::Node *value = *optValue;  | 
3870  |  | 
  | 
3871  | 0  |   bool method = true;  | 
3872  | 0  |   bool optional = false;  | 
3873  | 0  |   bool proto = false;  | 
3874  | 0  |   UniqueString *kind = initIdent_;  | 
3875  |  | 
  | 
3876  | 0  |   return setLocation(  | 
3877  | 0  |       start,  | 
3878  | 0  |       getPrevTokenEndLoc(),  | 
3879  | 0  |       new (context_) ESTree::ObjectTypePropertyNode(  | 
3880  | 0  |           key,  | 
3881  | 0  |           value,  | 
3882  | 0  |           method,  | 
3883  | 0  |           optional,  | 
3884  | 0  |           isStatic,  | 
3885  | 0  |           proto,  | 
3886  | 0  |           /* variance */ nullptr,  | 
3887  | 0  |           kind));  | 
3888  | 0  | }  | 
3889  |  |  | 
3890  |  | Optional<ESTree::Node *> JSParserImpl::parseGetOrSetTypePropertyFlow(  | 
3891  |  |     SMLoc start,  | 
3892  |  |     bool isStatic,  | 
3893  |  |     bool isGetter,  | 
3894  | 0  |     ESTree::Node *key) { | 
3895  | 0  |   auto optValue = parseMethodishTypeAnnotationFlow(start, nullptr);  | 
3896  | 0  |   if (!optValue)  | 
3897  | 0  |     return None;  | 
3898  |  |  | 
3899  | 0  |   ESTree::FunctionTypeAnnotationNode *value = *optValue;  | 
3900  | 0  |   bool method = false;  | 
3901  | 0  |   bool optional = false;  | 
3902  | 0  |   bool proto = false;  | 
3903  | 0  |   ESTree::Node *variance = nullptr;  | 
3904  | 0  |   UniqueString *kind = isGetter ? getIdent_ : setIdent_;  | 
3905  |  |  | 
3906  |  |   // Check the number of parameters, but we can continue parsing anyway.  | 
3907  | 0  |   if (isGetter) { | 
3908  | 0  |     if (value->_params.size() != 0) { | 
3909  | 0  |       error(value->getSourceRange(), "Getter must have 0 parameters");  | 
3910  | 0  |     }  | 
3911  | 0  |   } else { | 
3912  | 0  |     if (value->_params.size() != 1) { | 
3913  | 0  |       error(value->getSourceRange(), "Setter must have 1 parameter");  | 
3914  | 0  |     }  | 
3915  | 0  |   }  | 
3916  |  | 
  | 
3917  | 0  |   if (value->_this) { | 
3918  | 0  |     error(  | 
3919  | 0  |         value->_this->getSourceRange(),  | 
3920  | 0  |         "Accessors must not have 'this' annotations");  | 
3921  | 0  |   }  | 
3922  |  | 
  | 
3923  | 0  |   return setLocation(  | 
3924  | 0  |       start,  | 
3925  | 0  |       getPrevTokenEndLoc(),  | 
3926  | 0  |       new (context_) ESTree::ObjectTypePropertyNode(  | 
3927  | 0  |           key, value, method, optional, isStatic, proto, variance, kind));  | 
3928  | 0  | }  | 
3929  |  |  | 
3930  |  | Optional<ESTree::Node *> JSParserImpl::parseTypeMappedTypePropertyFlow(  | 
3931  |  |     SMLoc start,  | 
3932  |  |     ESTree::Node *left,  | 
3933  | 0  |     ESTree::Node *variance) { | 
3934  | 0  |   auto idOpt = reparseTypeAnnotationAsIdFlow(left);  | 
3935  | 0  |   if (!idOpt)  | 
3936  | 0  |     return None;  | 
3937  | 0  |   UniqueString *id = *idOpt;  | 
3938  | 0  |   ESTree::Node *keyTparam = setLocation(  | 
3939  | 0  |       left,  | 
3940  | 0  |       left,  | 
3941  | 0  |       new (context_) ESTree::TypeParameterNode(  | 
3942  | 0  |           id, false, nullptr, nullptr, nullptr, false));  | 
3943  |  | 
  | 
3944  | 0  |   auto optSourceType = parseTypeAnnotationFlow();  | 
3945  | 0  |   if (!optSourceType)  | 
3946  | 0  |     return None;  | 
3947  |  |  | 
3948  | 0  |   if (!eat(  | 
3949  | 0  |           TokenKind::r_square,  | 
3950  | 0  |           JSLexer::GrammarContext::Type,  | 
3951  | 0  |           "in mapped type",  | 
3952  | 0  |           "start of mapped type",  | 
3953  | 0  |           start))  | 
3954  | 0  |     return None;  | 
3955  |  |  | 
3956  | 0  |   UniqueString *optional = nullptr;  | 
3957  | 0  |   if (checkAndEat(TokenKind::plus, JSLexer::GrammarContext::Type)) { | 
3958  | 0  |     if (!eat(  | 
3959  | 0  |             TokenKind::question,  | 
3960  | 0  |             JSLexer::GrammarContext::Type,  | 
3961  | 0  |             "in mapped type",  | 
3962  | 0  |             "start of mapped type",  | 
3963  | 0  |             start))  | 
3964  | 0  |       return None;  | 
3965  |  |  | 
3966  | 0  |     optional = mappedTypePlusOptionalIdent_;  | 
3967  | 0  |   } else if (checkAndEat(TokenKind::minus, JSLexer::GrammarContext::Type)) { | 
3968  | 0  |     if (!eat(  | 
3969  | 0  |             TokenKind::question,  | 
3970  | 0  |             JSLexer::GrammarContext::Type,  | 
3971  | 0  |             "in mapped type",  | 
3972  | 0  |             "start of mapped type",  | 
3973  | 0  |             start))  | 
3974  | 0  |       return None;  | 
3975  |  |  | 
3976  | 0  |     optional = mappedTypeMinusOptionalIdent_;  | 
3977  | 0  |   } else if (checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type)) { | 
3978  | 0  |     optional = mappedTypeOptionalIdent_;  | 
3979  | 0  |   }  | 
3980  |  |  | 
3981  | 0  |   if (!eat(  | 
3982  | 0  |           TokenKind::colon,  | 
3983  | 0  |           JSLexer::GrammarContext::Type,  | 
3984  | 0  |           "in mapped type",  | 
3985  | 0  |           "start of mapped type",  | 
3986  | 0  |           start))  | 
3987  | 0  |     return None;  | 
3988  |  |  | 
3989  | 0  |   auto optPropType = parseTypeAnnotationFlow();  | 
3990  | 0  |   if (!optPropType)  | 
3991  | 0  |     return None;  | 
3992  |  |  | 
3993  | 0  |   return setLocation(  | 
3994  | 0  |       start,  | 
3995  | 0  |       getPrevTokenEndLoc(),  | 
3996  | 0  |       new (context_) ESTree::ObjectTypeMappedTypePropertyNode(  | 
3997  | 0  |           keyTparam, *optPropType, *optSourceType, variance, optional));  | 
3998  | 0  | }  | 
3999  |  |  | 
4000  |  | Optional<ESTree::Node *> JSParserImpl::parseTypeIndexerPropertyFlow(  | 
4001  |  |     SMLoc start,  | 
4002  |  |     ESTree::Node *left,  | 
4003  |  |     ESTree::Node *variance,  | 
4004  | 0  |     bool isStatic) { | 
4005  | 0  |   ESTree::IdentifierNode *id = nullptr;  | 
4006  | 0  |   ESTree::Node *key = nullptr;  | 
4007  |  | 
  | 
4008  | 0  |   if (checkAndEat(TokenKind::colon, JSLexer::GrammarContext::Type)) { | 
4009  | 0  |     auto optId = reparseTypeAnnotationAsIdentifierFlow(left);  | 
4010  | 0  |     if (!optId)  | 
4011  | 0  |       return None;  | 
4012  | 0  |     id = *optId;  | 
4013  | 0  |     auto optKey = parseTypeAnnotationFlow();  | 
4014  | 0  |     if (!optKey)  | 
4015  | 0  |       return None;  | 
4016  | 0  |     key = *optKey;  | 
4017  | 0  |   } else { | 
4018  | 0  |     key = left;  | 
4019  | 0  |   }  | 
4020  |  |  | 
4021  | 0  |   if (!eat(  | 
4022  | 0  |           TokenKind::r_square,  | 
4023  | 0  |           JSLexer::GrammarContext::Type,  | 
4024  | 0  |           "in indexer",  | 
4025  | 0  |           "start of indexer",  | 
4026  | 0  |           start))  | 
4027  | 0  |     return None;  | 
4028  |  |  | 
4029  | 0  |   if (!eat(  | 
4030  | 0  |           TokenKind::colon,  | 
4031  | 0  |           JSLexer::GrammarContext::Type,  | 
4032  | 0  |           "in indexer",  | 
4033  | 0  |           "start of indexer",  | 
4034  | 0  |           start))  | 
4035  | 0  |     return None;  | 
4036  |  |  | 
4037  | 0  |   auto optValue = parseTypeAnnotationFlow();  | 
4038  | 0  |   if (!optValue)  | 
4039  | 0  |     return None;  | 
4040  | 0  |   ESTree::Node *value = *optValue;  | 
4041  |  | 
  | 
4042  | 0  |   return setLocation(  | 
4043  | 0  |       start,  | 
4044  | 0  |       getPrevTokenEndLoc(),  | 
4045  | 0  |       new (context_)  | 
4046  | 0  |           ESTree::ObjectTypeIndexerNode(id, key, value, isStatic, variance));  | 
4047  | 0  | }  | 
4048  |  |  | 
4049  |  | Optional<ESTree::Node *> JSParserImpl::parseTypeCallPropertyFlow(  | 
4050  |  |     SMLoc start,  | 
4051  | 0  |     bool isStatic) { | 
4052  | 0  |   ESTree::Node *typeParams = nullptr;  | 
4053  | 0  |   if (check(TokenKind::less)) { | 
4054  | 0  |     auto optTypeParams = parseTypeParamsFlow();  | 
4055  | 0  |     if (!optTypeParams)  | 
4056  | 0  |       return None;  | 
4057  | 0  |     typeParams = *optTypeParams;  | 
4058  | 0  |   }  | 
4059  | 0  |   auto optValue = parseMethodishTypeAnnotationFlow(start, typeParams);  | 
4060  | 0  |   if (!optValue)  | 
4061  | 0  |     return None;  | 
4062  | 0  |   return setLocation(  | 
4063  | 0  |       start,  | 
4064  | 0  |       getPrevTokenEndLoc(),  | 
4065  | 0  |       new (context_) ESTree::ObjectTypeCallPropertyNode(*optValue, isStatic));  | 
4066  | 0  | }  | 
4067  |  |  | 
4068  | 0  | Optional<ESTree::Node *> JSParserImpl::parseTypeParamsFlow() { | 
4069  | 0  |   assert(check(TokenKind::less));  | 
4070  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
4071  |  | 
  | 
4072  | 0  |   ESTree::NodeList params{}; | 
4073  |  | 
  | 
4074  | 0  |   do { | 
4075  | 0  |     auto optType = parseTypeParamFlow();  | 
4076  | 0  |     if (!optType)  | 
4077  | 0  |       return None;  | 
4078  | 0  |     params.push_back(**optType);  | 
4079  |  | 
  | 
4080  | 0  |     if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))  | 
4081  | 0  |       break;  | 
4082  | 0  |   } while (!check(TokenKind::greater));  | 
4083  |  |  | 
4084  | 0  |   SMLoc end = tok_->getEndLoc();  | 
4085  | 0  |   if (!eat(  | 
4086  | 0  |           TokenKind::greater,  | 
4087  | 0  |           JSLexer::GrammarContext::Type,  | 
4088  | 0  |           "at end of type parameters",  | 
4089  | 0  |           "start of type parameters",  | 
4090  | 0  |           start))  | 
4091  | 0  |     return None;  | 
4092  |  |  | 
4093  | 0  |   return setLocation(  | 
4094  | 0  |       start,  | 
4095  | 0  |       end,  | 
4096  | 0  |       new (context_) ESTree::TypeParameterDeclarationNode(std::move(params)));  | 
4097  | 0  | }  | 
4098  |  |  | 
4099  | 0  | Optional<ESTree::Node *> JSParserImpl::parseTypeParamFlow() { | 
4100  | 0  |   SMLoc start = tok_->getStartLoc();  | 
4101  | 0  |   bool isConst = false;  | 
4102  | 0  |   ESTree::Node *variance = nullptr;  | 
4103  | 0  |   if (check(TokenKind::rw_const)) { | 
4104  | 0  |     isConst = true;  | 
4105  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
4106  | 0  |   }  | 
4107  |  | 
  | 
4108  | 0  |   if (check(TokenKind::plus, TokenKind::minus)) { | 
4109  | 0  |     variance = setLocation(  | 
4110  | 0  |         tok_,  | 
4111  | 0  |         tok_,  | 
4112  | 0  |         new (context_) ESTree::VarianceNode(  | 
4113  | 0  |             check(TokenKind::plus) ? plusIdent_ : minusIdent_));  | 
4114  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
4115  | 0  |   }  | 
4116  |  | 
  | 
4117  | 0  |   if (!need(TokenKind::identifier, "in type parameter", nullptr, {})) | 
4118  | 0  |     return None;  | 
4119  | 0  |   UniqueString *name = tok_->getIdentifier();  | 
4120  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
4121  |  | 
  | 
4122  | 0  |   ESTree::Node *bound = nullptr;  | 
4123  | 0  |   bool usesExtendsBound = false;  | 
4124  | 0  |   if (check(TokenKind::colon)) { | 
4125  | 0  |     SMLoc boundStart = advance(JSLexer::GrammarContext::Type).Start;  | 
4126  | 0  |     auto optType = parseTypeAnnotationFlow();  | 
4127  | 0  |     if (!optType)  | 
4128  | 0  |       return None;  | 
4129  | 0  |     bound = setLocation(  | 
4130  | 0  |         boundStart,  | 
4131  | 0  |         getPrevTokenEndLoc(),  | 
4132  | 0  |         new (context_) ESTree::TypeAnnotationNode(*optType));  | 
4133  | 0  |   } else if (check(TokenKind::rw_extends)) { | 
4134  | 0  |     usesExtendsBound = true;  | 
4135  | 0  |     SMLoc boundStart = advance(JSLexer::GrammarContext::Type).Start;  | 
4136  | 0  |     auto optType = parseTypeAnnotationFlow();  | 
4137  | 0  |     if (!optType)  | 
4138  | 0  |       return None;  | 
4139  | 0  |     bound = setLocation(  | 
4140  | 0  |         boundStart,  | 
4141  | 0  |         getPrevTokenEndLoc(),  | 
4142  | 0  |         new (context_) ESTree::TypeAnnotationNode(*optType));  | 
4143  | 0  |   }  | 
4144  |  |  | 
4145  | 0  |   ESTree::Node *initializer = nullptr;  | 
4146  | 0  |   if (checkAndEat(TokenKind::equal, JSLexer::GrammarContext::Type)) { | 
4147  | 0  |     auto optInit = parseTypeAnnotationFlow();  | 
4148  | 0  |     if (!optInit)  | 
4149  | 0  |       return None;  | 
4150  | 0  |     initializer = *optInit;  | 
4151  | 0  |   }  | 
4152  |  |  | 
4153  | 0  |   return setLocation(  | 
4154  | 0  |       start,  | 
4155  | 0  |       getPrevTokenEndLoc(),  | 
4156  | 0  |       new (context_) ESTree::TypeParameterNode(  | 
4157  | 0  |           name, isConst, bound, variance, initializer, usesExtendsBound));  | 
4158  | 0  | }  | 
4159  |  |  | 
4160  | 0  | Optional<ESTree::Node *> JSParserImpl::parseTypeArgsFlow() { | 
4161  | 0  |   assert(check(TokenKind::less));  | 
4162  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
4163  |  | 
  | 
4164  | 0  |   ESTree::NodeList params{}; | 
4165  |  | 
  | 
4166  | 0  |   while (!check(TokenKind::greater)) { | 
4167  | 0  |     auto optType = parseTypeAnnotationFlow();  | 
4168  | 0  |     if (!optType)  | 
4169  | 0  |       return None;  | 
4170  | 0  |     params.push_back(**optType);  | 
4171  |  | 
  | 
4172  | 0  |     if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))  | 
4173  | 0  |       break;  | 
4174  | 0  |   }  | 
4175  |  |  | 
4176  | 0  |   SMLoc end = tok_->getEndLoc();  | 
4177  | 0  |   if (!eat(  | 
4178  | 0  |           TokenKind::greater,  | 
4179  | 0  |           JSLexer::GrammarContext::Type,  | 
4180  | 0  |           "at end of type parameters",  | 
4181  | 0  |           "start of type parameters",  | 
4182  | 0  |           start))  | 
4183  | 0  |     return None;  | 
4184  |  |  | 
4185  | 0  |   return setLocation(  | 
4186  | 0  |       start,  | 
4187  | 0  |       end,  | 
4188  | 0  |       new (context_) ESTree::TypeParameterInstantiationNode(std::move(params)));  | 
4189  | 0  | }  | 
4190  |  |  | 
4191  |  | Optional<ESTree::FunctionTypeAnnotationNode *>  | 
4192  |  | JSParserImpl::parseMethodishTypeAnnotationFlow(  | 
4193  |  |     SMLoc start,  | 
4194  | 0  |     ESTree::Node *typeParams) { | 
4195  | 0  |   ESTree::NodeList params{}; | 
4196  | 0  |   ESTree::Node *thisConstraint = nullptr;  | 
4197  |  | 
  | 
4198  | 0  |   if (!need(TokenKind::l_paren, "at start of parameters", nullptr, {})) | 
4199  | 0  |     return None;  | 
4200  | 0  |   auto optRest =  | 
4201  | 0  |       parseFunctionTypeAnnotationParamsFlow(params, thisConstraint, false);  | 
4202  | 0  |   if (!optRest)  | 
4203  | 0  |     return None;  | 
4204  |  |  | 
4205  | 0  |   if (!eat(  | 
4206  | 0  |           TokenKind::colon,  | 
4207  | 0  |           JSLexer::GrammarContext::Type,  | 
4208  | 0  |           "in function type annotation",  | 
4209  | 0  |           "start of annotation",  | 
4210  | 0  |           start))  | 
4211  | 0  |     return None;  | 
4212  |  |  | 
4213  | 0  |   auto optReturn = parseReturnTypeAnnotationFlow();  | 
4214  | 0  |   if (!optReturn)  | 
4215  | 0  |     return None;  | 
4216  |  |  | 
4217  | 0  |   return setLocation(  | 
4218  | 0  |       start,  | 
4219  | 0  |       getPrevTokenEndLoc(),  | 
4220  | 0  |       new (context_) ESTree::FunctionTypeAnnotationNode(  | 
4221  | 0  |           std::move(params), thisConstraint, *optReturn, *optRest, typeParams));  | 
4222  | 0  | }  | 
4223  |  |  | 
4224  |  | Optional<ESTree::FunctionTypeParamNode *>  | 
4225  |  | JSParserImpl::parseFunctionTypeAnnotationParamsFlow(  | 
4226  |  |     ESTree::NodeList ¶ms,  | 
4227  |  |     ESTree::NodePtr &thisConstraint,  | 
4228  | 0  |     bool hook) { | 
4229  | 0  |   assert(check(TokenKind::l_paren));  | 
4230  | 0  |   SMLoc start = advance(JSLexer::GrammarContext::Type).Start;  | 
4231  |  | 
  | 
4232  | 0  |   ESTree::FunctionTypeParamNode *rest = nullptr;  | 
4233  | 0  |   thisConstraint = nullptr;  | 
4234  |  | 
  | 
4235  | 0  |   if (check(TokenKind::rw_this) && !hook) { | 
4236  | 0  |     OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
4237  | 0  |     if (optNext.hasValue() && *optNext == TokenKind::colon) { | 
4238  | 0  |       SMLoc thisStart = advance(JSLexer::GrammarContext::Type).Start;  | 
4239  | 0  |       advance(JSLexer::GrammarContext::Type);  | 
4240  | 0  |       auto optType = parseTypeAnnotationFlow();  | 
4241  | 0  |       if (!optType)  | 
4242  | 0  |         return None;  | 
4243  | 0  |       ESTree::Node *typeAnnotation = *optType;  | 
4244  |  | 
  | 
4245  | 0  |       thisConstraint = setLocation(  | 
4246  | 0  |           thisStart,  | 
4247  | 0  |           getPrevTokenEndLoc(),  | 
4248  | 0  |           new (context_) ESTree::FunctionTypeParamNode(  | 
4249  | 0  |               /* name */ nullptr, typeAnnotation, /* optional */ false));  | 
4250  | 0  |       checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);  | 
4251  | 0  |     } else if (optNext.hasValue() && *optNext == TokenKind::question) { | 
4252  | 0  |       error(tok_->getSourceRange(), "'this' constraint may not be optional");  | 
4253  | 0  |     }  | 
4254  | 0  |   }  | 
4255  |  |  | 
4256  | 0  |   while (!check(TokenKind::r_paren)) { | 
4257  | 0  |     bool isRest =  | 
4258  | 0  |         checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type);  | 
4259  |  | 
  | 
4260  | 0  |     auto optParam = hook ? parseHookTypeAnnotationParamFlow()  | 
4261  | 0  |                          : parseFunctionTypeAnnotationParamFlow();  | 
4262  | 0  |     if (!optParam)  | 
4263  | 0  |       return None;  | 
4264  |  |  | 
4265  | 0  |     if (isRest) { | 
4266  |  |       // Rest param must be the last param.  | 
4267  | 0  |       rest = *optParam;  | 
4268  | 0  |       checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);  | 
4269  | 0  |       break;  | 
4270  | 0  |     } else { | 
4271  | 0  |       params.push_back(**optParam);  | 
4272  | 0  |       if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type)) { | 
4273  | 0  |         break;  | 
4274  | 0  |       }  | 
4275  | 0  |     }  | 
4276  | 0  |   }  | 
4277  |  |  | 
4278  | 0  |   if (!eat(  | 
4279  | 0  |           TokenKind::r_paren,  | 
4280  | 0  |           JSLexer::GrammarContext::Type,  | 
4281  | 0  |           "at end of function annotation parameters",  | 
4282  | 0  |           "start of parameters",  | 
4283  | 0  |           start))  | 
4284  | 0  |     return None;  | 
4285  |  |  | 
4286  | 0  |   return rest;  | 
4287  | 0  | }  | 
4288  |  |  | 
4289  |  | Optional<ESTree::FunctionTypeParamNode *>  | 
4290  | 0  | JSParserImpl::parseHookTypeAnnotationParamFlow() { | 
4291  | 0  |   if (check(TokenKind::rw_this)) { | 
4292  | 0  |     OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
4293  | 0  |     if (optNext.hasValue() && *optNext == TokenKind::colon) { | 
4294  | 0  |       error(tok_->getSourceRange(), "hooks do not support 'this' constraints");  | 
4295  | 0  |     }  | 
4296  | 0  |   }  | 
4297  | 0  |   return parseFunctionTypeAnnotationParamFlow();  | 
4298  | 0  | }  | 
4299  |  |  | 
4300  |  | Optional<ESTree::FunctionTypeParamNode *>  | 
4301  | 0  | JSParserImpl::parseFunctionTypeAnnotationParamFlow() { | 
4302  | 0  |   SMLoc start = tok_->getStartLoc();  | 
4303  |  | 
  | 
4304  | 0  |   if (check(TokenKind::rw_this)) { | 
4305  | 0  |     OptValue<TokenKind> optNext = lexer_.lookahead1(None);  | 
4306  | 0  |     if (optNext.hasValue() && *optNext == TokenKind::colon) { | 
4307  | 0  |       error(  | 
4308  | 0  |           tok_->getSourceRange(),  | 
4309  | 0  |           "'this' constraint must be the first parameter");  | 
4310  | 0  |     }  | 
4311  | 0  |   }  | 
4312  |  | 
  | 
4313  | 0  |   auto optLeft = parseTypeAnnotationBeforeColonFlow();  | 
4314  | 0  |   if (!optLeft)  | 
4315  | 0  |     return None;  | 
4316  |  |  | 
4317  | 0  |   ESTree::Node *name = nullptr;  | 
4318  | 0  |   ESTree::Node *typeAnnotation = nullptr;  | 
4319  | 0  |   bool optional = false;  | 
4320  |  | 
  | 
4321  | 0  |   if (check(TokenKind::colon, TokenKind::question)) { | 
4322  |  |     // The node is actually supposed to be an identifier, not a TypeAnnotation.  | 
4323  | 0  |     auto optName = reparseTypeAnnotationAsIdentifierFlow(*optLeft);  | 
4324  | 0  |     if (!optName)  | 
4325  | 0  |       return None;  | 
4326  | 0  |     name = *optName;  | 
4327  | 0  |     optional = checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type);  | 
4328  | 0  |     if (!eat(  | 
4329  | 0  |             TokenKind::colon,  | 
4330  | 0  |             JSLexer::GrammarContext::Type,  | 
4331  | 0  |             "in function parameter type annotation",  | 
4332  | 0  |             "start of parameter",  | 
4333  | 0  |             start))  | 
4334  | 0  |       return None;  | 
4335  | 0  |     auto optType = parseTypeAnnotationFlow();  | 
4336  | 0  |     if (!optType)  | 
4337  | 0  |       return None;  | 
4338  | 0  |     typeAnnotation = *optType;  | 
4339  | 0  |   } else { | 
4340  | 0  |     typeAnnotation = *optLeft;  | 
4341  | 0  |   }  | 
4342  |  |  | 
4343  | 0  |   return setLocation(  | 
4344  | 0  |       start,  | 
4345  | 0  |       getPrevTokenEndLoc(),  | 
4346  | 0  |       new (context_)  | 
4347  | 0  |           ESTree::FunctionTypeParamNode(name, typeAnnotation, optional));  | 
4348  | 0  | }  | 
4349  |  |  | 
4350  |  | Optional<ESTree::GenericTypeAnnotationNode *>  | 
4351  | 0  | JSParserImpl::parseGenericTypeFlow() { | 
4352  | 0  |   assert(check(TokenKind::identifier) || tok_->isResWord());  | 
4353  | 0  |   SMLoc start = tok_->getStartLoc();  | 
4354  |  | 
  | 
4355  | 0  |   ESTree::Node *id = setLocation(  | 
4356  | 0  |       tok_,  | 
4357  | 0  |       tok_,  | 
4358  | 0  |       new (context_) ESTree::IdentifierNode(  | 
4359  | 0  |           tok_->getResWordOrIdentifier(), nullptr, false));  | 
4360  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
4361  |  | 
  | 
4362  | 0  |   while (checkAndEat(TokenKind::period, JSLexer::GrammarContext::Type)) { | 
4363  | 0  |     if (!check(TokenKind::identifier) && !tok_->isResWord()) { | 
4364  | 0  |       errorExpected(  | 
4365  | 0  |           TokenKind::identifier,  | 
4366  | 0  |           "in qualified generic type name",  | 
4367  | 0  |           "start of type name",  | 
4368  | 0  |           start);  | 
4369  | 0  |       return None;  | 
4370  | 0  |     }  | 
4371  | 0  |     ESTree::Node *next = setLocation(  | 
4372  | 0  |         tok_,  | 
4373  | 0  |         tok_,  | 
4374  | 0  |         new (context_) ESTree::IdentifierNode(  | 
4375  | 0  |             tok_->getResWordOrIdentifier(), nullptr, false));  | 
4376  | 0  |     advance(JSLexer::GrammarContext::Type);  | 
4377  | 0  |     id = setLocation(  | 
4378  | 0  |         id, next, new (context_) ESTree::QualifiedTypeIdentifierNode(id, next));  | 
4379  | 0  |   }  | 
4380  |  |  | 
4381  | 0  |   ESTree::Node *typeParams = nullptr;  | 
4382  | 0  |   if (check(TokenKind::less)) { | 
4383  | 0  |     auto optTypeParams = parseTypeArgsFlow();  | 
4384  | 0  |     if (!optTypeParams)  | 
4385  | 0  |       return None;  | 
4386  | 0  |     typeParams = *optTypeParams;  | 
4387  | 0  |   }  | 
4388  |  |  | 
4389  | 0  |   return setLocation(  | 
4390  | 0  |       start,  | 
4391  | 0  |       getPrevTokenEndLoc(),  | 
4392  | 0  |       new (context_) ESTree::GenericTypeAnnotationNode(id, typeParams));  | 
4393  | 0  | }  | 
4394  |  |  | 
4395  |  | Optional<ESTree::ClassImplementsNode *>  | 
4396  | 0  | JSParserImpl::parseClassImplementsFlow() { | 
4397  | 0  |   assert(check(TokenKind::identifier));  | 
4398  | 0  |   SMLoc start = tok_->getStartLoc();  | 
4399  |  | 
  | 
4400  | 0  |   ESTree::Node *id = setLocation(  | 
4401  | 0  |       tok_,  | 
4402  | 0  |       tok_,  | 
4403  | 0  |       new (context_)  | 
4404  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
4405  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
4406  |  | 
  | 
4407  | 0  |   ESTree::Node *typeParams = nullptr;  | 
4408  | 0  |   if (check(TokenKind::less)) { | 
4409  | 0  |     auto optTypeParams = parseTypeArgsFlow();  | 
4410  | 0  |     if (!optTypeParams)  | 
4411  | 0  |       return None;  | 
4412  | 0  |     typeParams = *optTypeParams;  | 
4413  | 0  |   }  | 
4414  |  |  | 
4415  | 0  |   return setLocation(  | 
4416  | 0  |       start,  | 
4417  | 0  |       getPrevTokenEndLoc(),  | 
4418  | 0  |       new (context_) ESTree::ClassImplementsNode(id, typeParams));  | 
4419  | 0  | }  | 
4420  |  |  | 
4421  | 0  | Optional<ESTree::Node *> JSParserImpl::parsePredicateFlow() { | 
4422  | 0  |   assert(check(checksIdent_));  | 
4423  | 0  |   SMRange checksRng = advance(JSLexer::GrammarContext::Type);  | 
4424  | 0  |   if (checkAndEat(TokenKind::l_paren, JSLexer::GrammarContext::AllowRegExp)) { | 
4425  | 0  |     auto optCond = parseConditionalExpression();  | 
4426  | 0  |     if (!optCond)  | 
4427  | 0  |       return None;  | 
4428  | 0  |     SMLoc end = tok_->getEndLoc();  | 
4429  | 0  |     if (!eat(  | 
4430  | 0  |             TokenKind::r_paren,  | 
4431  | 0  |             JSLexer::GrammarContext::Type,  | 
4432  | 0  |             "in declared predicate",  | 
4433  | 0  |             "start of predicate",  | 
4434  | 0  |             checksRng.Start))  | 
4435  | 0  |       return None;  | 
4436  | 0  |     return setLocation(  | 
4437  | 0  |         checksRng, end, new (context_) ESTree::DeclaredPredicateNode(*optCond));  | 
4438  | 0  |   }  | 
4439  | 0  |   return setLocation(  | 
4440  | 0  |       checksRng, checksRng, new (context_) ESTree::InferredPredicateNode());  | 
4441  | 0  | }  | 
4442  |  |  | 
4443  |  | Optional<UniqueString *> JSParserImpl::reparseTypeAnnotationAsIdFlow(  | 
4444  | 0  |     ESTree::Node *typeAnnotation) { | 
4445  | 0  |   UniqueString *id = nullptr;  | 
4446  | 0  |   if (isa<ESTree::AnyTypeAnnotationNode>(typeAnnotation)) { | 
4447  | 0  |     id = anyIdent_;  | 
4448  | 0  |   } else if (isa<ESTree::EmptyTypeAnnotationNode>(typeAnnotation)) { | 
4449  | 0  |     id = emptyIdent_;  | 
4450  | 0  |   } else if (isa<ESTree::BooleanTypeAnnotationNode>(typeAnnotation)) { | 
4451  | 0  |     id = booleanIdent_;  | 
4452  | 0  |   } else if (isa<ESTree::NumberTypeAnnotationNode>(typeAnnotation)) { | 
4453  | 0  |     id = numberIdent_;  | 
4454  | 0  |   } else if (isa<ESTree::StringTypeAnnotationNode>(typeAnnotation)) { | 
4455  | 0  |     id = stringIdent_;  | 
4456  | 0  |   } else if (isa<ESTree::SymbolTypeAnnotationNode>(typeAnnotation)) { | 
4457  | 0  |     id = symbolIdent_;  | 
4458  | 0  |   } else if (isa<ESTree::NullLiteralTypeAnnotationNode>(typeAnnotation)) { | 
4459  | 0  |     id = nullIdent_;  | 
4460  | 0  |   } else if (  | 
4461  | 0  |       auto *generic =  | 
4462  | 0  |           dyn_cast<ESTree::GenericTypeAnnotationNode>(typeAnnotation)) { | 
4463  | 0  |     if (!generic->_typeParameters) { | 
4464  | 0  |       if (auto *genericId = dyn_cast<ESTree::IdentifierNode>(generic->_id)) { | 
4465  | 0  |         id = genericId->_name;  | 
4466  | 0  |       }  | 
4467  | 0  |     }  | 
4468  | 0  |   }  | 
4469  |  | 
  | 
4470  | 0  |   if (!id) { | 
4471  | 0  |     error(typeAnnotation->getSourceRange(), "identifier expected");  | 
4472  | 0  |     return None;  | 
4473  | 0  |   }  | 
4474  |  |  | 
4475  | 0  |   return id;  | 
4476  | 0  | }  | 
4477  |  |  | 
4478  |  | Optional<ESTree::IdentifierNode *>  | 
4479  |  | JSParserImpl::reparseTypeAnnotationAsIdentifierFlow(  | 
4480  | 0  |     ESTree::Node *typeAnnotation) { | 
4481  | 0  |   auto idOpt = reparseTypeAnnotationAsIdFlow(typeAnnotation);  | 
4482  | 0  |   if (!idOpt)  | 
4483  | 0  |     return None;  | 
4484  | 0  |   UniqueString *id = *idOpt;  | 
4485  | 0  |   return setLocation(  | 
4486  | 0  |       typeAnnotation,  | 
4487  | 0  |       typeAnnotation,  | 
4488  | 0  |       new (context_) ESTree::IdentifierNode(id, nullptr, false));  | 
4489  | 0  | }  | 
4490  |  |  | 
4491  |  | Optional<ESTree::Node *> JSParserImpl::parseEnumDeclarationFlow(  | 
4492  |  |     SMLoc start,  | 
4493  | 0  |     bool declare) { | 
4494  | 0  |   assert(check(TokenKind::rw_enum));  | 
4495  | 0  |   advance();  | 
4496  |  | 
  | 
4497  | 0  |   if (!check(TokenKind::identifier)) { | 
4498  | 0  |     errorExpected(  | 
4499  | 0  |         TokenKind::identifier,  | 
4500  | 0  |         "in enum declaration",  | 
4501  | 0  |         "start of declaration",  | 
4502  | 0  |         start);  | 
4503  | 0  |     return None;  | 
4504  | 0  |   }  | 
4505  | 0  |   ESTree::Node *id = setLocation(  | 
4506  | 0  |       tok_,  | 
4507  | 0  |       tok_,  | 
4508  | 0  |       new (context_)  | 
4509  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
4510  | 0  |   advance(JSLexer::GrammarContext::Type);  | 
4511  |  | 
  | 
4512  | 0  |   OptValue<EnumKind> optKind = llvh::None;  | 
4513  | 0  |   Optional<SMLoc> explicitTypeStart = None;  | 
4514  | 0  |   if (check(ofIdent_)) { | 
4515  | 0  |     explicitTypeStart = advance().Start;  | 
4516  |  | 
  | 
4517  | 0  |     if (checkAndEat(stringIdent_)) { | 
4518  | 0  |       optKind = EnumKind::String;  | 
4519  | 0  |     } else if (checkAndEat(numberIdent_)) { | 
4520  | 0  |       optKind = EnumKind::Number;  | 
4521  | 0  |     } else if (checkAndEat(bigintIdent_)) { | 
4522  | 0  |       optKind = EnumKind::BigInt;  | 
4523  | 0  |     } else if (checkAndEat(booleanIdent_)) { | 
4524  | 0  |       optKind = EnumKind::Boolean;  | 
4525  | 0  |     } else if (checkAndEat(symbolIdent_)) { | 
4526  | 0  |       optKind = EnumKind::Symbol;  | 
4527  | 0  |     }  | 
4528  | 0  |   }  | 
4529  |  | 
  | 
4530  | 0  |   if (!need(  | 
4531  | 0  |           TokenKind::l_brace,  | 
4532  | 0  |           "in enum declaration",  | 
4533  | 0  |           "start of declaration",  | 
4534  | 0  |           start))  | 
4535  | 0  |     return None;  | 
4536  |  |  | 
4537  | 0  |   auto optBody = parseEnumBodyFlow(optKind, explicitTypeStart);  | 
4538  | 0  |   if (!optBody)  | 
4539  | 0  |     return None;  | 
4540  |  |  | 
4541  | 0  |   if (declare)  | 
4542  | 0  |     return setLocation(  | 
4543  | 0  |         start, *optBody, new (context_) ESTree::DeclareEnumNode(id, *optBody));  | 
4544  | 0  |   return setLocation(  | 
4545  | 0  |       start,  | 
4546  | 0  |       *optBody,  | 
4547  | 0  |       new (context_) ESTree::EnumDeclarationNode(id, *optBody));  | 
4548  | 0  | }  | 
4549  |  |  | 
4550  |  | Optional<ESTree::Node *> JSParserImpl::parseEnumBodyFlow(  | 
4551  |  |     OptValue<EnumKind> optKind,  | 
4552  | 0  |     Optional<SMLoc> explicitTypeStart) { | 
4553  | 0  |   assert(check(TokenKind::l_brace));  | 
4554  | 0  |   SMLoc start = advance().Start;  | 
4555  |  | 
  | 
4556  | 0  |   ESTree::NodeList members{}; | 
4557  | 0  |   bool hasUnknownMembers = false;  | 
4558  | 0  |   while (!check(TokenKind::r_brace)) { | 
4559  | 0  |     if (check(TokenKind::dotdotdot)) { | 
4560  | 0  |       SMLoc dotdotdotLoc = advance(JSLexer::GrammarContext::Type).Start;  | 
4561  | 0  |       if (!check(TokenKind::r_brace)) { | 
4562  | 0  |         error(  | 
4563  | 0  |             dotdotdotLoc,  | 
4564  | 0  |             "The `...` must come after all enum members. "  | 
4565  | 0  |             "Move it to the end of the enum body.");  | 
4566  | 0  |         return None;  | 
4567  | 0  |       }  | 
4568  | 0  |       hasUnknownMembers = true;  | 
4569  | 0  |       break;  | 
4570  | 0  |     }  | 
4571  | 0  |     if (!need(  | 
4572  | 0  |             TokenKind::identifier,  | 
4573  | 0  |             "in enum declaration",  | 
4574  | 0  |             "start of declaration",  | 
4575  | 0  |             start))  | 
4576  | 0  |       return None;  | 
4577  |  |  | 
4578  | 0  |     auto optMember = parseEnumMemberFlow();  | 
4579  | 0  |     if (!optMember)  | 
4580  | 0  |       return None;  | 
4581  | 0  |     ESTree::Node *member = *optMember;  | 
4582  | 0  |     OptValue<EnumKind> optMemberKind = getMemberEnumKindFlow(member);  | 
4583  |  | 
  | 
4584  | 0  |     if (optKind.hasValue()) { | 
4585  |  |       // We've already figured out the type of the enum, so ensure that the  | 
4586  |  |       // new member is compatible with this.  | 
4587  | 0  |       if (optMemberKind.hasValue()) { | 
4588  | 0  |         if (*optKind != *optMemberKind) { | 
4589  | 0  |           error(  | 
4590  | 0  |               member->getSourceRange(),  | 
4591  | 0  |               llvh::Twine("cannot use ") + enumKindStrFlow(*optMemberKind) + | 
4592  | 0  |                   " initializer in " + enumKindStrFlow(*optKind) + " enum");  | 
4593  | 0  |           sm_.note(start, "start of enum body", Subsystem::Parser);  | 
4594  | 0  |           return None;  | 
4595  | 0  |         }  | 
4596  | 0  |       }  | 
4597  | 0  |     } else { | 
4598  | 0  |       optKind = optMemberKind;  | 
4599  | 0  |     }  | 
4600  |  |  | 
4601  | 0  |     members.push_back(*member);  | 
4602  | 0  |     if (!checkAndEat(TokenKind::comma))  | 
4603  | 0  |       break;  | 
4604  | 0  |   }  | 
4605  |  |  | 
4606  | 0  |   if (!members.empty()) { | 
4607  |  |     // Ensure that enum members use initializers consistently.  | 
4608  |  |     // This is vacuously true when `members` is empty, so just make sure  | 
4609  |  |     // all members use initializers iff the first member does.  | 
4610  | 0  |     bool usesInitializers =  | 
4611  | 0  |         !isa<ESTree::EnumDefaultedMemberNode>(members.front());  | 
4612  | 0  |     for (const ESTree::Node &member : members) { | 
4613  | 0  |       if (usesInitializers != !isa<ESTree::EnumDefaultedMemberNode>(member)) { | 
4614  | 0  |         error(  | 
4615  | 0  |             member.getSourceRange(),  | 
4616  | 0  |             "enum members need to consistently either all use initializers, "  | 
4617  | 0  |             "or use no initializers");  | 
4618  | 0  |         sm_.note(  | 
4619  | 0  |             members.front().getSourceRange(),  | 
4620  | 0  |             "first enum member",  | 
4621  | 0  |             Subsystem::Parser);  | 
4622  | 0  |         return None;  | 
4623  | 0  |       }  | 
4624  | 0  |     }  | 
4625  |  |  | 
4626  | 0  |     if (!usesInitializers) { | 
4627  |  |       // It's only legal to use defaulted members for string and symbol enums,  | 
4628  |  |       // because other kinds of enums can't infer values from names.  | 
4629  | 0  |       if (optKind.hasValue() && *optKind != EnumKind::String &&  | 
4630  | 0  |           *optKind != EnumKind::Symbol) { | 
4631  | 0  |         error(start, "number and boolean enums must use initializers");  | 
4632  | 0  |         return None;  | 
4633  | 0  |       }  | 
4634  | 0  |     }  | 
4635  | 0  |   }  | 
4636  |  |  | 
4637  | 0  |   SMLoc end = tok_->getEndLoc();  | 
4638  | 0  |   if (!eat(  | 
4639  | 0  |           TokenKind::r_brace,  | 
4640  | 0  |           JSLexer::GrammarContext::AllowRegExp,  | 
4641  | 0  |           "in enum body",  | 
4642  | 0  |           "start of body",  | 
4643  | 0  |           start))  | 
4644  | 0  |     return None;  | 
4645  |  |  | 
4646  | 0  |   bool hasExplicitType = explicitTypeStart.hasValue();  | 
4647  | 0  |   if (hasExplicitType) { | 
4648  | 0  |     start = *explicitTypeStart;  | 
4649  | 0  |   }  | 
4650  |  | 
  | 
4651  | 0  |   if (!optKind.hasValue()) { | 
4652  | 0  |     return setLocation(  | 
4653  | 0  |         start,  | 
4654  | 0  |         end,  | 
4655  | 0  |         new (context_) ESTree::EnumStringBodyNode(  | 
4656  | 0  |             std::move(members), hasExplicitType, hasUnknownMembers));  | 
4657  | 0  |   }  | 
4658  |  |  | 
4659  |  |   // There are different node kinds per enum kind.  | 
4660  | 0  |   switch (*optKind) { | 
4661  | 0  |     case EnumKind::String:  | 
4662  | 0  |       return setLocation(  | 
4663  | 0  |           start,  | 
4664  | 0  |           end,  | 
4665  | 0  |           new (context_) ESTree::EnumStringBodyNode(  | 
4666  | 0  |               std::move(members), hasExplicitType, hasUnknownMembers));  | 
4667  | 0  |     case EnumKind::Number:  | 
4668  | 0  |       return setLocation(  | 
4669  | 0  |           start,  | 
4670  | 0  |           end,  | 
4671  | 0  |           new (context_) ESTree::EnumNumberBodyNode(  | 
4672  | 0  |               std::move(members), hasExplicitType, hasUnknownMembers));  | 
4673  | 0  |     case EnumKind::BigInt:  | 
4674  | 0  |       return setLocation(  | 
4675  | 0  |           start,  | 
4676  | 0  |           end,  | 
4677  | 0  |           new (context_) ESTree::EnumBigIntBodyNode(  | 
4678  | 0  |               std::move(members), hasExplicitType, hasUnknownMembers));  | 
4679  | 0  |     case EnumKind::Boolean:  | 
4680  | 0  |       return setLocation(  | 
4681  | 0  |           start,  | 
4682  | 0  |           end,  | 
4683  | 0  |           new (context_) ESTree::EnumBooleanBodyNode(  | 
4684  | 0  |               std::move(members), hasExplicitType, hasUnknownMembers));  | 
4685  | 0  |     case EnumKind::Symbol:  | 
4686  | 0  |       assert(  | 
4687  | 0  |           hasExplicitType && "symbol enums can only be made via explicit type");  | 
4688  | 0  |       return setLocation(  | 
4689  | 0  |           start,  | 
4690  | 0  |           end,  | 
4691  | 0  |           new (context_) ESTree::EnumSymbolBodyNode(  | 
4692  | 0  |               std::move(members), hasUnknownMembers));  | 
4693  | 0  |   }  | 
4694  | 0  |   llvm_unreachable("No other kind of enum"); | 
4695  | 0  | }  | 
4696  |  |  | 
4697  | 0  | Optional<ESTree::Node *> JSParserImpl::parseEnumMemberFlow() { | 
4698  | 0  |   assert(check(TokenKind::identifier));  | 
4699  | 0  |   ESTree::Node *id = setLocation(  | 
4700  | 0  |       tok_,  | 
4701  | 0  |       tok_,  | 
4702  | 0  |       new (context_)  | 
4703  | 0  |           ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));  | 
4704  | 0  |   advance();  | 
4705  |  | 
  | 
4706  | 0  |   ESTree::Node *member = nullptr;  | 
4707  | 0  |   if (checkAndEat(TokenKind::equal)) { | 
4708  |  |     // Parse initializer.  | 
4709  | 0  |     if (check(TokenKind::rw_true, TokenKind::rw_false)) { | 
4710  | 0  |       ESTree::Node *init = setLocation(  | 
4711  | 0  |           tok_,  | 
4712  | 0  |           tok_,  | 
4713  | 0  |           new (context_) ESTree::BooleanLiteralNode(check(TokenKind::rw_true)));  | 
4714  | 0  |       member = setLocation(  | 
4715  | 0  |           id, tok_, new (context_) ESTree::EnumBooleanMemberNode(id, init));  | 
4716  | 0  |     } else if (check(TokenKind::string_literal)) { | 
4717  | 0  |       ESTree::Node *init = setLocation(  | 
4718  | 0  |           tok_,  | 
4719  | 0  |           tok_,  | 
4720  | 0  |           new (context_) ESTree::StringLiteralNode(tok_->getStringLiteral()));  | 
4721  | 0  |       member = setLocation(  | 
4722  | 0  |           id, tok_, new (context_) ESTree::EnumStringMemberNode(id, init));  | 
4723  | 0  |     } else if (check(TokenKind::minus)) { | 
4724  | 0  |       SMLoc start = tok_->getStartLoc();  | 
4725  | 0  |       advance();  | 
4726  | 0  |       if (check(TokenKind::numeric_literal)) { | 
4727  |  |         // Negate the literal.  | 
4728  | 0  |         double value = -tok_->getNumericLiteral();  | 
4729  | 0  |         ESTree::Node *init = setLocation(  | 
4730  | 0  |             start, tok_, new (context_) ESTree::NumericLiteralNode(value));  | 
4731  | 0  |         member = setLocation(  | 
4732  | 0  |             id, tok_, new (context_) ESTree::EnumNumberMemberNode(id, init));  | 
4733  | 0  |       } else { | 
4734  | 0  |         errorExpected(  | 
4735  | 0  |             TokenKind::numeric_literal,  | 
4736  | 0  |             "in negated enum member initializer",  | 
4737  | 0  |             "start of negated enum member",  | 
4738  | 0  |             id->getStartLoc());  | 
4739  | 0  |         return None;  | 
4740  | 0  |       }  | 
4741  | 0  |     } else if (check(TokenKind::numeric_literal)) { | 
4742  | 0  |       ESTree::Node *init = setLocation(  | 
4743  | 0  |           tok_,  | 
4744  | 0  |           tok_,  | 
4745  | 0  |           new (context_) ESTree::NumericLiteralNode(tok_->getNumericLiteral()));  | 
4746  | 0  |       member = setLocation(  | 
4747  | 0  |           id, tok_, new (context_) ESTree::EnumNumberMemberNode(id, init));  | 
4748  | 0  |     } else if (check(TokenKind::bigint_literal)) { | 
4749  | 0  |       ESTree::Node *init = setLocation(  | 
4750  | 0  |           tok_,  | 
4751  | 0  |           tok_,  | 
4752  | 0  |           new (context_) ESTree::BigIntLiteralNode(tok_->getBigIntLiteral()));  | 
4753  | 0  |       member = setLocation(  | 
4754  | 0  |           id, tok_, new (context_) ESTree::EnumBigIntMemberNode(id, init));  | 
4755  | 0  |     } else { | 
4756  | 0  |       errorExpected(  | 
4757  | 0  |           {TokenKind::rw_true, | 
4758  | 0  |            TokenKind::rw_false,  | 
4759  | 0  |            TokenKind::string_literal,  | 
4760  | 0  |            TokenKind::numeric_literal,  | 
4761  | 0  |            TokenKind::bigint_literal},  | 
4762  | 0  |           "in enum member initializer",  | 
4763  | 0  |           "start of enum member",  | 
4764  | 0  |           id->getStartLoc());  | 
4765  | 0  |       return None;  | 
4766  | 0  |     }  | 
4767  | 0  |     advance();  | 
4768  | 0  |   } else { | 
4769  | 0  |     member =  | 
4770  | 0  |         setLocation(id, id, new (context_) ESTree::EnumDefaultedMemberNode(id));  | 
4771  | 0  |   }  | 
4772  |  |  | 
4773  | 0  |   assert(member != nullptr && "member must have been parsed");  | 
4774  | 0  |   return member;  | 
4775  | 0  | }  | 
4776  |  |  | 
4777  |  | #endif  | 
4778  |  |  | 
4779  |  | } // namespace detail  | 
4780  |  | } // namespace parser  | 
4781  |  | } // namespace hermes  |