Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/lib/Parser/JSParserImpl-ts.cpp
Line
Count
Source
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 "hermes/AST/ESTreeJSONDumper.h"
11
#include "hermes/Support/PerfSection.h"
12
13
#include "llvh/Support/SaveAndRestore.h"
14
15
namespace hermes {
16
namespace parser {
17
namespace detail {
18
19
#if HERMES_PARSE_TS
20
21
Optional<ESTree::Node *> JSParserImpl::parseTypeAnnotationTS(
22
0
    Optional<SMLoc> wrappedStart) {
23
0
  llvh::SaveAndRestore<bool> saveParam(allowAnonFunctionType_, true);
24
25
0
  SMLoc start = tok_->getStartLoc();
26
0
  ESTree::Node *result = nullptr;
27
28
0
  if (check(TokenKind::identifier)) {
29
    // Need to check if this is a predicate, which requires backtracking.
30
0
    JSLexer::SavePoint savePoint{&lexer_};
31
0
    ESTree::Node *id = setLocation(
32
0
        tok_,
33
0
        tok_,
34
0
        new (context_)
35
0
            ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));
36
0
    advance(JSLexer::GrammarContext::Type);
37
0
    if (check(isIdent_)) {
38
0
      SMLoc wrappedStart = advance(JSLexer::GrammarContext::Type).Start;
39
0
      CHECK_RECURSION;
40
0
      auto optType = parseTypeAnnotationTS(wrappedStart);
41
0
      if (!optType)
42
0
        return None;
43
0
      result = setLocation(
44
0
          start,
45
0
          getPrevTokenEndLoc(),
46
0
          new (context_) ESTree::TSTypePredicateNode(id, *optType));
47
0
    } else {
48
0
      savePoint.restore();
49
0
    }
50
0
  }
51
52
0
  if (!result) {
53
0
    if (check(TokenKind::rw_new)) {
54
0
      advance(JSLexer::GrammarContext::Type);
55
0
      ESTree::Node *typeParams = nullptr;
56
0
      if (check(TokenKind::less)) {
57
0
        auto optTypeParams = parseTSTypeParameters();
58
0
        if (!optTypeParams)
59
0
          return None;
60
0
        typeParams = *optTypeParams;
61
0
      }
62
0
      if (!need(
63
0
              TokenKind::l_paren,
64
0
              "in constructor type",
65
0
              "start of type",
66
0
              start))
67
0
        return None;
68
0
      auto optResult = parseTSFunctionOrParenthesizedType(
69
0
          start, typeParams, IsConstructorType::Yes);
70
0
      if (!optResult)
71
0
        return None;
72
0
      result = *optResult;
73
0
    } else if (check(TokenKind::less)) {
74
0
      auto optTypeParams = parseTSTypeParameters();
75
0
      if (!optTypeParams)
76
0
        return None;
77
0
      if (!need(TokenKind::l_paren, "in function type", "start of type", start))
78
0
        return None;
79
0
      auto optResult = parseTSFunctionOrParenthesizedType(
80
0
          start, *optTypeParams, IsConstructorType::No);
81
0
      if (!optResult)
82
0
        return None;
83
0
      result = *optResult;
84
0
    } else {
85
0
      auto optResult = parseTSUnionType();
86
0
      if (!optResult)
87
0
        return None;
88
0
      result = *optResult;
89
0
    }
90
0
  }
91
92
0
  if (checkAndEat(TokenKind::rw_extends, JSLexer::GrammarContext::Type)) {
93
    // Parse a conditional type.
94
0
    auto optCheck = parseTypeAnnotationTS();
95
0
    if (!optCheck)
96
0
      return None;
97
0
    if (!eat(
98
0
            TokenKind::question,
99
0
            JSLexer::GrammarContext::Type,
100
0
            "in conditional type",
101
0
            "start of type",
102
0
            start))
103
0
      return None;
104
105
0
    auto optTrue = parseTypeAnnotationTS();
106
0
    if (!optTrue)
107
0
      return None;
108
0
    if (!eat(
109
0
            TokenKind::colon,
110
0
            JSLexer::GrammarContext::Type,
111
0
            "in conditional type",
112
0
            "start of type",
113
0
            start))
114
0
      return None;
115
116
0
    auto optFalse = parseTypeAnnotationTS();
117
0
    if (!optFalse)
118
0
      return None;
119
120
0
    result = setLocation(
121
0
        result,
122
0
        getPrevTokenEndLoc(),
123
0
        new (context_) ESTree::TSConditionalTypeNode(
124
0
            result, *optCheck, *optTrue, *optFalse));
125
0
  }
126
127
0
  if (wrappedStart)
128
0
    return setLocation(
129
0
        *wrappedStart,
130
0
        result,
131
0
        new (context_) ESTree::TSTypeAnnotationNode(result));
132
133
0
  return result;
134
0
}
135
136
0
Optional<ESTree::Node *> JSParserImpl::parseTSUnionType() {
137
0
  SMLoc start = tok_->getStartLoc();
138
0
  checkAndEat(TokenKind::pipe, JSLexer::GrammarContext::Type);
139
140
0
  auto optFirst = parseTSIntersectionType();
141
0
  if (!optFirst)
142
0
    return None;
143
144
0
  if (!check(TokenKind::pipe)) {
145
    // Done with the union, move on.
146
0
    return *optFirst;
147
0
  }
148
149
0
  ESTree::NodeList types{};
150
0
  types.push_back(**optFirst);
151
152
0
  while (checkAndEat(TokenKind::pipe, JSLexer::GrammarContext::Type)) {
153
0
    auto optInt = parseTSIntersectionType();
154
0
    if (!optInt)
155
0
      return None;
156
0
    types.push_back(**optInt);
157
0
  }
158
159
0
  return setLocation(
160
0
      start,
161
0
      getPrevTokenEndLoc(),
162
0
      new (context_) ESTree::TSUnionTypeNode(std::move(types)));
163
0
}
164
165
0
Optional<ESTree::Node *> JSParserImpl::parseTSIntersectionType() {
166
0
  SMLoc start = tok_->getStartLoc();
167
0
  checkAndEat(TokenKind::amp, JSLexer::GrammarContext::Type);
168
169
0
  auto optFirst = parseTSPostfixType();
170
0
  if (!optFirst)
171
0
    return None;
172
173
0
  if (!check(TokenKind::amp)) {
174
    // Done with the union, move on.
175
0
    return *optFirst;
176
0
  }
177
178
0
  ESTree::NodeList types{};
179
0
  types.push_back(**optFirst);
180
181
0
  while (checkAndEat(TokenKind::amp, JSLexer::GrammarContext::Type)) {
182
0
    auto optInt = parseTSPostfixType();
183
0
    if (!optInt)
184
0
      return None;
185
0
    types.push_back(**optInt);
186
0
  }
187
188
0
  return setLocation(
189
0
      start,
190
0
      getPrevTokenEndLoc(),
191
0
      new (context_) ESTree::TSIntersectionTypeNode(std::move(types)));
192
0
}
193
194
0
Optional<ESTree::Node *> JSParserImpl::parseTSTupleType() {
195
0
  assert(check(TokenKind::l_square));
196
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
197
198
0
  ESTree::NodeList types{};
199
200
0
  while (!check(TokenKind::r_square)) {
201
0
    auto optType = parseTypeAnnotationTS();
202
0
    if (!optType)
203
0
      return None;
204
0
    types.push_back(**optType);
205
206
0
    if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
207
0
      break;
208
0
  }
209
210
0
  if (!need(
211
0
          TokenKind::r_square,
212
0
          "at end of tuple type annotation",
213
0
          "start of tuple",
214
0
          start))
215
0
    return None;
216
217
0
  return setLocation(
218
0
      start,
219
0
      advance(JSLexer::GrammarContext::Type).End,
220
0
      new (context_) ESTree::TSTupleTypeNode(std::move(types)));
221
0
}
222
223
Optional<ESTree::Node *> JSParserImpl::parseTSFunctionOrParenthesizedType(
224
    SMLoc start,
225
    ESTree::Node *typeParams,
226
0
    IsConstructorType isConstructorType) {
227
0
  assert(check(TokenKind::l_paren));
228
  // This is either
229
  // ( Type )
230
  // ^
231
  // or
232
  // ( ParamList ) => Type
233
  // ^
234
  // so we use a similar approach to arrow function parameters by keeping track
235
  // and reparsing in certain cases.
236
0
  advance(JSLexer::GrammarContext::Type);
237
238
0
  bool isFunction = typeParams != nullptr;
239
0
  bool hasRest = false;
240
0
  ESTree::Node *type = nullptr;
241
0
  ESTree::NodeList params{};
242
243
0
  if (check(TokenKind::rw_this)) {
244
0
    OptValue<TokenKind> optNext = lexer_.lookahead1(None);
245
0
    if (optNext.hasValue() && *optNext == TokenKind::colon) {
246
0
      SMLoc thisStart = advance(JSLexer::GrammarContext::Type).Start;
247
0
      advance(JSLexer::GrammarContext::Type);
248
0
      CHECK_RECURSION;
249
0
      auto typeAnnotation = parseTypeAnnotationTS();
250
0
      if (!typeAnnotation)
251
0
        return None;
252
253
0
      params.push_back(*setLocation(
254
0
          thisStart,
255
0
          getPrevTokenEndLoc(),
256
0
          new (context_) ESTree::IdentifierNode(
257
0
              thisIdent_, *typeAnnotation, /* optional */ false)));
258
0
      checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);
259
0
    } else if (optNext.hasValue() && *optNext == TokenKind::question) {
260
0
      error(tok_->getSourceRange(), "'this' constraint may not be optional");
261
0
      return None;
262
0
    }
263
0
  }
264
265
0
  if (allowAnonFunctionType_ &&
266
0
      checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type)) {
267
0
    isFunction = true;
268
0
    hasRest = true;
269
    // Must be parameters, and this must be the last one.
270
0
    auto optName = parseTSFunctionTypeParam();
271
0
    if (!optName)
272
0
      return None;
273
0
    params.push_back(*setLocation(
274
0
        start,
275
0
        getPrevTokenEndLoc(),
276
0
        new (context_) ESTree::RestElementNode(*optName)));
277
0
  } else if (check(TokenKind::l_paren)) {
278
0
    auto optType = parseTypeAnnotationTS();
279
0
    if (!optType)
280
0
      return None;
281
0
    type = *optType;
282
0
  } else if (check(TokenKind::r_paren)) {
283
0
    isFunction = true;
284
    // ( )
285
    //   ^
286
    // No parameters, but this must be an empty param list.
287
0
  } else {
288
    // Not sure yet whether this is a param or simply a type.
289
0
    auto optParam = parseTSFunctionTypeParam();
290
0
    if (!optParam)
291
0
      return None;
292
0
    if (auto *param =
293
0
            llvh::dyn_cast<ESTree::TSParameterPropertyNode>(*optParam)) {
294
0
      if (param &&
295
0
          (param->_accessibility || param->_export || param->_readonly ||
296
0
           param->_static)) {
297
        // Must be a param.
298
0
        isFunction = true;
299
0
      }
300
0
      params.push_back(*param);
301
0
    } else if (
302
0
        auto *ident = llvh::dyn_cast<ESTree::IdentifierNode>(*optParam)) {
303
0
      params.push_back(*ident);
304
0
      type = ident->_typeAnnotation
305
0
          ? ident->_typeAnnotation
306
0
          : reparseIdentifierAsTSTypeAnnotation(ident);
307
0
      if (ident->_typeAnnotation || ident->_optional) {
308
        // Must be a param.
309
0
        isFunction = true;
310
0
      }
311
0
    } else {
312
0
      type = *optParam;
313
0
      params.push_back(**optParam);
314
0
    }
315
0
  }
316
317
  // If isFunction was already forced by something previously then we
318
  // have no choice but to attempt to parse as a function type annotation.
319
0
  if ((isFunction || allowAnonFunctionType_) &&
320
0
      checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type)) {
321
0
    isFunction = true;
322
0
    while (!check(TokenKind::r_paren)) {
323
0
      bool isRest = !hasRest &&
324
0
          checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type);
325
326
0
      auto optParam = parseTSFunctionTypeParam();
327
0
      if (!optParam)
328
0
        return None;
329
0
      if (isRest) {
330
0
        params.push_back(*setLocation(
331
0
            start,
332
0
            getPrevTokenEndLoc(),
333
0
            new (context_) ESTree::RestElementNode(*optParam)));
334
0
        checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);
335
0
        break;
336
0
      } else {
337
0
        params.push_back(**optParam);
338
0
      }
