Skip to content

Commit b260092

Browse files
committed
Make IndentRegions a subcase of normal regions.
Nerge the `indented` and `currentRegion` stacks
1 parent cd887c6 commit b260092

File tree

2 files changed

+68
-49
lines changed

2 files changed

+68
-49
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,11 @@ object Parsers {
606606

607607
/** Parse indentation region `body` and rewrite it to be in braces instead */
608608
def indentedToBraces[T](body: => T): T = {
609-
val indentWidth = in.indent.enclosing.width
609+
val enclRegion = in.currentRegion.enclosing
610+
def indentWidth = enclRegion match {
611+
case Indented(w, _, _, _) => w
612+
case _ => IndentWidth.Zero
613+
}
610614
val followsColon = testChar(in.lastOffset - 1, ':')
611615
val startOpening =
612616
if (followsColon)
@@ -1172,7 +1176,7 @@ object Parsers {
11721176
}
11731177

11741178
def indentRegion[T](tag: EndMarkerTag)(op: => T): T = {
1175-
val iw = in.indent.width
1179+
val iw = in.currentIndentWidth
11761180
val t = op
11771181
in.consumeEndMarker(tag, iw)
11781182
t

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 62 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -307,14 +307,11 @@ object Scanners {
307307
*/
308308
var currentRegion: Region = Outermost
309309

310-
def currentIndentWidth = currentRegion match {
310+
def currentIndentWidth: IndentWidth = currentRegion match {
311311
case r: Indented => r.width
312-
case _ => 0
312+
case _ => IndentWidth.Zero
313313
}
314314

315-
/** Indentation widths, innermost to outermost */
316-
var indent: IndentRegion = IndentRegion(IndentWidth.Zero, Set(), EMPTY, null)
317-
318315
/** The end marker that was skipped last */
319316
val endMarkers = new mutable.ListBuffer[EndMarker]
320317

@@ -418,7 +415,7 @@ object Scanners {
418415
* value at the end of the endMarkers queue.
419416
*/
420417
private def handleEndMarkers(width: IndentWidth): Unit = {
421-
if (next.token == IDENTIFIER && next.name == nme.end && width == indent.width) {
418+
if (next.token == IDENTIFIER && next.name == nme.end && width == currentIndentWidth) {
422419
val lookahead = lookaheadScanner
423420
lookahead.nextToken() // skip the `end`
424421

@@ -565,49 +562,63 @@ object Scanners {
565562
* if the current indentation width and the indentation of the current token are incomparable.
566563
*/
567564
def handleNewLine(lastToken: Token) = {
568-
val indentIsSignificant = indentSyntax && currentRegion.isOutermost
569-
val newlineIsSeparating = currentRegion match {
570-
case Outermost | InBraces(_) => true
571-
case _ => false
565+
var indentIsSignificant = false
566+
var newlineIsSeparating = false
567+
var lastWidth = IndentWidth.Zero
568+
var indentPrefix = EMPTY
569+
currentRegion match {
570+
case Outermost =>
571+
if (indentSyntax) indentIsSignificant = true
572+
newlineIsSeparating = true
573+
case r: Indented =>
574+
indentIsSignificant = true
575+
newlineIsSeparating = true
576+
lastWidth = r.width
577+
indentPrefix = r.prefix
578+
case _: InBraces =>
579+
newlineIsSeparating = true
580+
case _ =>
572581
}
573-
val curWidth = indentWidth(offset)
574-
val lastWidth = indent.width
582+
val nextWidth = indentWidth(offset)
575583
if (newlineIsSeparating &&
576584
canEndStatTokens.contains(lastToken)&&
577585
canStartStatTokens.contains(token) &&
578-
(!indentIsSignificant || lastWidth <= curWidth) &&
586+
(!indentIsSignificant || lastWidth <= nextWidth) &&
579587
!isLeadingInfixOperator())
580588
insert(if (pastBlankLine) NEWLINES else NEWLINE, lineOffset)
581589
else if (indentIsSignificant) {
582-
if (lastWidth < curWidth ||
583-
lastWidth == curWidth && (lastToken == MATCH || lastToken == CATCH) && token == CASE) {
590+
if (lastWidth < nextWidth ||
591+
lastWidth == nextWidth && (lastToken == MATCH || lastToken == CATCH) && token == CASE) {
584592
if (canStartIndentTokens.contains(lastToken)) {
585-
indent = IndentRegion(curWidth, Set(), lastToken, indent)
593+
currentRegion = Indented(nextWidth, Set(), lastToken, currentRegion)
586594
insert(INDENT, offset)
587595
}
588596
}
589-
else if (curWidth < lastWidth ||
590-
curWidth == lastWidth && (indent.token == MATCH || indent.token == CATCH) && token != CASE) {
597+
else if (nextWidth < lastWidth ||
598+
nextWidth == lastWidth && (indentPrefix == MATCH || indentPrefix == CATCH) && token != CASE) {
591599
if (!isLeadingInfixOperator()) {
592-
indent = indent.enclosing
600+
currentRegion = currentRegion.asInstanceOf[Indented].enclosing
593601
insert(OUTDENT, offset)
594-
handleEndMarkers(curWidth)
602+
handleEndMarkers(nextWidth)
595603
}
596604
}
597-
else if (lastWidth != curWidth)
605+
else if (lastWidth != nextWidth)
598606
errorButContinue(
599607
i"""Incompatible combinations of tabs and spaces in indentation prefixes.
600608
|Previous indent : $lastWidth
601-
|Latest indent : $curWidth""")
609+
|Latest indent : $nextWidth""")
610+
}
611+
currentRegion match {
612+
case Indented(curWidth, others, prefix, outer) if curWidth < nextWidth && !others.contains(nextWidth) =>
613+
if (token == OUTDENT)
614+
errorButContinue(
615+
i"""The start of this line does not match any of the previous indentation widths.
616+
|Indentation width of current line : $nextWidth
617+
|This falls between previous widths: $curWidth and $lastWidth""")
618+
else
619+
currentRegion = Indented(curWidth, others + nextWidth, prefix, outer)
620+
case _ =>
602621
}
603-
if (indentIsSignificant && indent.width < curWidth && !indent.others.contains(curWidth))
604-
if (token == OUTDENT)
605-
errorButContinue(
606-
i"""The start of this line does not match any of the previous indentation widths.
607-
|Indentation width of current line : $curWidth
608-
|This falls between previous widths: ${indent.width} and $lastWidth""")
609-
else
610-
indent = IndentRegion(indent.width, indent.others + curWidth, indent.token, indent.outer)
611622
}
612623

613624
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
@@ -650,9 +661,13 @@ object Scanners {
650661
val atEOL = isAfterLineEnd
651662
reset()
652663
if (atEOL) token = COLONEOL
653-
case EOF if !indent.isOutermost =>
654-
insert(OUTDENT, offset)
655-
indent = indent.outer
664+
case EOF =>
665+
currentRegion match {
666+
case r: Indented =>
667+
insert(OUTDENT, offset)
668+
currentRegion = r.outer
669+
case _ =>
670+
}
656671
case _ =>
657672
}
658673
}
@@ -763,35 +778,38 @@ object Scanners {
763778
getStringPart(multiLine)
764779
currentRegion = InString(multiLine, currentRegion)
765780
}
766-
def fetchDoubleQuote() = {
781+
def fetchDoubleQuote() =
767782
if (token == INTERPOLATIONID) {
768783
nextRawChar()
769784
if (ch == '\"') {
770785
nextRawChar()
771786
if (ch == '\"') {
772787
nextRawChar()
773788
stringPart(multiLine = true)
774-
} else {
789+
}
790+
else {
775791
token = STRINGLIT
776792
strVal = ""
777793
}
778-
} else stringPart(multiLine = false)
779-
} else {
794+
}
795+
else stringPart(multiLine = false)
796+
}
797+
else {
780798
nextChar()
781799
if (ch == '\"') {
782800
nextChar()
783801
if (ch == '\"') {
784802
nextRawChar()
785803
getRawStringLit()
786-
} else {
804+
}
805+
else {
787806
token = STRINGLIT
788807
strVal = ""
789808
}
790-
} else {
791-
getStringLit()
792809
}
810+
else
811+
getStringLit()
793812
}
794-
}
795813
fetchDoubleQuote()
796814
case '\'' =>
797815
def fetchSingleQuote() = {
@@ -1352,17 +1370,14 @@ object Scanners {
13521370
case class InParens(prefix: Token, outer: Region) extends Region
13531371
case class InBraces(outer: Region) extends Region
13541372
case class InString(multiLine: Boolean, outer: Region) extends Region
1355-
case class Indented(width: IndentWidth, others: Set[IndentWidth], prefix: Token, outer: Region) extends Region
1356-
case object Outermost extends Region { val outer = null }
13571373

13581374
/** A class describing an indentation region.
13591375
* @param width The principal indendation width
13601376
* @param others Other indendation widths > width of lines in the same region
13611377
*/
1362-
class IndentRegion(val width: IndentWidth, val others: Set[IndentWidth], val token: Token, val outer: IndentRegion | Null) {
1363-
def enclosing: IndentRegion = outer.asInstanceOf[IndentRegion]
1364-
def isOutermost = outer == null
1365-
}
1378+
case class Indented(width: IndentWidth, others: Set[IndentWidth], prefix: Token, outer: Region) extends Region
1379+
1380+
case object Outermost extends Region { val outer = null }
13661381

13671382
enum IndentWidth {
13681383
case Run(ch: Char, n: Int)

0 commit comments

Comments
 (0)