@zzzen/pyright-internal 1.2.0-dev.20230514 → 1.2.0-dev.20230521

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/dist/analyzer/analyzerFileInfo.d.ts +1 -0
  2. package/dist/analyzer/analyzerFileInfo.js +4 -3
  3. package/dist/analyzer/analyzerFileInfo.js.map +1 -1
  4. package/dist/analyzer/backgroundAnalysisProgram.d.ts +17 -15
  5. package/dist/analyzer/backgroundAnalysisProgram.js +43 -53
  6. package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
  7. package/dist/analyzer/binder.d.ts +0 -2
  8. package/dist/analyzer/binder.js +2 -20
  9. package/dist/analyzer/binder.js.map +1 -1
  10. package/dist/analyzer/checker.d.ts +1 -1
  11. package/dist/analyzer/checker.js +61 -28
  12. package/dist/analyzer/checker.js.map +1 -1
  13. package/dist/analyzer/constructorTransform.js +5 -1
  14. package/dist/analyzer/constructorTransform.js.map +1 -1
  15. package/dist/analyzer/constructors.js +14 -12
  16. package/dist/analyzer/constructors.js.map +1 -1
  17. package/dist/analyzer/dataClasses.js +3 -0
  18. package/dist/analyzer/dataClasses.js.map +1 -1
  19. package/dist/analyzer/declarationUtils.js +1 -0
  20. package/dist/analyzer/declarationUtils.js.map +1 -1
  21. package/dist/analyzer/importResolver.d.ts +4 -4
  22. package/dist/analyzer/importResolver.js +46 -40
  23. package/dist/analyzer/importResolver.js.map +1 -1
  24. package/dist/analyzer/importResult.d.ts +2 -2
  25. package/dist/analyzer/importStatementUtils.js +2 -2
  26. package/dist/analyzer/importStatementUtils.js.map +1 -1
  27. package/dist/analyzer/packageTypeVerifier.js +1 -1
  28. package/dist/analyzer/packageTypeVerifier.js.map +1 -1
  29. package/dist/analyzer/parseTreeUtils.js +2 -34
  30. package/dist/analyzer/parseTreeUtils.js.map +1 -1
  31. package/dist/analyzer/parseTreeWalker.js +2 -2
  32. package/dist/analyzer/parseTreeWalker.js.map +1 -1
  33. package/dist/analyzer/patternMatching.js +1 -0
  34. package/dist/analyzer/patternMatching.js.map +1 -1
  35. package/dist/analyzer/program.d.ts +12 -18
  36. package/dist/analyzer/program.js +25 -12
  37. package/dist/analyzer/program.js.map +1 -1
  38. package/dist/analyzer/protocols.js +3 -1
  39. package/dist/analyzer/protocols.js.map +1 -1
  40. package/dist/analyzer/service.d.ts +4 -4
  41. package/dist/analyzer/service.js +21 -24
  42. package/dist/analyzer/service.js.map +1 -1
  43. package/dist/analyzer/sourceFile.d.ts +1 -6
  44. package/dist/analyzer/sourceFile.js +7 -26
  45. package/dist/analyzer/sourceFile.js.map +1 -1
  46. package/dist/analyzer/sourceMapper.js +1 -1
  47. package/dist/analyzer/sourceMapper.js.map +1 -1
  48. package/dist/analyzer/typeDocStringUtils.js +1 -1
  49. package/dist/analyzer/typeDocStringUtils.js.map +1 -1
  50. package/dist/analyzer/typeEvaluator.d.ts +2 -2
  51. package/dist/analyzer/typeEvaluator.js +134 -55
  52. package/dist/analyzer/typeEvaluator.js.map +1 -1
  53. package/dist/analyzer/typeEvaluatorTypes.d.ts +3 -2
  54. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  55. package/dist/analyzer/typeGuards.js +1 -0
  56. package/dist/analyzer/typeGuards.js.map +1 -1
  57. package/dist/analyzer/typePrinter.js +8 -1
  58. package/dist/analyzer/typePrinter.js.map +1 -1
  59. package/dist/analyzer/typeUtils.js +1 -1
  60. package/dist/analyzer/typeUtils.js.map +1 -1
  61. package/dist/analyzer/typeVarContext.js +2 -2
  62. package/dist/analyzer/typeVarContext.js.map +1 -1
  63. package/dist/analyzer/typedDicts.js +138 -41
  64. package/dist/analyzer/typedDicts.js.map +1 -1
  65. package/dist/analyzer/types.d.ts +7 -1
  66. package/dist/analyzer/types.js +19 -6
  67. package/dist/analyzer/types.js.map +1 -1
  68. package/dist/backgroundAnalysisBase.d.ts +25 -19
  69. package/dist/backgroundAnalysisBase.js +145 -115
  70. package/dist/backgroundAnalysisBase.js.map +1 -1
  71. package/dist/backgroundThreadBase.d.ts +1 -1
  72. package/dist/backgroundThreadBase.js +1 -1
  73. package/dist/backgroundThreadBase.js.map +1 -1
  74. package/dist/commands/dumpFileDebugInfoCommand.js +3 -3
  75. package/dist/commands/dumpFileDebugInfoCommand.js.map +1 -1
  76. package/dist/common/configOptions.js +1 -1
  77. package/dist/common/configOptions.js.map +1 -1
  78. package/dist/common/extensibility.d.ts +2 -4
  79. package/dist/common/extensibility.js.map +1 -1
  80. package/dist/common/textRange.js +1 -1
  81. package/dist/common/textRange.js.map +1 -1
  82. package/dist/common/workspaceEditUtils.d.ts +1 -1
  83. package/dist/common/workspaceEditUtils.js +5 -7
  84. package/dist/common/workspaceEditUtils.js.map +1 -1
  85. package/dist/languageServerBase.js +2 -2
  86. package/dist/languageServerBase.js.map +1 -1
  87. package/dist/languageService/autoImporter.d.ts +3 -3
  88. package/dist/languageService/autoImporter.js +3 -3
  89. package/dist/languageService/autoImporter.js.map +1 -1
  90. package/dist/languageService/callHierarchyProvider.js +3 -2
  91. package/dist/languageService/callHierarchyProvider.js.map +1 -1
  92. package/dist/languageService/completionProvider.d.ts +2 -2
  93. package/dist/languageService/completionProvider.js +37 -30
  94. package/dist/languageService/completionProvider.js.map +1 -1
  95. package/dist/languageService/documentSymbolCollector.js +9 -9
  96. package/dist/languageService/documentSymbolCollector.js.map +1 -1
  97. package/dist/languageService/referencesProvider.js +1 -1
  98. package/dist/languageService/referencesProvider.js.map +1 -1
  99. package/dist/languageService/signatureHelpProvider.js +1 -1
  100. package/dist/languageService/signatureHelpProvider.js.map +1 -1
  101. package/dist/languageService/symbolIndexer.d.ts +0 -8
  102. package/dist/languageService/symbolIndexer.js.map +1 -1
  103. package/dist/localization/localize.d.ts +22 -3
  104. package/dist/localization/localize.js +12 -3
  105. package/dist/localization/localize.js.map +1 -1
  106. package/dist/localization/package.nls.en-us.json +14 -5
  107. package/dist/parser/parseNodes.d.ts +8 -8
  108. package/dist/parser/parseNodes.js +20 -10
  109. package/dist/parser/parseNodes.js.map +1 -1
  110. package/dist/parser/parser.d.ts +3 -3
  111. package/dist/parser/parser.js +133 -159
  112. package/dist/parser/parser.js.map +1 -1
  113. package/dist/parser/stringTokenUtils.d.ts +3 -13
  114. package/dist/parser/stringTokenUtils.js +8 -181
  115. package/dist/parser/stringTokenUtils.js.map +1 -1
  116. package/dist/parser/tokenizer.d.ts +3 -0
  117. package/dist/parser/tokenizer.js +211 -24
  118. package/dist/parser/tokenizer.js.map +1 -1
  119. package/dist/parser/tokenizerTypes.d.ts +31 -1
  120. package/dist/parser/tokenizerTypes.js +51 -1
  121. package/dist/parser/tokenizerTypes.js.map +1 -1
  122. package/dist/readonlyAugmentedFileSystem.js +1 -1
  123. package/dist/readonlyAugmentedFileSystem.js.map +1 -1
  124. package/dist/tests/harness/fourslash/testLanguageService.js +1 -1
  125. package/dist/tests/harness/fourslash/testLanguageService.js.map +1 -1
  126. package/dist/tests/harness/fourslash/testState.js +2 -1
  127. package/dist/tests/harness/fourslash/testState.js.map +1 -1
  128. package/dist/tests/importResolver.test.js +3 -3
  129. package/dist/tests/importResolver.test.js.map +1 -1
  130. package/dist/tests/textRange.test.d.ts +1 -0
  131. package/dist/tests/textRange.test.js +45 -0
  132. package/dist/tests/textRange.test.js.map +1 -0
  133. package/dist/tests/tokenizer.test.js +272 -58
  134. package/dist/tests/tokenizer.test.js.map +1 -1
  135. package/dist/tests/typeEvaluator2.test.js +4 -0
  136. package/dist/tests/typeEvaluator2.test.js.map +1 -1
  137. package/dist/tests/typeEvaluator3.test.js +10 -0
  138. package/dist/tests/typeEvaluator3.test.js.map +1 -1
  139. package/dist/tests/typeEvaluator4.test.js +7 -2
  140. package/dist/tests/typeEvaluator4.test.js.map +1 -1
  141. package/dist/tests/typeEvaluator5.test.js +8 -0
  142. package/dist/tests/typeEvaluator5.test.js.map +1 -1
  143. package/dist/workspaceFactory.js +3 -5
  144. package/dist/workspaceFactory.js.map +1 -1
  145. package/package.json +1 -1