339
340
0
      if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
341
0
        break;
342
0
    }
343
0
  }
344
345
0
  if (!eat(
346
0
          TokenKind::r_paren,
347
0
          JSLexer::GrammarContext::Type,
348
0
          "at end of function type parameters",
349
0
          "start of parameters",
350
0
          start))
351
0
    return None;
352
353
0
  if (isFunction) {
354
0
    if (!eat(
355
0
            TokenKind::equalgreater,
356
0
            JSLexer::GrammarContext::Type,
357
0
            "in function type",
358
0
            "start of function",
359
0
            start))
360
0
      return None;
361
0
  } else if (allowAnonFunctionType_) {
362
0
    if (checkAndEat(TokenKind::equalgreater, JSLexer::GrammarContext::Type)) {
363
0
      isFunction = true;
364
0
    }
365
0
  }
366
367
0
  if (!isFunction) {
368
0
    type->incParens();
369
0
    return type;
370
0
  }
371
372
0
  auto optReturnType = parseTypeAnnotationTS();
373
0
  if (!optReturnType)
374
0
    return None;
375
376
0
  if (isConstructorType == IsConstructorType::Yes) {
377
0
    return setLocation(
378
0
        start,
379
0
        getPrevTokenEndLoc(),
380
0
        new (context_) ESTree::TSConstructorTypeNode(
381
0
            std::move(params), *optReturnType, typeParams));
382
0
  }
