@@ -1368,43 +1368,26 @@ object Parsers {
13681368 // APIs behaves predictably in the presence of empty leading/trailing lines
13691369 if (closingIndent == " " ) str
13701370 else {
1371- // Check for mixed tabs and spaces in closing indent
1372-
1373- val hasTabs = closingIndent.contains('\t ' )
1374- val hasSpaces = closingIndent.contains(' ' )
1375- if (hasTabs && hasSpaces) {
1371+ if (closingIndent.contains('\t ' ) && closingIndent.contains(' ' )) {
13761372 syntaxError(
13771373 em " dedented string literal cannot mix tabs and spaces in indentation " ,
13781374 offset
13791375 )
13801376 return str
13811377 }
13821378
1383- // Split into lines
13841379 val linesAndWithSeps = (str.linesIterator.zip(str.linesWithSeparators)).toSeq
1385-
13861380 var lineOffset = offset
13871381
13881382 def dedentLine (line : String , lineWithSep : String ) = {
13891383 val result =
13901384 if (line.startsWith(closingIndent)) line.substring(closingIndent.length)
13911385 else if (line.trim.isEmpty) " " // Empty or whitespace-only lines
13921386 else {
1393- // Check if this line has mixed tabs/spaces that don't match closing indent
1394- val lineIndent = line.takeWhile(_.isWhitespace)
1395- val lineHasTabs = lineIndent.contains('\t ' )
1396- val lineHasSpaces = lineIndent.contains(' ' )
1397- if ((hasTabs && lineHasSpaces && ! lineHasTabs) || (hasSpaces && lineHasTabs && ! lineHasSpaces)) {
1398- syntaxError(
1399- em " dedented string literal cannot mix tabs and spaces in indentation " ,
1400- offset
1401- )
1402- } else {
1403- syntaxError(
1404- em " line in dedented string literal must be indented at least as much as the closing delimiter " ,
1405- lineOffset
1406- )
1407- }
1387+ syntaxError(
1388+ em " line in dedented string literal must be indented at least as much as the closing delimiter with an identical prefix " ,
1389+ lineOffset
1390+ )
14081391 line
14091392 }
14101393 lineOffset += lineWithSep.length // Make sure to include any \n, \r, \r\n, or \n\r
@@ -1551,14 +1534,15 @@ object Parsers {
15511534 in.charOffset + 1 < in.buf.length &&
15521535 in.buf(in.charOffset) == '"' &&
15531536 in.buf(in.charOffset + 1 ) == '"'
1537+
15541538 val isDedented =
15551539 in.charOffset + 2 < in.buf.length &&
15561540 in.buf(in.charOffset - 1 ) == '\' ' &&
15571541 in.buf(in.charOffset) == '\' ' &&
15581542 in.buf(in.charOffset + 1 ) == '\' '
1543+
15591544 in.nextToken()
15601545
1561- // Collect all string parts and their offsets
15621546 val stringParts = new ListBuffer [(String , Offset )]
15631547 val interpolatedExprs = new ListBuffer [Tree ]
15641548
@@ -1569,7 +1553,6 @@ object Parsers {
15691553 offsetCorrection = 0
15701554 in.nextToken()
15711555
1572- // Collect the interpolated expression
15731556 interpolatedExprs += atSpan(in.offset) {
15741557 if (in.token == IDENTIFIER )
15751558 termIdent()
@@ -1591,7 +1574,6 @@ object Parsers {
15911574 }
15921575 }
15931576
1594- // Get the final STRINGLIT
15951577 val finalLiteral = if (in.token == STRINGLIT ) {
15961578 val s = in.strVal
15971579 val off = in.offset + offsetCorrection
@@ -1611,7 +1593,6 @@ object Parsers {
16111593 }
16121594 }
16131595
1614- // Build the segments with dedented strings
16151596 for ((str, expr) <- dedentedParts.zip(interpolatedExprs)) {
16161597 val (dedentedStr, offset) = str
16171598 segmentBuf += Thicket (
@@ -1620,8 +1601,7 @@ object Parsers {
16201601 )
16211602 }
16221603
1623- // Add the final literal if present
1624- if (finalLiteral) {
1604+ if (finalLiteral) { // Add the final literal if present
16251605 val (dedentedStr, offset) = dedentedParts.last
16261606 segmentBuf += atSpan(offset, offset, offset + dedentedStr.length) { Literal (Constant (dedentedStr)) }
16271607 }
0 commit comments