@@ -274,7 +274,7 @@ object Scanners {
274
274
private val prev = newTokenData
275
275
276
276
/** The current region. This is initially an Indented region with zero indentation width. */
277
- var currentRegion : Region = Indented (IndentWidth .Zero , Set (), EMPTY , null )
277
+ var currentRegion : Region = Indented (IndentWidth .Zero , EMPTY , null )
278
278
279
279
def lastKnownIndentWidth : IndentWidth =
280
280
def recur (r : Region | Null ): IndentWidth =
@@ -333,6 +333,10 @@ object Scanners {
333
333
case InParens (prefix, outer) if prefix + 1 == lastToken => currentRegion = outer
334
334
case _ =>
335
335
}
336
+ case OUTDENT =>
337
+ currentRegion match
338
+ case r : Indented => currentRegion = r.enclosing
339
+ case _ =>
336
340
case STRINGLIT =>
337
341
currentRegion match {
338
342
case InString (_, outer) => currentRegion = outer
@@ -441,8 +445,8 @@ object Scanners {
441
445
|| {
442
446
r.outer match
443
447
case null => true
444
- case Indented (outerWidth, others , _, _) =>
445
- outerWidth < nextWidth && ! others .contains(nextWidth)
448
+ case ro @ Indented (outerWidth, _, _) =>
449
+ outerWidth < nextWidth && ! ro.otherIndentWidths .contains(nextWidth)
446
450
case outer =>
447
451
outer.indentWidth < nextWidth
448
452
}
@@ -548,6 +552,15 @@ object Scanners {
548
552
var lastWidth = IndentWidth .Zero
549
553
var indentPrefix = EMPTY
550
554
val nextWidth = indentWidth(offset)
555
+
556
+ // If nextWidth is an indentation level not yet seen by enclosing indentation
557
+ // region, invoke `handler`.
558
+ def handleNewIndentWidth (r : Region , handler : Indented => Unit ): Unit = r match
559
+ case r @ Indented (curWidth, prefix, outer)
560
+ if curWidth < nextWidth && ! r.otherIndentWidths.contains(nextWidth) && nextWidth != lastWidth =>
561
+ handler(r)
562
+ case _ =>
563
+
551
564
currentRegion match
552
565
case r : Indented =>
553
566
indentIsSignificant = indentSyntax
@@ -576,32 +589,28 @@ object Scanners {
576
589
else if ! isLeadingInfixOperator(nextWidth) && ! statCtdTokens.contains(lastToken) && lastToken != INDENT then
577
590
currentRegion match
578
591
case r : Indented =>
579
- currentRegion = r.enclosing
580
592
insert(OUTDENT , offset)
593
+ if next.token != COLON then
594
+ handleNewIndentWidth(r.enclosing, ir =>
595
+ errorButContinue(
596
+ i """ The start of this line does not match any of the previous indentation widths.
597
+ |Indentation width of current line : $nextWidth
598
+ |This falls between previous widths: ${ir.width} and $lastWidth""" ))
581
599
case r : InBraces if ! closingRegionTokens.contains(token) =>
582
600
report.warning(" Line is indented too far to the left, or a `}` is missing" , sourcePos())
583
601
case _ =>
584
602
585
603
else if lastWidth < nextWidth
586
604
|| lastWidth == nextWidth && (lastToken == MATCH || lastToken == CATCH ) && token == CASE then
587
605
if canStartIndentTokens.contains(lastToken) then
588
- currentRegion = Indented (nextWidth, Set (), lastToken, currentRegion)
606
+ currentRegion = Indented (nextWidth, lastToken, currentRegion)
589
607
insert(INDENT , offset)
590
608
else if lastToken == SELFARROW then
591
609
currentRegion.knownWidth = nextWidth
592
610
else if (lastWidth != nextWidth)
593
611
errorButContinue(spaceTabMismatchMsg(lastWidth, nextWidth))
594
- currentRegion match
595
- case Indented (curWidth, others, prefix, outer)
596
- if curWidth < nextWidth && ! others.contains(nextWidth) && nextWidth != lastWidth =>
597
- if token == OUTDENT && next.token != COLON then
598
- errorButContinue(
599
- i """ The start of this line does not match any of the previous indentation widths.
600
- |Indentation width of current line : $nextWidth
601
- |This falls between previous widths: $curWidth and $lastWidth""" )
602
- else
603
- currentRegion = Indented (curWidth, others + nextWidth, prefix, outer)
604
- case _ =>
612
+ if token != OUTDENT || next.token == COLON then
613
+ handleNewIndentWidth(currentRegion, _.otherIndentWidths += nextWidth)
605
614
end handleNewLine
606
615
607
616
def spaceTabMismatchMsg (lastWidth : IndentWidth , nextWidth : IndentWidth ) =
@@ -621,7 +630,7 @@ object Scanners {
621
630
val nextWidth = indentWidth(next.offset)
622
631
val lastWidth = currentRegion.indentWidth
623
632
if lastWidth < nextWidth then
624
- currentRegion = Indented (nextWidth, Set (), COLONEOL , currentRegion)
633
+ currentRegion = Indented (nextWidth, COLONEOL , currentRegion)
625
634
offset = next.offset
626
635
token = INDENT
627
636
end observeIndented
@@ -636,7 +645,6 @@ object Scanners {
636
645
&& ! (token == CASE && r.prefix == MATCH )
637
646
&& next.token == EMPTY // can be violated for ill-formed programs, e.g. neg/i12605.sala
638
647
=>
639
- currentRegion = r.enclosing
640
648
insert(OUTDENT , offset)
641
649
case _ =>
642
650
@@ -651,9 +659,7 @@ object Scanners {
651
659
}
652
660
653
661
def closeIndented () = currentRegion match
654
- case r : Indented if ! r.isOutermost =>
655
- insert(OUTDENT , offset)
656
- currentRegion = r.outer
662
+ case r : Indented if ! r.isOutermost => insert(OUTDENT , offset)
657
663
case _ =>
658
664
659
665
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT
@@ -684,7 +690,6 @@ object Scanners {
684
690
currentRegion match
685
691
case r : Indented if isEnclosedInParens(r.outer) =>
686
692
insert(OUTDENT , offset)
687
- currentRegion = r.outer
688
693
case _ =>
689
694
lookAhead()
690
695
if isAfterLineEnd
@@ -1570,13 +1575,16 @@ object Scanners {
1570
1575
1571
1576
/** A class describing an indentation region.
1572
1577
* @param width The principal indendation width
1573
- * @param others Other indendation widths > width of lines in the same region
1574
1578
* @param prefix The token before the initial <indent> of the region
1575
1579
*/
1576
- case class Indented (width : IndentWidth , others : Set [ IndentWidth ], prefix : Token , outer : Region | Null ) extends Region :
1580
+ case class Indented (width : IndentWidth , prefix : Token , outer : Region | Null ) extends Region :
1577
1581
knownWidth = width
1578
1582
1579
- def topLevelRegion (width : IndentWidth ) = Indented (width, Set (), EMPTY , null )
1583
+ /** Other indendation widths > width of lines in the same region */
1584
+ var otherIndentWidths : Set [IndentWidth ] = Set ()
1585
+ end Indented
1586
+
1587
+ def topLevelRegion (width : IndentWidth ) = Indented (width, EMPTY , null )
1580
1588
1581
1589
enum IndentWidth {
1582
1590
case Run (ch : Char , n : Int )
0 commit comments