383
384
0
  return setLocation(
385
0
      start,
386
0
      getPrevTokenEndLoc(),
387
0
      new (context_) ESTree::TSFunctionTypeNode(
388
0
          std::move(params), *optReturnType, typeParams));
389
0
}
390
391
bool JSParserImpl::parseTSFunctionTypeParams(
392
    SMLoc start,
393
0
    ESTree::NodeList &params) {
394
0
  assert(check(TokenKind::l_paren));
395
396
0
  advance(JSLexer::GrammarContext::Type);
397
398
0
  while (!check(TokenKind::r_paren)) {
399
0
    auto optParam = parseTSFunctionTypeParam();
400
0
    if (!optParam)
401
0
      return false;
402
0
    params.push_back(**optParam);
403
404
0
    if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
405
0
      break;
406
0
  }
407
408
0
  if (!eat(
409
0
          TokenKind::r_paren,
410
0
          JSLexer::GrammarContext::Type,
411
0
          "at end of function type parameters",
412
0
          "start of parameters",
413
0
          start))
414
0
    return false;
415
416
0
  return true;
417
0
}
418
419
0
Optional<ESTree::Node *> JSParserImpl::parseTSFunctionTypeParam() {
420
0
  SMLoc start = tok_->getStartLoc();
421
422
0
  ESTree::NodeLabel accessibilityNode = nullptr;
423
0
  bool readonlyNode = false;
424
0
  bool staticNode = false;
425
0
  bool exportNode = false;
426
427
0
  while (checkN(
428
0
      TokenKind::identifier, TokenKind::rw_static, TokenKind::rw_export)) {
429
    // Check if this is a modifier.
430
0
    if (!staticNode && checkN(TokenKind::rw_static, staticIdent_)) {
431
0
      advance(JSLexer::GrammarContext::Type);
432
0
      if (checkN(
433
0
              TokenKind::identifier,
434
0
              TokenKind::rw_static,
435
0
              TokenKind::rw_export)) {
436
0
        staticNode = true;
437
0
        continue;
438
0
      }
439
0
    }
440
0
    if (!exportNode && checkN(TokenKind::rw_export)) {
441
0
      advance(JSLexer::GrammarContext::Type);
442
0
      if (checkN(
443
0
              TokenKind::identifier,
444
0
              TokenKind::rw_static,
445
0
              TokenKind::rw_export)) {
446
0
        exportNode = true;
447
0
        continue;
448
0
      }
449
0
    }
450
0
    if (!readonlyNode && checkN(readonlyIdent_)) {
451
0
      advance(JSLexer::GrammarContext::Type);
452
0
      if (checkN(
453
0
              TokenKind::identifier,
454
0
              TokenKind::rw_static,
455
0
              TokenKind::rw_export)) {
456
0
        readonlyNode = true;
457
0
        continue;
458
0
      }
459
0
    }
460
0
    if (!accessibilityNode) {
461
0
      if (checkN(TokenKind::rw_public, publicIdent_)) {
462
0
        advance(JSLexer::GrammarContext::Type);
463
0
        if (checkN(
464
0
                TokenKind::identifier,
465
0
                TokenKind::rw_static,
466
0
                TokenKind::rw_export)) {
467
0
          accessibilityNode = publicIdent_;
468
0
          continue;
469
0
        }
470
0
      }
471
0
      if (checkN(TokenKind::rw_private, privateIdent_)) {
472
0
        advance(JSLexer::GrammarContext::Type);
473
0
        if (checkN(
474
0
                TokenKind::identifier,
475
0
                TokenKind::rw_static,
476
0
                TokenKind::rw_export)) {
477
0
          accessibilityNode = privateIdent_;
478
0
          continue;
479
0
        }
480
0
      }
481
0
      if (checkN(TokenKind::rw_protected, protectedIdent_)) {
482
0
        advance(JSLexer::GrammarContext::Type);
483
0
        if (checkN(
484
0
                TokenKind::identifier,
485
0
                TokenKind::rw_static,
486
0
                TokenKind::rw_export)) {
487
0
          accessibilityNode = protectedIdent_;
488
0
          continue;
489
0
        }
490
0
      }
491
0
    }
492
493
    // Not a modifier.
494
0
    break;
495
0
  }
496
497
0
  auto optParam = parseBindingElement(Param{});
498
0
  if (!optParam)
499
0
    return None;
500
501
0
  if (accessibilityNode || readonlyNode || staticNode || exportNode) {
502
0
    return setLocation(
503
0
        start,
504
0
        getPrevTokenEndLoc(),
505
0
        new (context_) ESTree::TSParameterPropertyNode(
506
0
            *optParam,
507
0
            accessibilityNode,
508
0
            readonlyNode,
509
0
            staticNode,
510
0
            exportNode));
511
0
  }
512
513
0
  return *optParam;
514
0
}
515
516
0
Optional<ESTree::Node *> JSParserImpl::parseTSDeclaration() {
517
0
  assert(checkDeclaration());
518
519
0
  SMLoc start = tok_->getStartLoc();
520
521
0
  if (checkN(TokenKind::rw_interface, interfaceIdent_)) {
522
0
    return parseTSInterfaceDeclaration();
523
0
  }
524
525
0
  if (checkAndEat(typeIdent_, JSLexer::GrammarContext::Type)) {
526
0
    return parseTSTypeAliasDeclaration(start);
527
0
  }
528
529
0
  if (check(namespaceIdent_)) {
530
0
    return parseTSNamespaceDeclaration();
531
0
  }
532
533
0
  assert(check(TokenKind::rw_enum));
534
0
  return parseTSEnumDeclaration();
535
0
}
536
537
Optional<ESTree::Node *> JSParserImpl::parseTSTypeAliasDeclaration(
538
0
    SMLoc start) {
539
0
  if (!need(
540
0
          TokenKind::identifier, "in type alias", "start of type alias", start))
541
0
    return None;
542
543
0
  ESTree::Node *id = setLocation(
544
0
      tok_,
545
0
      tok_,
546
0
      new (context_)
547
0
          ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));
548
0
  advance(JSLexer::GrammarContext::Type);
549
550
0
  ESTree::Node *typeParams = nullptr;
551
0
  if (check(TokenKind::less)) {
552
0
    auto optTypeParams = parseTSTypeParameters();
553
0
    if (!optTypeParams)
554
0
      return None;
555
0
    typeParams = *optTypeParams;
556
0
  }
