private void ScanInterpolatedStringLiteralContents(ArrayBuilder <Interpolation> interpolations) { while (true) { if (IsAtEnd()) { // error: end of line before end of string return; } switch (lexer.TextWindow.PeekChar()) { case '"': if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"') { lexer.TextWindow.AdvanceChar(); // " lexer.TextWindow.AdvanceChar(); // " continue; } // found the end of the string return; case '}': var pos = lexer.TextWindow.Position; lexer.TextWindow.AdvanceChar(); // } // ensure any } characters are doubled up if (lexer.TextWindow.PeekChar() == '}') { lexer.TextWindow.AdvanceChar(); // } } else if (error == null) { error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}"); } continue; case '{': if (lexer.TextWindow.PeekChar(1) == '{') { lexer.TextWindow.AdvanceChar(); lexer.TextWindow.AdvanceChar(); } else { int openBracePosition = lexer.TextWindow.Position; lexer.TextWindow.AdvanceChar(); int colonPosition = 0; ScanInterpolatedStringLiteralHoleBalancedText('}', true, ref colonPosition); int closeBracePosition = lexer.TextWindow.Position; bool closeBraceMissing = false; if (lexer.TextWindow.PeekChar() == '}') { lexer.TextWindow.AdvanceChar(); } else { closeBraceMissing = true; if (error == null) { error = lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole); } } interpolations?.Add(new Interpolation(openBracePosition, colonPosition, closeBracePosition, closeBraceMissing)); } continue; case '\\': if (isVerbatim) { goto default; } var escapeStart = lexer.TextWindow.Position; char c2; char ch = lexer.ScanEscapeSequence(out c2); if ((ch == '{' || ch == '}') && error == null) { error = lexer.MakeError(escapeStart, lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch); } continue; default: // found some other character in the string portion lexer.TextWindow.AdvanceChar(); continue; } } }
private void ScanInterpolatedStringLiteralContents(ArrayBuilder <Interpolation>?interpolations) { while (true) { if (IsAtEnd()) { // error: end of line before end of string return; } switch (_lexer.TextWindow.PeekChar()) { case '"' when RecoveringFromRunawayLexing(): // When recovering from mismatched delimiters, we consume the next // quote character as the close quote for the interpolated string. In // practice this gets us out of trouble in scenarios we've encountered. // See, for example, https://github.com/dotnet/roslyn/issues/44789 return; case '"': if (_isVerbatim && _lexer.TextWindow.PeekChar(1) == '"') { _lexer.TextWindow.AdvanceChar(); // " _lexer.TextWindow.AdvanceChar(); // " continue; } // found the end of the string return; case '}': var pos = _lexer.TextWindow.Position; _lexer.TextWindow.AdvanceChar(); // } // ensure any } characters are doubled up if (_lexer.TextWindow.PeekChar() == '}') { _lexer.TextWindow.AdvanceChar(); // } } else { TrySetUnrecoverableError(_lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}")); } continue; case '{': if (_lexer.TextWindow.PeekChar(1) == '{') { _lexer.TextWindow.AdvanceChar(); _lexer.TextWindow.AdvanceChar(); } else { int openBracePosition = _lexer.TextWindow.Position; _lexer.TextWindow.AdvanceChar(); int colonPosition = 0; ScanInterpolatedStringLiteralHoleBalancedText('}', isHole: true, ref colonPosition); int closeBracePosition = _lexer.TextWindow.Position; bool closeBraceMissing = false; if (_lexer.TextWindow.PeekChar() == '}') { _lexer.TextWindow.AdvanceChar(); } else { closeBraceMissing = true; TrySetUnrecoverableError(_lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole)); } interpolations?.Add(new Interpolation(openBracePosition, colonPosition, closeBracePosition, closeBraceMissing)); } continue; case '\\': if (_isVerbatim) { goto default; } var escapeStart = _lexer.TextWindow.Position; char ch = _lexer.ScanEscapeSequence(surrogateCharacter: out _); if (ch == '{' || ch == '}') { TrySetUnrecoverableError(_lexer.MakeError(escapeStart, _lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch)); } continue; default: // found some other character in the string portion _lexer.TextWindow.AdvanceChar(); continue; } } }