@@ -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