557
558
0
  if (!eat(
559
0
          TokenKind::equal,
560
0
          JSLexer::GrammarContext::Type,
561
0
          "in type alias",
562
0
          "start of type alias",
563
0
          start))
564
0
    return None;
565
566
0
  auto optRight = parseTypeAnnotationTS();
567
0
  if (!optRight)
568
0
    return None;
569
0
  ESTree::Node *right = *optRight;
570
571
0
  if (!eatSemi(true))
572
0
    return None;
573
574
0
  return setLocation(
575
0
      start,
576
0
      getPrevTokenEndLoc(),
577
0
      new (context_) ESTree::TSTypeAliasDeclarationNode(id, typeParams, right));
578
0
}
579
580
0
Optional<ESTree::Node *> JSParserImpl::parseTSInterfaceDeclaration() {
581
0
  assert(checkN(TokenKind::rw_interface, interfaceIdent_));
582
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
583
584
0
  if (!check(TokenKind::identifier) && !tok_->isResWord()) {
585
0
    errorExpected(
586
0
        TokenKind::identifier,
587
0
        "in interface declaration",
588
0
        "start of interface",
589
0
        start);
590
0
    return None;
591
0
  }
592
593
0
  ESTree::Node *id = setLocation(
594
0
      tok_,
595
0
      tok_,
596
0
      new (context_) ESTree::IdentifierNode(
597
0
          tok_->getResWordOrIdentifier(), nullptr, false));
598
0
  advance(JSLexer::GrammarContext::Type);
599
600
0
  ESTree::Node *typeParams = nullptr;
601
0
  if (check(TokenKind::less)) {
602
0
    auto optTypeParams = parseTSTypeParameters();
603
0
    if (!optTypeParams)
604
0
      return None;
605
0
    typeParams = *optTypeParams;
606
0
  }
607
608
0
  ESTree::NodeList extends{};
609
0
  if (checkAndEat(
610
0
          TokenKind::rw_extends, JSLexer::GrammarContext::AllowRegExp)) {
611
0
    do {
612
0
      auto optExpr = parseTSTypeReference();
613
0
      if (!optExpr)
614
0
        return None;
615
0
      ESTree::TSTypeReferenceNode *expr = *optExpr;
616
617
0
      ESTree::Node *typeArgs = nullptr;
618
0
      if (expr->_typeParameters) {
619
0
        typeArgs = expr->_typeParameters;
620
0
        expr->_typeParameters = nullptr;
621
0
      }
622
623
0
      extends.push_back(*setLocation(
624
0
          start,
625
0
          getPrevTokenEndLoc(),
626
0
          new (context_) ESTree::TSInterfaceHeritageNode(expr, typeArgs)));
627
628
0
      if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
629
0
        break;
630
0
    } while (!check(TokenKind::l_brace));
631
0
  }
632
633
0
  SMLoc bodyStart = tok_->getStartLoc();
634
635
0
  if (!eat(
636
0
          TokenKind::l_brace,
637
0
          JSLexer::GrammarContext::Type,
638
0
          "in interface declaration",
639
0
          "start of interface",
640
0
          start))
641
0
    return None;
642
643
0
  ESTree::NodeList members{};
644
645
0
  while (!check(TokenKind::r_brace)) {
646
0
    auto optMember = parseTSObjectTypeMember();
647
0
    if (!optMember)
648
0
      return None;
649
0
    members.push_back(**optMember);
650
651
0
    bool hasNext = check(TokenKind::comma, TokenKind::semi);
652
0
    if (hasNext) {
653
0
      advance(JSLexer::GrammarContext::Type);
654
0
    } else {
655
0
      break;
656
0
    }
657
0
  }
658
659
0
  if (!eat(
660
0
          TokenKind::r_brace,
661
0
          JSLexer::GrammarContext::Type,
662
0
          "at end of object type",
663
0
          "start of object type",
664
0
          start))
665
0
    return None;
666
667
0
  ESTree::Node *body = setLocation(
668
0
      bodyStart,
669
0
      getPrevTokenEndLoc(),
670
0
      new (context_) ESTree::TSInterfaceBodyNode(std::move(members)));
671
672
0
  return setLocation(
673
0
      start,
674
0
      getPrevTokenEndLoc(),
675
0
      new (context_) ESTree::TSInterfaceDeclarationNode(
676
0
          id, body, std::move(extends), typeParams));
677
0
}
678
679
0
Optional<ESTree::Node *> JSParserImpl::parseTSEnumDeclaration() {
680
0
  assert(check(TokenKind::rw_enum));
681
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
682
683
0
  auto optName = parseBindingIdentifier(Param{});
684
0
  if (!optName) {
685
0
    errorExpected(
686
0
        TokenKind::identifier, "in enum declaration", "start of enum", start);
687
0
    return None;
688
0
  }
689
0
  ESTree::Node *name = *optName;
690
691
0
  if (!eat(
692
0
          TokenKind::l_brace,
693
0
          JSLexer::GrammarContext::Type,
694
0
          "in enum declaration",
695
0
          "start of enum",
696
0
          start))
697
0
    return None;
698
699
0
  ESTree::NodeList members{};
700
701
0
  while (!check(TokenKind::r_brace)) {
702
0
    auto optMember = parseTSEnumMember();
703
0
    if (!optMember)
704
0
      return None;
705
0
    members.push_back(**optMember);
706
707
0
    if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
708
0
      break;
709
0
  }
710
711
0
  if (!eat(
712
0
          TokenKind::r_brace,
713
0
          JSLexer::GrammarContext::Type,
714
0
          "in enum declaration",
715
0
          "start of enum",
716
0
          start))
717
0
    return None;
718
719
0
  return setLocation(
720
0
      start,
721
0
      getPrevTokenEndLoc(),
722
0
      new (context_) ESTree::TSEnumDeclarationNode(name, std::move(members)));
723
0
}
724
725
0
Optional<ESTree::Node *> JSParserImpl::parseTSEnumMember() {
726
0
  SMLoc start = tok_->getStartLoc();
727
728
0
  auto optName = parseBindingIdentifier(Param{});
729
0
  if (!optName) {
730
0
    errorExpected(
731
0
        TokenKind::identifier, "in enum member", "start of member", start);
732
0
    return None;
733
0
  }
734
0
  ESTree::Node *name = *optName;
735
736
0
  ESTree::Node *init = nullptr;
737
0
  if (checkAndEat(TokenKind::equal)) {
738
0
    auto optExpr = parseAssignmentExpression();
739
0
    if (!optExpr)
740
0
      return None;
741
0
    init = *optExpr;
742
0
  }
743
744
0
  return setLocation(
745
0
      start,
746
0
      getPrevTokenEndLoc(),
747
0
      new (context_) ESTree::TSEnumMemberNode(name, init));
748
0
}
749
750
0
Optional<ESTree::Node *> JSParserImpl::parseTSNamespaceDeclaration() {
751
0
  assert(check(namespaceIdent_));
752
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
753
754
0
  auto optName = parseTSQualifiedName();
755
0
  if (!optName) {
756
0
    errorExpected(
757
0
        TokenKind::identifier,
758
0
        "in namespace declaration",
759
0
        "start of namespace",
760
0
        start);
761
0
    return None;
762
0
  }
763
0
  ESTree::Node *name = *optName;
764
765
0
  if (!eat(
766
0
          TokenKind::l_brace,
767
0
          JSLexer::GrammarContext::Type,
768
0
          "in namespace declaration",
769
0
          "start of namespace",
770
0
          start))
771
0
    return None;
772
773
0
  ESTree::NodeList members{};
774
775
0
  while (!check(TokenKind::r_brace)) {
776
0
    auto optMember =
777
0
        parseStatementListItem(Param{}, AllowImportExport::Yes, members);
778
0
    if (!optMember)
779
0
      return None;
780
0
  }
781
782
0
  if (!eat(
783
0
          TokenKind::r_brace,
784
0
          JSLexer::GrammarContext::Type,
785
0
          "in namespace declaration",
786
0
          "start of namespace",
787
0
          start))
788
0
    return None;
789
790
0
  ESTree::Node *body = setLocation(
791
0
      start,
792
0
      getPrevTokenEndLoc(),
793
0
      new (context_) ESTree::TSModuleBlockNode(std::move(members)));
794
795
0
  return setLocation(
796
0
      start,
797
0
      getPrevTokenEndLoc(),
798
0
      new (context_) ESTree::TSModuleMemberNode(name, body));
799
0
}
800
801
0
Optional<ESTree::Node *> JSParserImpl::parseTSTypeParameters() {
802
0
  assert(check(TokenKind::less));
803
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
804
805
0
  ESTree::NodeList params{};
806
807
0
  do {
808
0
    auto optType = parseTSTypeParameter();
809
0
    if (!optType)
810
0
      return None;
811
0
    params.push_back(**optType);
812
813
0
    if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
814
0
      break;
815
0
  } while (!check(TokenKind::greater));
816
817
0
  SMLoc end = tok_->getEndLoc();
818
0
  if (!eat(
819
0
          TokenKind::greater,
820
0
          JSLexer::GrammarContext::Type,
821
0
          "at end of type parameters",
822
0
          "start of type parameters",
823
0
          start))
824
0
    return None;
825
826
0
  return setLocation(
827
0
      start,
828
0
      end,
829
0
      new (context_) ESTree::TSTypeParameterDeclarationNode(std::move(params)));
830
0
}
831
832
0
Optional<ESTree::Node *> JSParserImpl::parseTSTypeParameter() {
833
0
  SMLoc start = tok_->getStartLoc();
834
835
0
  if (!need(TokenKind::identifier, "in type parameter", nullptr, {}))
836
0
    return None;
837
0
  ESTree::IdentifierNode *name = setLocation(
838
0
      tok_,
839
0
      tok_,
840
0
      new (context_)
841
0
          ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));
