@@ -1862,10 +1862,22 @@ parseStringSegments(SmallVectorImpl<Lexer::StringSegment> &Segments,
1862
1862
SyntaxParsingContext ExprContext (SyntaxContext,
1863
1863
SyntaxKind::ExpressionSegment);
1864
1864
1865
+ unsigned DelimiterLen = EntireTok.getCustomDelimiterLen ();
1866
+ bool HasCustomDelimiter = DelimiterLen > 0 ;
1867
+
1865
1868
// Backslash is part of an expression segment.
1866
- Token BackSlash (tok::backslash,
1867
- CharSourceRange (Segment. Loc . getAdvancedLoc (- 1 ) , 1 ).str ());
1869
+ SourceLoc BackSlashLoc = Segment. Loc . getAdvancedLoc (- 1 - DelimiterLen);
1870
+ Token BackSlash (tok::backslash, CharSourceRange (BackSlashLoc , 1 ).str ());
1868
1871
ExprContext.addToken (BackSlash, EmptyTrivia, EmptyTrivia);
1872
+
1873
+ // Custom delimiter may be a part of an expression segment.
1874
+ if (HasCustomDelimiter) {
1875
+ SourceLoc DelimiterLoc = Segment.Loc .getAdvancedLoc (-DelimiterLen);
1876
+ Token Delimiter (tok::raw_string_delimiter,
1877
+ CharSourceRange (DelimiterLoc, DelimiterLen).str ());
1878
+ ExprContext.addToken (Delimiter, EmptyTrivia, EmptyTrivia);
1879
+ }
1880
+
1869
1881
// Create a temporary lexer that lexes from the body of the string.
1870
1882
LexerState BeginState =
1871
1883
L->getStateForBeginningOfTokenLoc (Segment.Loc );
@@ -1888,30 +1900,12 @@ parseStringSegments(SmallVectorImpl<Lexer::StringSegment> &Segments,
1888
1900
TokReceiver->registerTokenKindChange (Tok.getLoc (),
1889
1901
tok::string_interpolation_anchor);
1890
1902
1891
- SourceLoc lParen, rParen;
1892
- SmallVector<Expr *, 4 > args;
1893
- SmallVector<Identifier, 4 > argLabels;
1894
- SmallVector<SourceLoc, 4 > argLabelLocs;
1895
- Expr *trailingClosureNeverPresent;
1896
- ParserStatus S =
1897
- parseExprList (tok::l_paren, tok::r_paren,
1898
- /* isPostfix=*/ false , /* isExprBasic=*/ true ,
1899
- lParen, args, argLabels, argLabelLocs, rParen,
1900
- trailingClosureNeverPresent,
1901
- SyntaxKind::Unknown);
1902
- assert (!trailingClosureNeverPresent);
1903
-
1904
- Status |= S;
1905
- // If there was an error parsing a parameter, add an ErrorExpr to
1906
- // represent it. Prevents spurious errors about a nonexistent
1907
- // appendInterpolation() overload.
1908
- if (S.isError () && args.size () == 0 )
1909
- args.push_back (new (Context) ErrorExpr (SourceRange (lParen, rParen)));
1910
-
1911
- while (argLabels.size () < args.size ())
1912
- argLabels.push_back (Identifier ());
1913
- while (argLabelLocs.size () < args.size ())
1914
- argLabelLocs.push_back (SourceLoc ());
1903
+ auto callee = new (Context) UnresolvedDotExpr (InterpolationVarRef,
1904
+ /* dotloc=*/ BackSlashLoc,
1905
+ appendInterpolation,
1906
+ /* nameloc=*/ DeclNameLoc (),
1907
+ /* Implicit=*/ true );
1908
+ auto S = parseExprCallSuffix (makeParserResult (callee), true );
1915
1909
1916
1910
// If we stopped parsing the expression before the expression segment is
1917
1911
// over, eat the remaining tokens into a token list
@@ -1925,51 +1919,14 @@ parseStringSegments(SmallVectorImpl<Lexer::StringSegment> &Segments,
1925
1919
L->getLocForEndOfToken (SourceMgr, Tok.getLoc ()));
1926
1920
}
1927
1921
1922
+ Expr *call = S.getPtrOrNull ();
1923
+ if (!call)
1924
+ call = new (Context) ErrorExpr (SourceRange (Segment.Loc ,
1925
+ Segment.getEndLoc ()));
1926
+
1928
1927
InterpolationCount += 1 ;
1929
-
1930
- // In Swift 4.2 and earlier, a single argument with a label would ignore
1931
- // the label (at best), and multiple arguments would form a tuple.
1932
- if (!Context.isSwiftVersionAtLeast (5 )) {
1933
- if (args.size () > 1 ) {
1934
- diagnose (args[1 ]->getLoc (), diag::string_interpolation_list_changing)
1935
- .highlightChars (args[1 ]->getLoc (), rParen);
1936
- diagnose (args[1 ]->getLoc (),
1937
- diag::string_interpolation_list_insert_parens)
1938
- .fixItInsertAfter (lParen, " (" )
1939
- .fixItInsert (rParen, " )" );
1940
-
1941
- args = {
1942
- TupleExpr::create (Context,
1943
- lParen, args, argLabels, argLabelLocs, rParen,
1944
- /* hasTrailingClosure=*/ false ,
1945
- /* Implicit=*/ false )
1946
- };
1947
- argLabels = { Identifier () };
1948
- argLabelLocs = { SourceLoc () };
1949
- }
1950
- else if (args.size () == 1 && argLabels[0 ] != Identifier ()) {
1951
- diagnose (argLabelLocs[0 ], diag::string_interpolation_label_changing)
1952
- .highlightChars (argLabelLocs[0 ], args[0 ]->getStartLoc ());
1953
- diagnose (argLabelLocs[0 ], diag::string_interpolation_remove_label,
1954
- argLabels[0 ])
1955
- .fixItRemoveChars (argLabelLocs[0 ], args[0 ]->getStartLoc ());
1956
-
1957
- argLabels[0 ] = Identifier ();
1958
- }
1959
- }
1960
-
1961
- auto AppendInterpolationRef =
1962
- new (Context) UnresolvedDotExpr (InterpolationVarRef,
1963
- /* dotloc=*/ SourceLoc (),
1964
- appendInterpolation,
1965
- /* nameloc=*/ DeclNameLoc (),
1966
- /* Implicit=*/ true );
1967
- auto AppendInterpolationCall =
1968
- CallExpr::create (Context, AppendInterpolationRef,
1969
- lParen, args, argLabels, argLabelLocs, rParen,
1970
- /* trailingClosure=*/ nullptr , /* implicit=*/ false );
1971
-
1972
- Stmts.push_back (AppendInterpolationCall);
1928
+ Stmts.push_back (call);
1929
+ Status |= S;
1973
1930
1974
1931
if (!Tok.is (tok::eof)) {
1975
1932
diagnose (Tok, diag::string_interpolation_extra);
@@ -2003,35 +1960,73 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
2003
1960
SourceLoc Loc = Tok.getLoc ();
2004
1961
SourceLoc EndLoc = Loc.getAdvancedLoc (Tok.getLength ());
2005
1962
2006
- // The simple case: just a single literal segment.
2007
- if (Segments.size () == 1 &&
2008
- Segments.front ().Kind == Lexer::StringSegment::Literal) {
2009
- consumeToken ();
2010
- return makeParserResult (
2011
- createStringLiteralExprFromSegment (Context, L, Segments.front (), Loc));
2012
- }
2013
-
2014
- // We are now sure this is a string interpolation expression.
2015
- LocalContext.setCreateSyntax (SyntaxKind::StringInterpolationExpr);
2016
- StringRef OpenQuoteStr, CloseQuoteStr;
1963
+ StringRef OpenDelimiterStr, OpenQuoteStr, CloseQuoteStr, CloseDelimiterStr;
1964
+ unsigned DelimiterLength = Tok.getCustomDelimiterLen ();
1965
+ bool HasCustomDelimiter = DelimiterLength > 0 ;
1966
+ unsigned QuoteLength;
2017
1967
tok QuoteKind;
2018
- std::tie (OpenQuoteStr, CloseQuoteStr, QuoteKind) = Tok.isMultilineString () ?
2019
- std::make_tuple (Tok.getRawText ().take_front (3 ),
2020
- Tok.getRawText ().take_back (3 ),
2021
- tok::multiline_string_quote) :
2022
- std::make_tuple (Tok.getRawText ().take_front (1 ),
2023
- Tok.getRawText ().take_back (1 ),
2024
- tok::string_quote);
1968
+ std::tie (QuoteLength, QuoteKind) =
1969
+ Tok.isMultilineString () ? std::make_tuple (3 , tok::multiline_string_quote)
1970
+ : std::make_tuple (1 , tok::string_quote);
1971
+ unsigned CloseQuoteBegin = Tok.getLength () - DelimiterLength - QuoteLength;
1972
+
1973
+ OpenDelimiterStr = Tok.getRawText ().take_front (DelimiterLength);
1974
+ OpenQuoteStr = Tok.getRawText ().substr (DelimiterLength, QuoteLength);
1975
+ CloseQuoteStr = Tok.getRawText ().substr (CloseQuoteBegin, QuoteLength);
1976
+ CloseDelimiterStr = Tok.getRawText ().take_back (DelimiterLength);
2025
1977
2026
1978
// Make unknown tokens to represent the open and close quote.
2027
1979
Token OpenQuote (QuoteKind, OpenQuoteStr);
2028
1980
Token CloseQuote (QuoteKind, CloseQuoteStr);
2029
1981
ParsedTrivia EmptyTrivia;
2030
1982
ParsedTrivia EntireTrailingTrivia = TrailingTrivia;
2031
1983
2032
- // Add the open quote to the context; the quote should have the leading trivia
2033
- // of the entire string token and a void trailing trivia.
2034
- SyntaxContext->addToken (OpenQuote, LeadingTrivia, EmptyTrivia);
1984
+ if (HasCustomDelimiter) {
1985
+ Token OpenDelimiter (tok::raw_string_delimiter, OpenDelimiterStr);
1986
+ // When a custom delimiter is present, it owns the leading trivia.
1987
+ SyntaxContext->addToken (OpenDelimiter, LeadingTrivia, EmptyTrivia);
1988
+
1989
+ SyntaxContext->addToken (OpenQuote, EmptyTrivia, EmptyTrivia);
1990
+ } else {
1991
+ // Without custom delimiter the quote owns trailing trivia.
1992
+ SyntaxContext->addToken (OpenQuote, LeadingTrivia, EmptyTrivia);
1993
+ }
1994
+
1995
+ // The simple case: just a single literal segment.
1996
+ if (Segments.size () == 1 &&
1997
+ Segments.front ().Kind == Lexer::StringSegment::Literal) {
1998
+ {
1999
+ consumeExtraToken (Tok);
2000
+ consumeTokenWithoutFeedingReceiver ();
2001
+
2002
+ SyntaxParsingContext SegmentsCtx (SyntaxContext,
2003
+ SyntaxKind::StringLiteralSegments);
2004
+
2005
+ SyntaxParsingContext StrSegContext (SyntaxContext,
2006
+ SyntaxKind::StringSegment);
2007
+
2008
+ // Make an unknown token to encapsulate the entire string segment and add
2009
+ // such token to the context.
2010
+ auto Segment = Segments.front ();
2011
+ Token content (tok::string_segment,
2012
+ CharSourceRange (Segment.Loc , Segment.Length ).str ());
2013
+ SyntaxContext->addToken (content, EmptyTrivia, EmptyTrivia);
2014
+ }
2015
+
2016
+ if (HasCustomDelimiter) {
2017
+ SyntaxContext->addToken (CloseQuote, EmptyTrivia, EmptyTrivia);
2018
+
2019
+ Token CloseDelimiter (tok::raw_string_delimiter, CloseDelimiterStr);
2020
+ // When a custom delimiter is present it owns the trailing trivia.
2021
+ SyntaxContext->addToken (CloseDelimiter, EmptyTrivia, EntireTrailingTrivia);
2022
+ } else {
2023
+ // Without custom delimiter the quote owns trailing trivia.
2024
+ SyntaxContext->addToken (CloseQuote, EmptyTrivia, EntireTrailingTrivia);
2025
+ }
2026
+
2027
+ return makeParserResult (
2028
+ createStringLiteralExprFromSegment (Context, L, Segments.front (), Loc));
2029
+ }
2035
2030
2036
2031
// We don't expose the entire interpolated string as one token. Instead, we
2037
2032
// should expose the tokens in each segment.
@@ -2044,8 +2039,8 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
2044
2039
2045
2040
// We're not in a place where an interpolation would be valid.
2046
2041
if (!CurLocalContext) {
2047
- // Return an error, but include an empty InterpolatedStringLiteralExpr
2048
- // so that parseDeclPoundDiagnostic() can figure out why this string
2042
+ // Return an error, but include an empty InterpolatedStringLiteralExpr
2043
+ // so that parseDeclPoundDiagnostic() can figure out why this string
2049
2044
// literal was bad.
2050
2045
return makeParserErrorResult (
2051
2046
new (Context) InterpolatedStringLiteralExpr (Loc, 0 , 0 , nullptr ));
@@ -2075,7 +2070,7 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
2075
2070
2076
2071
// Collect all string segments.
2077
2072
SyntaxParsingContext SegmentsCtx (SyntaxContext,
2078
- SyntaxKind::StringInterpolationSegments );
2073
+ SyntaxKind::StringLiteralSegments );
2079
2074
Status = parseStringSegments (Segments, EntireTok, InterpolationVar,
2080
2075
Stmts, LiteralCapacity, InterpolationCount);
2081
2076
@@ -2084,9 +2079,16 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
2084
2079
AppendingExpr = new (Context) TapExpr (nullptr , Body);
2085
2080
}
2086
2081
2087
- // Add the close quote the context; the quote should have a void leading trivia
2088
- // and the trailing trivia of the entire string token.
2089
- SyntaxContext->addToken (CloseQuote, EmptyTrivia, EntireTrailingTrivia);
2082
+ if (HasCustomDelimiter) {
2083
+ SyntaxContext->addToken (CloseQuote, EmptyTrivia, EmptyTrivia);
2084
+
2085
+ Token CloseDelimiter (tok::raw_string_delimiter, CloseDelimiterStr);
2086
+ // When a custom delimiter is present it owns the trailing trivia.
2087
+ SyntaxContext->addToken (CloseDelimiter, EmptyTrivia, EntireTrailingTrivia);
2088
+ } else {
2089
+ // Without custom delimiter the quote owns trailing trivia.
2090
+ SyntaxContext->addToken (CloseQuote, EmptyTrivia, EntireTrailingTrivia);
2091
+ }
2090
2092
2091
2093
if (AppendingExpr->getBody ()->getNumElements () == 1 ) {
2092
2094
Status.setIsParseError ();
0 commit comments