@@ -33,7 +33,7 @@ export interface ModuleImport {
33
33
  nameNode: ModuleNameNode;
34
34
  leadingDots: number;
35
35
  nameParts: string[];
36
- importedSymbols: string[] | undefined;
36
+ importedSymbols: Set<string> | undefined;
37
37
  }
38
38
  export interface ArgListResult {
39
39
  args: ArgumentNode[];
@@ -166,9 +166,9 @@ export declare class Parser {
166
166
  private _getTypeAnnotationCommentText;
167
167
  private _parseVariableTypeAnnotationComment;
168
168
  private _parseFunctionTypeAnnotationComment;
169
- private _parseFormatStringSegment;
169
+ private _parseFStringReplacementField;
170
+ private _parseFStringFormatString;
170
171
  private _parseFormatString;
171
- private _getFormatStringExpressionLength;
172
172
  private _createBinaryOperationNode;
173
173
  private _createUnaryOperationNode;
174
174
  private _parseStringList;
@@ -813,7 +813,7 @@ class Parser {
813
813
  (0, debug_1.assert)(stringList.nodeType === 48 /* StringList */);
814
814
  // Check for f-strings, which are not allowed.
815
815
  stringList.strings.forEach((stringAtom) => {
816
- if (stringAtom.token.flags & 64 /* Format */) {
816
+ if (stringAtom.nodeType === 27 /* FormatString */) {
817
817
  this._addError(localize_1.Localizer.Diagnostic.formatStringInPattern(), stringAtom);
818
818
  }
819
819
  });
@@ -1937,7 +1937,7 @@ class Parser {
1937
1937
  nameNode: importFromNode.module,
1938
1938
  leadingDots: importFromNode.module.leadingDots,
1939
1939
  nameParts: importFromNode.module.nameParts.map((p) => p.value),
1940
- importedSymbols: importFromNode.imports.map((imp) => imp.name.value),
1940
+ importedSymbols: new Set(importFromNode.imports.map((imp) => imp.name.value)),
1941
1941
  });
1942
1942
  let isTypingImport = false;
1943
1943
  if (importFromNode.module.nameParts.length === 1) {
@@ -2990,7 +2990,7 @@ class Parser {
2990
2990
  if (nextToken.type === 7 /* Identifier */) {
2991
2991
  return parseNodes_1.NameNode.create(this._getNextToken());
2992
2992
  }
2993
- if (nextToken.type === 5 /* String */) {
2993
+ if (nextToken.type === 5 /* String */ || nextToken.type === 24 /* FStringStart */) {
2994
2994
  return this._parseStringList();
2995
2995
  }
2996
2996
  if (nextToken.type === 22 /* Backtick */) {
@@ -3074,7 +3074,7 @@ class Parser {
3074
3074
  if (additionalStopTokens) {
3075
3075
  (0, collectionUtils_1.appendArray)(stopTokens, additionalStopTokens);
3076
3076
  }
3077
- // Using token that is not consumed by error node will mess up spans in parse node.
3077
+ // Using a token that is not included in the error node creates problems.
3078
3078
  // Sibling nodes in parse tree shouldn't overlap each other.
3079
3079
  const nextToken = this._peekToken();
3080
3080
  const initialRange = stopTokens.some((k) => nextToken.type === k)
@@ -3356,6 +3356,7 @@ class Parser {
3356
3356
  // augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
3357
3357
  // '<<=' | '>>=' | '**=' | '//=')
3358
3358
  _parseExpressionStatement() {
3359
+ var _a, _b;
3359
3360
  let leftExpr = this._parseTestOrStarListAsExpression(
3360
3361
  /* allowAssignmentExpression */ false,
3361
3362
  /* allowMultipleUnpack */ false, 2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedExpr());
@@ -3382,10 +3383,9 @@ class Parser {
3382
3383
  if (isTypeAliasDeclaration) {
3383
3384
  this._isParsingTypeAnnotation = true;
3384
3385
  }
3385
- const rightExpr = this._tryParseYieldExpression() ||
3386
- this._parseTestOrStarListAsExpression(
3387
- /* allowAssignmentExpression */ false,
3388
- /* allowMultipleUnpack */ true, 2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedAssignRightHandExpr());
3386
+ const rightExpr = (_a = this._tryParseYieldExpression()) !== null && _a !== void 0 ? _a : this._parseTestOrStarListAsExpression(
3387
+ /* allowAssignmentExpression */ false,
3388
+ /* allowMultipleUnpack */ true, 2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedAssignRightHandExpr());
3389
3389
  this._isParsingTypeAnnotation = wasParsingTypeAnnotation;
3390
3390
  return parseNodes_1.AssignmentNode.create(leftExpr, rightExpr);
3391
3391
  }
@@ -3395,8 +3395,7 @@ class Parser {
3395
3395
  }
3396
3396
  if (tokenizer_1.Tokenizer.isOperatorAssignment(this._peekOperatorType())) {
3397
3397
  const operatorToken = this._getNextToken();
3398
- const rightExpr = this._tryParseYieldExpression() ||
3399
- this._parseTestListAsExpression(2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedBinaryRightHandExpr());
3398
+ const rightExpr = (_b = this._tryParseYieldExpression()) !== null && _b !== void 0 ? _b : this._parseTestListAsExpression(2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedBinaryRightHandExpr());
3400
3399
  // Make a shallow copy of the dest expression but give it a new ID.
3401
3400
  const destExpr = Object.assign({}, leftExpr);
3402
3401
  destExpr.id = (0, parseNodes_1.getNextNodeId)();
@@ -3405,15 +3404,15 @@ class Parser {
3405
3404
  return leftExpr;
3406
3405
  }
3407
3406
  _parseChainAssignments(leftExpr) {
3407
+ var _a;
3408
3408
  // Make a list of assignment targets.
3409
3409
  const assignmentTargets = [leftExpr];
3410
3410
  let rightExpr;
3411
3411
  while (true) {
3412
3412
  rightExpr =
3413
- this._tryParseYieldExpression() ||
3414
- this._parseTestOrStarListAsExpression(
3415
- /* allowAssignmentExpression */ false,
3416
- /* allowMultipleUnpack */ true, 2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedAssignRightHandExpr());
3413
+ (_a = this._tryParseYieldExpression()) !== null && _a !== void 0 ? _a : this._parseTestOrStarListAsExpression(
3414
+ /* allowAssignmentExpression */ false,
3415
+ /* allowMultipleUnpack */ true, 2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedAssignRightHandExpr());
3417
3416
  if (rightExpr.nodeType === 0 /* Error */) {
3418
3417
  break;
3419
3418
  }
@@ -3517,7 +3516,7 @@ class Parser {
3517
3516
  if (stringToken.flags & 65536 /* Unterminated */) {
3518
3517
  this._addError(localize_1.Localizer.Diagnostic.stringUnterminated(), stringToken);
3519
3518
  }
3520
- if (unescapedResult.nonAsciiInBytes) {
3519
+ if (unescapedResult === null || unescapedResult === void 0 ? void 0 : unescapedResult.nonAsciiInBytes) {
3521
3520
  this._addError(localize_1.Localizer.Diagnostic.stringNonAsciiBytes(), stringToken);
3522
3521
  }
3523
3522
  if (stringToken.flags & 64 /* Format */) {
@@ -3535,7 +3534,7 @@ class Parser {
3535
3534
  _makeStringNode(stringToken) {
3536
3535
  const unescapedResult = StringTokenUtils.getUnescapedString(stringToken);
3537
3536
  this._reportStringTokenErrors(stringToken, unescapedResult);
3538
- return parseNodes_1.StringNode.create(stringToken, unescapedResult.value, unescapedResult.unescapeErrors.length > 0);
3537
+ return parseNodes_1.StringNode.create(stringToken, unescapedResult.value);
3539
3538
  }
3540
3539
  _getTypeAnnotationCommentText() {
3541
3540
  if (this._tokenIndex === 0) {
@@ -3601,154 +3600,123 @@ class Parser {
3601
3600
  functionAnnotation.parent = functionNode;
3602
3601
  (0, parseNodes_1.extendRange)(functionNode, functionAnnotation);
3603
3602
  }
3604
- _parseFormatStringSegment(stringToken, segment, segmentOffset, segmentLength) {
3605
- (0, debug_1.assert)(segment.isExpression);
3606
- const parser = new Parser();
3607
- const parseResults = parser.parseTextExpression(this._fileContents, stringToken.start + stringToken.prefixLength + stringToken.quoteMarkLength + segment.offset + segmentOffset, segmentLength, this._parseOptions, 0 /* Expression */,
3608
- /* initialParenDepth */ 1, this._typingSymbolAliases);
3609
- parseResults.diagnostics.forEach((diag) => {
3610
- const textRangeStart = (diag.range ? (0, positionUtils_1.convertPositionToOffset)(diag.range.start, parseResults.lines) : stringToken.start) ||
3611
- stringToken.start;
3612
- const textRangeEnd = (diag.range
3613
- ? ((0, positionUtils_1.convertPositionToOffset)(diag.range.end, parseResults.lines) || 0) + 1
3614
- : stringToken.start + stringToken.length) || stringToken.start + stringToken.length;
3615
- const textRange = { start: textRangeStart, length: textRangeEnd - textRangeStart };
3616
- this._addError(diag.message, textRange);
3617
- });
3618
- return parseResults.parseTree;
3603
+ _parseFStringReplacementField(fieldExpressions, middleTokens, formatExpressions, nestingDepth = 0) {
3604
+ var _a;
3605
+ let nextToken = this._getNextToken();
3606
+ // The caller should have already confirmed that the next token is an open brace.
3607
+ (0, debug_1.assert)(nextToken.type === 17 /* OpenCurlyBrace */);
3608
+ // Consume the expression.
3609
+ const expr = (_a = this._tryParseYieldExpression()) !== null && _a !== void 0 ? _a : this._parseTestOrStarListAsExpression(
3610
+ /* allowAssignmentExpression */ true,
3611
+ /* allowMultipleUnpack */ true, 2 /* MissingExpression */, () => localize_1.Localizer.Diagnostic.expectedExpr());
3612
+ fieldExpressions.push(expr);
3613
+ if (expr.nodeType === 0 /* Error */) {
3614
+ return false;
3615
+ }
3616
+ // Consume an optional "=" token after the expression.
3617
+ nextToken = this._peekToken();
3618
+ if (nextToken.type === 9 /* Operator */ &&
3619
+ nextToken.operatorType === 2 /* Assign */) {
3620
+ // This feature requires Python 3.8 or newer.
3621
+ if (this._parseOptions.pythonVersion < pythonVersion_1.PythonVersion.V3_8) {
3622
+ this._addError(localize_1.Localizer.Diagnostic.formatStringDebuggingIllegal(), nextToken);
3623
+ }
3624
+ this._getNextToken();
3625
+ nextToken = this._peekToken();
3626
+ }
3627
+ // Consume an optional !r, !s, or !a token.
3628
+ if (nextToken.type === 23 /* ExclamationMark */) {
3629
+ this._getNextToken();
3630
+ nextToken = this._peekToken();
3631
+ if (nextToken.type !== 7 /* Identifier */) {
3632
+ this._addError(localize_1.Localizer.Diagnostic.formatStringExpectedConversion(), nextToken);
3633
+ }
3634
+ else {
3635
+ this._getNextToken();
3636
+ nextToken = this._peekToken();
3637
+ }
3638
+ }
3639
+ if (nextToken.type === 10 /* Colon */) {
3640
+ this._getNextToken();
3641
+ this._parseFStringFormatString(fieldExpressions, middleTokens, formatExpressions, nestingDepth);
3642
+ nextToken = this._peekToken();
3643
+ }
3644
+ if (nextToken.type !== 18 /* CloseCurlyBrace */) {
3645
+ this._addError(localize_1.Localizer.Diagnostic.formatStringUnterminated(), nextToken);
3646
+ return false;
3647
+ }
3648
+ else {
3649
+ this._getNextToken();
3650
+ }
3651
+ // Indicate success.
3652
+ return true;
3619
3653
  }
3620
- _parseFormatString(stringToken) {
3621
- const unescapedResult = StringTokenUtils.getUnescapedString(stringToken);
3622
- this._reportStringTokenErrors(stringToken, unescapedResult);
3623
- const formatExpressions = [];
3624
- for (const segment of unescapedResult.formatStringSegments) {
3625
- if (segment.isExpression) {
3626
- // Determine if we need to truncate the expression because it
3627
- // contains formatting directives that start with a ! or :.
3628
- const segmentExprLength = this._getFormatStringExpressionLength(segment.value.trimEnd());
3629
- const parseTree = this._parseFormatStringSegment(stringToken, segment, 0, segmentExprLength);
3630
- if (parseTree) {
3631
- (0, debug_1.assert)(parseTree.nodeType !== 62 /* FunctionAnnotation */);
3632
- formatExpressions.push(parseTree);
3633
- }
3634
- // Look for additional expressions within the format directive.
3635
- const formatDirective = segment.value.substr(segmentExprLength);
3636
- let braceDepth = 0;
3637
- let startOfExprOffset = 0;
3638
- for (let i = 0; i < formatDirective.length; i++) {
3639
- if (formatDirective.charCodeAt(i) === 123 /* OpenBrace */) {
3640
- if (braceDepth === 0) {
3641
- startOfExprOffset = i + 1;
3642
- }
3643
- braceDepth++;
3644
- }
3645
- else if (formatDirective.charCodeAt(i) === 125 /* CloseBrace */) {
3646
- if (braceDepth > 0) {
3647
- braceDepth--;
3648
- if (braceDepth === 0) {
3649
- const formatSegmentLength = this._getFormatStringExpressionLength(segment.value.substr(segmentExprLength + startOfExprOffset, i - startOfExprOffset));
3650
- const parseTree = this._parseFormatStringSegment(stringToken, segment, segmentExprLength + startOfExprOffset, formatSegmentLength);
3651
- if (parseTree) {
3652
- (0, debug_1.assert)(parseTree.nodeType !== 62 /* FunctionAnnotation */);
3653
- formatExpressions.push(parseTree);
3654
- }
3655
- }
3656
- }
3657
- }
3654
+ _parseFStringFormatString(fieldExpressions, middleTokens, formatExpressions, nestingDepth) {
3655
+ while (true) {
3656
+ const nextToken = this._peekToken();
3657
+ if (nextToken.type === 18 /* CloseCurlyBrace */ || nextToken.type === 26 /* FStringEnd */) {
3658
+ break;
3659
+ }
3660
+ if (nextToken.type === 25 /* FStringMiddle */) {
3661
+ this._getNextToken();
3662
+ continue;
3663
+ }
3664
+ if (nextToken.type === 17 /* OpenCurlyBrace */) {
3665
+ // The Python interpreter reports an error at the point where the
3666
+ // nesting level exceeds 1. Don't report the error again for deeper nestings.
3667
+ if (nestingDepth === 2) {
3668
+ this._addError(localize_1.Localizer.Diagnostic.formatStringNestedFormatSpecifier(), nextToken);
3658
3669
  }
3670
+ this._parseFStringReplacementField(fieldExpressions, middleTokens, formatExpressions, nestingDepth + 1);
3671
+ continue;
3659
3672
  }
3673
+ break;
3660
3674
  }
3661
- return parseNodes_1.FormatStringNode.create(stringToken, unescapedResult.value, unescapedResult.unescapeErrors.length > 0, formatExpressions);
3662
3675
  }
3663
- _getFormatStringExpressionLength(segmentValue) {
3664
- let segmentExprLength = 0;
3665
- // PEP 498 says: Expressions cannot contain ':' or '!' outside of
3666
- // strings or parentheses, brackets, or braces. The exception is
3667
- // that the '!=' operator is allowed as a special case.
3668
- const quoteStack = [];
3669
- let braceCount = 0;
3670
- let parenCount = 0;
3671
- let bracketCount = 0;
3672
- let indexOfDebugEqual;
3673
- while (segmentExprLength < segmentValue.length) {
3674
- const curChar = segmentValue[segmentExprLength];
3675
- const ignoreSeparator = quoteStack.length > 0 || braceCount > 0 || parenCount > 0 || bracketCount > 0;
3676
- const inString = quoteStack.length > 0;
3677
- if (curChar === '=') {
3678
- indexOfDebugEqual = segmentExprLength;
3679
- }
3680
- else {
3681
- if (curChar === ':') {
3682
- if (!ignoreSeparator) {
3683
- break;
3684
- }
3676
+ _parseFormatString(startToken) {
3677
+ const middleTokens = [];
3678
+ const fieldExpressions = [];
3679
+ const formatExpressions = [];
3680
+ let endToken = undefined;
3681
+ // Consume middle tokens and expressions until we hit a "{" or "}" token.
3682
+ while (true) {
3683
+ const nextToken = this._peekToken();
3684
+ if (nextToken.type === 26 /* FStringEnd */) {
3685
+ endToken = nextToken;
3686
+ if ((endToken.flags & 65536 /* Unterminated */) !== 0) {
3687
+ this._addError(localize_1.Localizer.Diagnostic.stringUnterminated(), startToken);
3685
3688
  }
3686
- else if (curChar === '!') {
3687
- if (!ignoreSeparator) {
3688
- // Allow !=, as per PEP 498
3689
- if (segmentExprLength === segmentValue.length - 1 ||
3690
- segmentValue[segmentExprLength + 1] !== '=') {
3691
- break;
3689
+ this._getNextToken();
3690
+ break;
3691
+ }
3692
+ if (nextToken.type === 25 /* FStringMiddle */) {
3693
+ middleTokens.push(nextToken);
3694
+ this._getNextToken();
3695
+ continue;
3696
+ }
3697
+ if (nextToken.type === 17 /* OpenCurlyBrace */) {
3698
+ if (!this._parseFStringReplacementField(fieldExpressions, middleTokens, formatExpressions)) {
3699
+ // An error was reported. Try to recover the parse.
3700
+ if (this._consumeTokensUntilType([26 /* FStringEnd */, 2 /* NewLine */])) {
3701
+ if (this._peekToken().type === 26 /* FStringEnd */) {
3702
+ this._getNextToken();
3692
3703
  }
3693
3704
  }
3705
+ break;
3694
3706
  }
3695
- else if (curChar === "'" || curChar === '"') {
3696
- let quoteSequence = curChar;
3697
- if (segmentExprLength + 2 < segmentValue.length &&
3698
- segmentValue[segmentExprLength + 1] === curChar &&
3699
- segmentValue[segmentExprLength + 2] === curChar) {
3700
- quoteSequence = curChar + curChar + curChar;
3701
- segmentExprLength += 2;
3702
- }
3703
- if (quoteStack.length > 0 && quoteStack[quoteStack.length - 1] === quoteSequence) {
3704
- quoteStack.pop();
3705
- }
3706
- else if (quoteStack.length === 0) {
3707
- quoteStack.push(quoteSequence);
3708
- }
3709
- }
3710
- else if (curChar === '(') {
3711
- if (!inString) {
3712
- parenCount++;
3713
- }
3714
- }
3715
- else if (curChar === ')') {
3716
- if (!inString && parenCount > 0) {
3717
- parenCount--;
3718
- }
3719
- }
3720
- else if (curChar === '{') {
3721
- if (!inString) {
3722
- braceCount++;
3723
- }
3724
- }
3725
- else if (curChar === '}') {
3726
- if (!inString && braceCount > 0) {
3727
- braceCount--;
3728
- }
3729
- }
3730
- else if (curChar === '[') {
3731
- if (!inString) {
3732
- bracketCount++;
3733
- }
3734
- }
3735
- else if (curChar === ']') {
3736
- if (!inString && bracketCount > 0) {
3737
- bracketCount--;
3738
- }
3739
- }
3740
- if (curChar !== ' ') {
3741
- indexOfDebugEqual = undefined;
3742
- }
3707
+ continue;
3743
3708
  }
3744
- segmentExprLength++;
3745
- }
3746
- // Handle Python 3.8 f-string formatting expressions that
3747
- // end in an "=".
3748
- if (this._parseOptions.pythonVersion >= pythonVersion_1.PythonVersion.V3_8 && indexOfDebugEqual !== undefined) {
3749
- segmentExprLength = indexOfDebugEqual;
3709
+ // We've hit an error. Consume tokens until we find the end.
3710
+ if (this._consumeTokensUntilType([26 /* FStringEnd */])) {
3711
+ this._getNextToken();
3712
+ }
3713
+ this._addError(nextToken.type === 18 /* CloseCurlyBrace */
3714
+ ? localize_1.Localizer.Diagnostic.formatStringBrace()
3715
+ : localize_1.Localizer.Diagnostic.stringUnterminated(), nextToken);
3716
+ break;
3750
3717
  }
3751
- return segmentExprLength;
3718
+ this._reportStringTokenErrors(startToken);
3719
+ return parseNodes_1.FormatStringNode.create(startToken, endToken, middleTokens, fieldExpressions, formatExpressions);
3752
3720
  }
3753
3721
  _createBinaryOperationNode(leftExpression, rightExpression, operatorToken, operator) {
3754
3722
  // Determine if we're exceeding the max parse depth. If so, replace
@@ -3776,13 +3744,16 @@ class Parser {
3776
3744
  }
3777
3745
  _parseStringList() {
3778
3746
  const stringList = [];
3779
- while (this._peekTokenType() === 5 /* String */) {
3780
- const stringToken = this._getNextToken();
3781
- if (stringToken.flags & 64 /* Format */) {
3782
- stringList.push(this._parseFormatString(stringToken));
3747
+ while (true) {
3748
+ const nextToken = this._peekToken();
3749
+ if (nextToken.type === 5 /* String */) {
3750
+ stringList.push(this._makeStringNode(this._getNextToken()));
3751
+ }
3752
+ else if (nextToken.type === 24 /* FStringStart */) {
3753
+ stringList.push(this._parseFormatString(this._getNextToken()));
3783
3754
  }
3784
3755
  else {
3785
- stringList.push(this._makeStringNode(stringToken));
3756
+ break;
3786
3757
  }
3787
3758
  }
3788
3759
  const stringNode = parseNodes_1.StringListNode.create(stringList);
@@ -3793,7 +3764,7 @@ class Parser {
3793
3764
  if (stringNode.strings.length > 1) {
3794
3765
  this._addError(localize_1.Localizer.Diagnostic.annotationSpansStrings(), stringNode);
3795
3766
  }
3796
- else if (stringNode.strings[0].token.flags & 64 /* Format */) {
3767
+ else if (stringNode.strings[0].nodeType === 27 /* FormatString */) {
3797
3768
  this._addError(localize_1.Localizer.Diagnostic.annotationFormatString(), stringNode);
3798
3769
  }
3799
3770
  else {
@@ -3889,6 +3860,9 @@ class Parser {
3889
3860
  case 18 /* CloseCurlyBrace */:
3890
3861
  case 12 /* Comma */:
3891
3862
  case 10 /* Colon */:
3863
+ case 23 /* ExclamationMark */:
3864
+ case 25 /* FStringMiddle */:
3865
+ case 26 /* FStringEnd */:
3892
3866
  return true;
3893
3867
  }
3894
3868
  return false;