842
0
  advance(JSLexer::GrammarContext::Type);
843
844
0
  ESTree::Node *constraint = nullptr;
845
0
  if (checkAndEat(TokenKind::rw_extends, JSLexer::GrammarContext::Type)) {
846
0
    auto optType = parseTypeAnnotationTS();
847
0
    if (!optType)
848
0
      return None;
849
0
    constraint = *optType;
850
0
  }
851
852
0
  ESTree::Node *init = nullptr;
853
0
  if (checkAndEat(TokenKind::equal, JSLexer::GrammarContext::Type)) {
854
0
    auto optType = parseTypeAnnotationTS();
855
0
    if (!optType)
856
0
      return None;
857
0
    init = *optType;
858
0
  }
859
860
0
  return setLocation(
861
0
      start,
862
0
      getPrevTokenEndLoc(),
863
0
      new (context_) ESTree::TSTypeParameterNode(name, constraint, init));
864
0
}
865
866
0
Optional<ESTree::Node *> JSParserImpl::parseTSPostfixType() {
867
0
  SMLoc start = tok_->getStartLoc();
868
0
  auto optPrimary = parseTSPrimaryType();
869
0
  if (!optPrimary)
870
0
    return None;
871
872
0
  ESTree::Node *result = *optPrimary;
873
874
  // Parse any [] after the primary type.
875
0
  while (!lexer_.isNewLineBeforeCurrentToken() &&
876
0
         checkAndEat(TokenKind::l_square, JSLexer::GrammarContext::Type)) {
877
0
    if (check(TokenKind::r_square)) {
878
0
      result = setLocation(
879
0
          start,
880
0
          advance(JSLexer::GrammarContext::Type).End,
881
0
          new (context_) ESTree::TSArrayTypeNode(result));
882
0
    } else {
883
0
      auto optType = parseTypeAnnotationTS();
884
0
      if (!optType)
885
0
        return None;
886
0
      if (!eat(
887
0
              TokenKind::r_square,
888
0
              JSLexer::GrammarContext::Type,
889
0
              "in indexed access type",
890
0
              "start of type",
891
0
              start))
892
0
        return None;
893
0
      result = setLocation(
894
0
          start,
895
0
          getPrevTokenEndLoc(),
896
0
          new (context_) ESTree::TSIndexedAccessTypeNode(result, *optType));
897
0
    }
898
0
  }
899
900
0
  return result;
901
0
}
902
903
0
Optional<ESTree::Node *> JSParserImpl::parseTSPrimaryType() {
904
0
  CHECK_RECURSION;
905
0
  SMLoc start = tok_->getStartLoc();
906
0
  switch (tok_->getKind()) {
907
0
    case TokenKind::star:
908
0
      return setLocation(
909
0
          start,
910
0
          advance(JSLexer::GrammarContext::Type).End,
911
0
          new (context_) ESTree::ExistsTypeAnnotationNode());
912
0
    case TokenKind::l_paren:
913
0
      return parseTSFunctionOrParenthesizedType(
914
0
          start, nullptr, IsConstructorType::No);
915
0
    case TokenKind::l_brace:
916
0
      return parseTSObjectType();
917
0
    case TokenKind::rw_interface:
918
0
      return parseTSInterfaceDeclaration();
919
0
    case TokenKind::rw_typeof:
920
0
      return parseTSTypeQuery();
921
0
    case TokenKind::l_square:
922
0
      return parseTSTupleType();
923
0
    case TokenKind::rw_this:
924
0
      return setLocation(
925
0
          start,
926
0
          advance(JSLexer::GrammarContext::Type).End,
927
0
          new (context_) ESTree::TSThisTypeNode());
928
0
    case TokenKind::rw_static:
929
0
    case TokenKind::identifier:
930
0
      if (tok_->getResWordOrIdentifier() == anyIdent_) {
931
0
        return setLocation(
932
0
            start,
933
0
            advance(JSLexer::GrammarContext::Type).End,
934
0
            new (context_) ESTree::TSAnyKeywordNode());
935
0
      }
936
0
      if (tok_->getResWordOrIdentifier() == booleanIdent_) {
937
0
        return setLocation(
938
0
            start,
939
0
            advance(JSLexer::GrammarContext::Type).End,
940
0
            new (context_) ESTree::TSBooleanKeywordNode());
941
0
      }
942
0
      if (tok_->getResWordOrIdentifier() == numberIdent_) {
943
0
        return setLocation(
944
0
            start,
945
0
            advance(JSLexer::GrammarContext::Type).End,
946
0
            new (context_) ESTree::TSNumberKeywordNode());
947
0
      }
948
0
      if (tok_->getResWordOrIdentifier() == symbolIdent_) {
949
0
        return setLocation(
950
0
            start,
951
0
            advance(JSLexer::GrammarContext::Type).End,
952
0
            new (context_) ESTree::TSSymbolKeywordNode());
953
0
      }
954
0
      if (tok_->getResWordOrIdentifier() == stringIdent_) {
955
0
        return setLocation(
956
0
            start,
957
0
            advance(JSLexer::GrammarContext::Type).End,
958
0
            new (context_) ESTree::TSStringKeywordNode());
959
0
      }
960
0
      if (tok_->getResWordOrIdentifier() == bigintIdent_) {
961
0
        return setLocation(
962
0
            start,
963
0
            advance(JSLexer::GrammarContext::Type).End,
964
0
            new (context_) ESTree::TSBigIntKeywordNode());
965
0
      }
966
0
      if (tok_->getResWordOrIdentifier() == neverIdent_) {
967
0
        return setLocation(
968
0
            start,
969
0
            advance(JSLexer::GrammarContext::Type).End,
970
0
            new (context_) ESTree::TSNeverKeywordNode());
971
0
      }
972
0
      if (tok_->getResWordOrIdentifier() == undefinedIdent_) {
973
0
        return setLocation(
974
0
            start,
975
0
            advance(JSLexer::GrammarContext::Type).End,
976
0
            new (context_) ESTree::TSUndefinedKeywordNode());
977
0
      }
978
0
      if (tok_->getResWordOrIdentifier() == unknownIdent_) {
979
0
        return setLocation(
980
0
            start,
981
0
            advance(JSLexer::GrammarContext::Type).End,
982
0
            new (context_) ESTree::TSUnknownKeywordNode());
983
0
      }
984
985
0
      {
986
0
        auto optRef = parseTSTypeReference();
987
0
        if (!optRef)
988
0
          return None;
989
0
        return *optRef;
990
0
      }
991
992
0
    case TokenKind::rw_null: {
993
0
      SMLoc end = advance(JSLexer::GrammarContext::Type).End;
994
0
      return setLocation(
995
0
          start,
996
0
          end,
997
0
          new (context_) ESTree::TSLiteralTypeNode(setLocation(
998
0
              start, end, new (context_) ESTree::NullLiteralNode())));
999
0
    }
1000
1001
0
    case TokenKind::rw_void:
1002
0
      return setLocation(
1003
0
          start,
1004
0
          advance(JSLexer::GrammarContext::Type).End,
1005
0
          new (context_) ESTree::TSVoidKeywordNode());
1006
1007
0
    case TokenKind::string_literal: {
1008
0
      UniqueString *str = tok_->getStringLiteral();
1009
0
      SMLoc end = advance(JSLexer::GrammarContext::Type).End;
1010
0
      return setLocation(
1011
0
          start,
1012
0
          end,
1013
0
          new (context_) ESTree::TSLiteralTypeNode(setLocation(
1014
0
              start, end, new (context_) ESTree::StringLiteralNode(str))));
1015
0
    }
1016
1017
0
    case TokenKind::numeric_literal: {
1018
0
      double str = tok_->getNumericLiteral();
1019
0
      SMLoc end = advance(JSLexer::GrammarContext::Type).End;
1020
0
      return setLocation(
1021
0
          start,
1022
0
          end,
1023
0
          new (context_) ESTree::TSLiteralTypeNode(setLocation(
1024
0
              start, end, new (context_) ESTree::NumericLiteralNode(str))));
1025
0
    }
1026
1027
0
    case TokenKind::bigint_literal: {
1028
0
      UniqueString *raw = tok_->getBigIntLiteral();
1029
0
      SMLoc end = advance(JSLexer::GrammarContext::Type).End;
1030
0
      return setLocation(
1031
0
          start,
1032
0
          end,
1033
0
          new (context_) ESTree::TSLiteralTypeNode(setLocation(
1034
0
              start, end, new (context_) ESTree::BigIntLiteralNode(raw))));
1035
0
    }
1036
1037
0
    case TokenKind::rw_true:
1038
0
    case TokenKind::rw_false: {
1039
0
      bool value = check(TokenKind::rw_true);
1040
0
      SMLoc end = advance(JSLexer::GrammarContext::Type).End;
1041
0
      return setLocation(
1042
0
          start,
1043
0
          end,
1044
0
          new (context_) ESTree::TSLiteralTypeNode(setLocation(
1045
0
              start, end, new (context_) ESTree::BooleanLiteralNode(value))));
1046
0
    }
1047
1048
0
    default:
1049
0
      if (tok_->isResWord()) {
1050
0
        auto optRef = parseTSTypeReference();
1051
0
        if (!optRef)
1052
0
          return None;
1053
0
        return *optRef;
1054
0
      }
1055
0
      error(tok_->getStartLoc(), "unexpected token in type annotation");
1056
0
      return None;
1057
0
  }
1058
0
}
1059
1060
0
Optional<ESTree::TSTypeReferenceNode *> JSParserImpl::parseTSTypeReference() {
1061
0
  assert(check(TokenKind::identifier) || tok_->isResWord());
1062
0
  SMLoc start = tok_->getStartLoc();
1063
1064
0
  auto optName = parseTSQualifiedName();
1065
0
  if (!optName)
1066
0
    return None;
1067
0
  ESTree::Node *typeName = *optName;
1068
1069
0
  ESTree::Node *typeParams = nullptr;
1070
0
  if (check(TokenKind::less)) {
1071
0
    auto optTypeParams = parseTSTypeArguments();
1072
0
    if (!optTypeParams)
1073
0
      return None;
1074
0
    typeParams = *optTypeParams;
1075
0
  }
1076
1077
0
  return setLocation(
1078
0
      start,
1079
0
      getPrevTokenEndLoc(),
1080
0
      new (context_) ESTree::TSTypeReferenceNode(typeName, typeParams));
1081
0
}
1082
1083
0
Optional<ESTree::Node *> JSParserImpl::parseTSQualifiedName() {
1084
0
  SMLoc start = tok_->getStartLoc();
1085
0
  ESTree::Node *typeName = setLocation(
1086
0
      tok_,
1087
0
      tok_,
1088
0
      new (context_) ESTree::IdentifierNode(
1089
0
          tok_->getResWordOrIdentifier(), nullptr, false));
1090
0
  advance(JSLexer::GrammarContext::Type);
1091
1092
0
  while (checkAndEat(TokenKind::period, JSLexer::GrammarContext::Type)) {
1093
0
    if (!check(TokenKind::identifier) && !tok_->isResWord()) {
1094
0
      errorExpected(
1095
0
          TokenKind::identifier,
1096
0
          "in qualified type name",
1097
0
          "start of type name",
1098
0
          start);
1099
0
      return None;
1100
0
    }
1101
0
    ESTree::Node *right = setLocation(
1102
0
        tok_,
1103
0
        tok_,
1104
0
        new (context_) ESTree::IdentifierNode(
1105
0
            tok_->getResWordOrIdentifier(), nullptr, false));
1106
0
    advance(JSLexer::GrammarContext::Type);
1107
0
    typeName = setLocation(
1108
0
        typeName,
1109
0
        getPrevTokenEndLoc(),
1110
0
        new (context_) ESTree::TSQualifiedNameNode(typeName, right));
1111
0
  }
1112
1113
0
  return typeName;
1114
0
}
1115
1116
0
Optional<ESTree::Node *> JSParserImpl::parseTSTypeQuery() {
1117
0
  assert(check(TokenKind::rw_typeof));
1118
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
1119
1120
0
  if (!(tok_->isResWord() || check(TokenKind::identifier))) {
1121
0
    errorExpected(
1122
0
        TokenKind::identifier, "in type query", "start of type query", start);
1123
0
    return None;
1124
0
  }
1125
1126
0
  ESTree::Node *typeName = setLocation(
1127
0
      tok_,
1128
0
      tok_,
1129
0
      new (context_) ESTree::IdentifierNode(
1130
0
          tok_->getResWordOrIdentifier(), nullptr, false));
1131
0
  advance(JSLexer::GrammarContext::Type);
1132
1133
0
  while (checkAndEat(TokenKind::period, JSLexer::GrammarContext::Type)) {
1134
0
    if (!check(TokenKind::identifier) && !tok_->isResWord()) {
1135
0
      errorExpected(
1136
0
          TokenKind::identifier,
1137
0
          "in qualified type name",
1138
0
          "start of type name",
1139
0
          start);
1140
0
      return None;
1141
0
    }
1142
0
    ESTree::Node *right = setLocation(
1143
0
        tok_,
1144
0
        tok_,
1145
0
        new (context_) ESTree::IdentifierNode(
1146
0
            tok_->getResWordOrIdentifier(), nullptr, false));
1147
0
    advance(JSLexer::GrammarContext::Type);
1148
0
    typeName = setLocation(
1149
0
        typeName,
1150
0
        getPrevTokenEndLoc(),
1151
0
        new (context_) ESTree::TSQualifiedNameNode(typeName, right));
1152
0
  }
1153
1154
0
  return setLocation(
1155
0
      start,
1156
0
      getPrevTokenEndLoc(),
1157
0
      new (context_) ESTree::TSTypeQueryNode(typeName));
1158
0
}
1159
1160
0
Optional<ESTree::Node *> JSParserImpl::parseTSTypeArguments() {
1161
0
  assert(check(TokenKind::less));
1162
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
1163
1164
0
  ESTree::NodeList params{};
1165
1166
0
  while (!check(TokenKind::greater)) {
1167
0
    auto optType = parseTypeAnnotationTS();
1168
0
    if (!optType)
1169
0
      return None;
1170
0
    params.push_back(**optType);
1171
1172
0
    if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
1173
0
      break;
1174
0
  }
1175
1176
0
  SMLoc end = tok_->getEndLoc();
1177
0
  if (!eat(
1178
0
          TokenKind::greater,
1179
0
          JSLexer::GrammarContext::Type,
1180
0
          "at end of type parameters",
1181
0
          "start of type parameters",
1182
0
          start))
1183
0
    return None;
1184
1185
0
  return setLocation(
1186
0
      start,
1187
0
      end,
1188
0
      new (context_)
1189
0
          ESTree::TSTypeParameterInstantiationNode(std::move(params)));
1190
0
}
1191
1192
0
Optional<ESTree::Node *> JSParserImpl::parseTSObjectType() {
1193
0
  assert(check(TokenKind::l_brace));
1194
0
  SMLoc start = advance(JSLexer::GrammarContext::Type).Start;
1195
1196
0
  ESTree::NodeList members{};
1197
1198
0
  while (!check(TokenKind::r_brace)) {
1199
0
    auto optMember = parseTSObjectTypeMember();
1200
0
    if (!optMember)
1201
0
      return None;
1202
0
    members.push_back(**optMember);
1203
1204
0
    bool hasNext = check(TokenKind::comma, TokenKind::semi);
1205
0
    if (hasNext) {
1206
0
      advance(JSLexer::GrammarContext::Type);
1207
0
    } else {
1208
0
      break;
1209
0
    }
1210
0
  }
1211
1212
0
  if (!eat(
1213
0
          TokenKind::r_brace,
1214
0
          JSLexer::GrammarContext::Type,
1215
0
          "at end of object type",
1216
0
          "start of object type",
1217
0
          start))
1218
0
    return None;
1219
1220
0
  return setLocation(
1221
0
      start,
1222
0
      getPrevTokenEndLoc(),
1223
0
      new (context_) ESTree::TSTypeLiteralNode(std::move(members)));
1224
0
}
1225
1226
0
Optional<ESTree::Node *> JSParserImpl::parseTSObjectTypeMember() {
1227
0
  SMLoc start = tok_->getStartLoc();
1228
1229
0
  if (check(TokenKind::l_paren)) {
1230
0
    ESTree::NodeList params{};
1231
0
    if (!parseTSFunctionTypeParams(start, params))
1232
0
      return None;
1233
0
    ESTree::Node *returnType = nullptr;
1234
0
    if (checkAndEat(TokenKind::colon, JSLexer::GrammarContext::Type)) {
1235
0
      auto optType = parseTypeAnnotationTS();
1236
0
      if (!optType)
1237
0
        return None;
1238
0
      returnType = *optType;
1239
0
    }
1240
0
    return setLocation(
1241
0
        start,
1242
0
        getPrevTokenEndLoc(),
1243
0
        new (context_) ESTree::TSCallSignatureDeclarationNode(
1244
0
            std::move(params), returnType));
1245
0
  }
1246
1247
0
  bool optional = false;
1248
0
  bool computed = false;
1249
1250
  // TODO: Parse modifiers.
1251
0
  bool readonly = false;
1252
0
  bool isStatic = false;
1253
0
  bool isExport = false;
1254
1255
0
  ESTree::Node *key = nullptr;
1256
1257
  // TODO: Parse initializer.
1258
0
  ESTree::Node *init = nullptr;
1259
1260
0
  if (checkAndEat(TokenKind::l_square, JSLexer::GrammarContext::Type)) {
1261
0
    computed = true;
1262
1263
0
    if (check(TokenKind::identifier)) {
1264
0
      auto optNext = lexer_.lookahead1(llvh::None);
1265
0
      if (optNext.hasValue() && *optNext == TokenKind::colon) {
1266
        // Unambiguously an index signature.
1267
0
        return parseTSIndexSignature(start);
1268
0
      }
1269
0
    }
1270
1271
0
    auto optExpr = parseAssignmentExpression(ParamIn);
1272
0
    if (!optExpr)
1273
0
      return None;
1274
0
    key = *optExpr;
1275
1276
0
    if (!eat(
1277
0
            TokenKind::r_square,
1278
0
            JSLexer::GrammarContext::Type,
1279
0
            "at end of computed property type",
1280
0
            "start of property",
1281
0
            start))
1282
0
      return None;
1283
1284
0
    if (checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type)) {
1285
0
      optional = true;
1286
0
    }
1287
0
  } else {
1288
0
    if (!need(TokenKind::identifier, "in property", "start of property", start))
1289
0
      return None;
1290
0
    key = setLocation(
1291
0
        tok_,
1292
0
        tok_,
1293
0
        new (context_)
1294
0
            ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));
1295
0
    advance(JSLexer::GrammarContext::Type);
1296
1297
0
    if (checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type)) {
1298
0
      optional = true;
1299
0
    }
1300
0
  }
1301
1302
0
  if (check(TokenKind::colon)) {
1303
0
    SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
1304
0
    auto optType = parseTypeAnnotationTS(annotStart);
1305
0
    if (!optType)
1306
0
      return None;
1307
0
    return setLocation(
1308
0
        start,
1309
0
        getPrevTokenEndLoc(),
1310
0
        new (context_) ESTree::TSPropertySignatureNode(
1311
0
            key,
1312
0
            *optType,
1313
0
            init,
1314
0
            optional,
1315
0
            computed,
1316
0
            readonly,
1317
0
            isStatic,
1318
0
            isExport));
1319
0
  }
1320
1321
0
  if (check(TokenKind::l_paren)) {
1322
0
    ESTree::NodeList params{};
1323
0
    if (!parseTSFunctionTypeParams(start, params))
1324
0
      return None;
1325
1326
0
    ESTree::Node *returnType = nullptr;
1327
0
    if (check(TokenKind::colon)) {
1328
0
      SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
1329
0
      auto optType = parseTypeAnnotationTS(annotStart);
1330
0
      if (!optType)
1331
0
        return None;
1332
0
      returnType = *optType;
1333
0
    }
1334
1335
0
    return setLocation(
1336
0
        start,
1337
0
        getPrevTokenEndLoc(),
1338
0
        new (context_) ESTree::TSMethodSignatureNode(
1339
0
            key, std::move(params), returnType, computed));
1340
0
  }
1341
1342
0
  ESTree::Node *returnType = nullptr;
1343
0
  if (check(TokenKind::colon)) {
1344
0
    SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
1345
0
    auto optType = parseTypeAnnotationTS(annotStart);
1346
0
    if (!optType)
1347
0
      return None;
1348
0
    returnType = *optType;
1349
0
  }
1350
1351
0
  return setLocation(
1352
0
      start,
1353
0
      getPrevTokenEndLoc(),
1354
0
      new (context_) ESTree::TSPropertySignatureNode(
1355
0
          key,
1356
0
          returnType,
1357
0
          init,
1358
0
          optional,
1359
0
          computed,
1360
0
          readonly,
1361
0
          isStatic,
1362
0
          isExport));
1363
0
}
1364
1365
0
Optional<ESTree::Node *> JSParserImpl::parseTSIndexSignature(SMLoc start) {
1366
0
  ESTree::NodeList params{};
1367
1368
0
  while (!check(TokenKind::r_square)) {
1369
0
    auto optKey = parseBindingIdentifier(Param{});
1370
0
    if (!optKey) {
1371
0
      errorExpected(
1372
0
          TokenKind::identifier, "in property", "start of property", start);
1373
1374
0
      return None;
1375
0
    }
1376
0
    params.push_back(**optKey);
1377
1378
0
    if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
1379
0
      break;
1380
0
  }
1381
1382
0
  if (!eat(
1383
0
          TokenKind::r_square,
1384
0
          JSLexer::GrammarContext::Type,
1385
0
          "at end of indexer type annotation",
1386
0
          "start of indexer",
1387
0
          start))
1388
0
    return None;
1389
1390
0
  ESTree::Node *returnType = nullptr;
1391
0
  if (check(TokenKind::colon)) {
1392
0
    SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
1393
0
    auto optType = parseTypeAnnotationTS(annotStart);
1394
0
    if (!optType)
1395
0
      return None;
1396
0
    returnType = *optType;
1397
0
  }
1398
1399
0
  return setLocation(
1400
0
      start,
1401
0
      getPrevTokenEndLoc(),
1402
0
      new (context_)
1403
0
          ESTree::TSIndexSignatureNode(std::move(params), returnType));
1404
0
}
1405
1406
ESTree::Node *JSParserImpl::reparseIdentifierAsTSTypeAnnotation(
1407
0
    ESTree::IdentifierNode *ident) {
1408
0
  UniqueString *name = ident->_name;
1409
0
  if (name == anyIdent_) {
1410
0
    return setLocation(ident, ident, new (context_) ESTree::TSAnyKeywordNode());
1411
0
  }
1412
0
  if (name == booleanIdent_) {
1413
0
    return setLocation(
1414
0
        ident, ident, new (context_) ESTree::TSBooleanKeywordNode());
1415
0
  }
1416
0
  if (name == numberIdent_) {
1417
0
    return setLocation(
1418
0
        ident, ident, new (context_) ESTree::TSNumberKeywordNode());
1419
0
  }
1420
0
  if (name == symbolIdent_) {
1421
0
    return setLocation(
1422
0
        ident, ident, new (context_) ESTree::TSSymbolKeywordNode());
1423
0
  }
1424
0
  if (name == stringIdent_) {
1425
0
    return setLocation(
1426
0
        ident, ident, new (context_) ESTree::TSStringKeywordNode());
1427
0
  }
1428
1429
0
  return setLocation(
1430
0
      ident, ident, new (context_) ESTree::TSTypeReferenceNode(ident, {}));
1431
0
}
1432
1433
#endif
1434
1435
} // namespace detail
1436
} // namespace parser
1437
} // namespace hermes