diff --git a/compiler/src/dotty/tools/backend/jvm/CodeGen.scala b/compiler/src/dotty/tools/backend/jvm/CodeGen.scala index 86aa9a19a5f1..f0ba6e942732 100644 --- a/compiler/src/dotty/tools/backend/jvm/CodeGen.scala +++ b/compiler/src/dotty/tools/backend/jvm/CodeGen.scala @@ -103,7 +103,7 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)( GeneratedDefs(generatedClasses.toList, generatedTasty.toList) // Creates a callback that will be evaluated in PostProcessor after creating a file - private def onFileCreated(cls: ClassNode, claszSymbol: Symbol, sourceFile: interfaces.SourceFile): AbstractFile => Unit = clsFile => + private def onFileCreated(cls: ClassNode, claszSymbol: Symbol, sourceFile: interfaces.SourceFile): AbstractFile => Unit = clsFile => { val (fullClassName, isLocal) = atPhase(sbtExtractDependenciesPhase): (ExtractDependencies.classNameAsString(claszSymbol), claszSymbol.isLocal) @@ -116,6 +116,7 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)( val cb = ctx.sbtCallback if (isLocal) cb.generatedLocalClass(jSourceFile, clsFile.file) else cb.generatedNonLocalClass(jSourceFile, clsFile.file, className, fullClassName) + } /** Convert a `dotty.tools.io.AbstractFile` into a * `dotty.tools.dotc.interfaces.AbstractFile`. diff --git a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala index 62eaa04c1914..933d944d66a8 100644 --- a/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/AggregateClassPath.scala @@ -127,8 +127,10 @@ case class AggregateClassPath(aggregates: Seq[ClassPath]) extends ClassPath: cp <- aggregates entry <- getEntries(cp) if !seenNames.contains(entry.name) } + { entriesBuffer += entry seenNames += entry.name + } entriesBuffer.toIndexedSeq object AggregateClassPath: diff --git a/compiler/src/dotty/tools/dotc/core/Comments.scala b/compiler/src/dotty/tools/dotc/core/Comments.scala index c94342e89ebe..e82a19e5d926 100644 --- a/compiler/src/dotty/tools/dotc/core/Comments.scala +++ b/compiler/src/dotty/tools/dotc/core/Comments.scala @@ -10,7 +10,7 @@ import util.{SourceFile, ReadOnlyMap} import util.Spans._ import util.CommentParsing._ import util.Property.Key -import parsing.Parsers.Parser +import parsing.Parsers import reporting.ProperDefinitionNotFound object Comments: @@ -118,7 +118,7 @@ object Comments: object UseCase: def apply(code: String, codePos: Span)(using Context): UseCase = val tree = - val tree = new Parser(SourceFile.virtual("", code)).localDef(codePos.start) + val tree = Parsers.parser(SourceFile.virtual("", code)).localDef(codePos.start) tree match case tree: untpd.DefDef => val newName = ctx.compilationUnit.freshNames.newName(tree.name, NameKinds.DocArtifactName) diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index 81fed97e4409..8bc1a0fd65ea 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -12,7 +12,7 @@ import SymDenotations.SymDenotation import config.Printers.inlining import ErrorReporting.errorTree import dotty.tools.dotc.util.{SourceFile, SourcePosition, SrcPos} -import parsing.Parsers.Parser +import parsing.Parsers import transform.{PostTyper, Inlining, CrossVersionChecks} import staging.StagingLevel @@ -323,7 +323,7 @@ object Inlines: case ConstantType(Constant(code: String)) => val source2 = SourceFile.virtual("tasty-reflect", code) inContext(ctx.fresh.setNewTyperState().setTyper(new Typer(ctx.nestingLevel + 1)).setSource(source2)): - val tree2 = new Parser(source2).block() + val tree2 = Parsers.parser(source2).block() if ctx.reporter.allErrors.nonEmpty then ctx.reporter.allErrors.map((ErrorKind.Parser, _)) else diff --git a/compiler/src/dotty/tools/dotc/parsing/ParserPhase.scala b/compiler/src/dotty/tools/dotc/parsing/ParserPhase.scala index 261a6d2bd0be..27fa5ce540c6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/ParserPhase.scala +++ b/compiler/src/dotty/tools/dotc/parsing/ParserPhase.scala @@ -27,7 +27,7 @@ class Parser extends Phase: unit.untpdTree = if (unit.isJava) new JavaParsers.JavaParser(unit.source).parse() else - val p = new Parsers.Parser(unit.source) + val p = Parsers.parser(unit.source) // p.in.debugTokenStream = true val tree = p.parse() if (p.firstXmlPos.exists && !firstXmlPos.exists) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 24c684c39afd..fc0223c666dc 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -23,7 +23,6 @@ import StdNames._ import util.Spans._ import Constants._ import Symbols.NoSymbol -import ScriptParsers._ import Decorators._ import util.Chars import scala.annotation.tailrec @@ -72,7 +71,7 @@ object Parsers: * if not, the AST will be supplemented. */ def parser(source: SourceFile)(using Context): Parser = - if source.isSelfContained then new ScriptParser(source) + if ctx.settings.rewrite.value.isDefined && ctx.settings.indent.value then new ToIndentParser(source) else new Parser(source) private val InCase: Region => Region = Scanners.InCase(_) @@ -162,15 +161,18 @@ object Parsers: else if (in.token == RBRACE || in.token == OUTDENT) openBraces -= 1 in.nextToken() - class Parser(source: SourceFile, allowRewrite: Boolean = true)(using Context) extends ParserCommon(source): + class Parser private[Parsers] (source: SourceFile, allowRewrite: Boolean = true)(using Context) extends ParserCommon(source): - val in: Scanner = new Scanner(source, profile = Profile.current, allowRewrite = allowRewrite) + val in: Scanner = createScanner() // in.debugTokenStream = true // uncomment to see the token stream of the standard scanner, but not syntax highlighting + def createScanner() = + new Scanner(source, profile = Profile.current, allowRewrite = allowRewrite) + /** This is the general parse entry point. - * Overridden by ScriptParser */ def parse(): Tree = + if !source.isSelfContained then unsupported("parse") val t = compilationUnit() accept(EOF) t @@ -286,7 +288,7 @@ object Parsers: val offset = in.offset if in.token != token then syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token)) - if in.token == token then nextToken() + if in.token == token then in.nextToken() offset def accept(name: Name): Int = @@ -294,19 +296,19 @@ object Parsers: if !isIdent(name) then syntaxErrorOrIncomplete(em"`$name` expected") if isIdent(name) then - nextToken() + in.nextToken() offset def acceptColon(): Int = val offset = in.offset - if in.isColon then { nextToken(); offset } + if in.isColon then { in.nextToken(); offset } else accept(COLONop) /** semi = nl {nl} | `;' * nl = `\n' // where allowed */ def acceptStatSep(): Unit = - if in.isNewLine then nextToken() else accept(SEMI) + if in.isNewLine then in.nextToken() else accept(SEMI) /** Parse statement separators and end markers. Ensure that there is at least * one statement separator unless the next token terminates a statement´sequence. @@ -321,7 +323,7 @@ object Parsers: def statSepOrEnd[T <: Tree](stats: ListBuffer[T], noPrevStat: Boolean = false, what: String = "statement", altEnd: Token = EOF): Boolean = def recur(sepSeen: Boolean, endSeen: Boolean): Boolean = if isStatSep then - nextToken() + in.nextToken() recur(true, endSeen) else if in.token == END then if endSeen then syntaxError(em"duplicate end marker") @@ -340,7 +342,7 @@ object Parsers: if mustStartStatTokens.contains(found) then false // it's a statement that might be legal in an outer context else - nextToken() // needed to ensure progress; otherwise we might cycle forever + in.nextToken() // needed to ensure progress; otherwise we might cycle forever skip() true @@ -451,7 +453,6 @@ object Parsers: syntaxError(em"invalid parameter definition syntax in tuple value", param.span) case _ => - /** Convert (qual)ident to type identifier */ def convertToTypeId(tree: Tree): Tree = tree match @@ -532,21 +533,17 @@ object Parsers: def inBraces[T](body: => T): T = enclosed(LBRACE, body) def inBrackets[T](body: => T): T = enclosed(LBRACKET, body) - def inBracesOrIndented[T](body: => T, inStatSeq: Boolean = false, rewriteWithColon: Boolean = false): T = - val followsArrow = in.last.token == ARROW + def isAfterArrow = testChars(in.lastOffset - 3, " =>") + + def inBracesOrIndented[T](body: => T, rewriteWithColon: Boolean = false): T = if in.token == INDENT then // braces are always optional after `=>` so none should be inserted - val rewriteToBraces = in.rewriteNoIndent && !followsArrow - val rewriteToIndent = in.rewriteToIndent && !followsArrow - if rewriteToBraces then indentedToBraces(body) - else if rewriteToIndent then enclosed(INDENT, toIndentedRegion(body)) + if in.rewriteNoIndent && !isAfterArrow then indentedToBraces(body) else enclosed(INDENT, body) - else - if in.rewriteToIndent then bracesToIndented(body, inStatSeq, rewriteWithColon) - else inBraces(body) + else inBraces(body) - def inDefScopeBraces[T](body: => T, inStatSeq: Boolean = false, rewriteWithColon: Boolean = false): T = - inBracesOrIndented(body, inStatSeq, rewriteWithColon) + def inDefScopeBraces[T](body: => T, rewriteWithColon: Boolean = false): T = + inBracesOrIndented(body, rewriteWithColon) /** {`,` } */ def commaSeparated[T](part: () => T): List[T] = @@ -561,7 +558,7 @@ object Parsers: if in.token == COMMA then val ts = new ListBuffer[T] += leading while in.token == COMMA do - nextToken() + in.nextToken() ts += part() ts.toList else leading :: Nil @@ -613,18 +610,6 @@ object Parsers: /* -------- REWRITES ----------------------------------------------------------- */ - object IndentRewriteState: - /** The last offset where a colon at the end of line would be required if a subsequent { ... } - * block would be converted to an indentation region. */ - var possibleColonOffset: Int = -1 - - /** When rewriting to indent, the minimum indent width to rewrite to */ - var minimumIndent: IndentWidth = IndentWidth.Zero - - /** When rewritting to indent, the maximum indent width to rewrite to - * to ensure an indent region is properly closed by outdentation */ - var maximumIndent: Option[IndentWidth] = None - def testChar(idx: Int, p: Char => Boolean): Boolean = val txt = source.content idx > -1 && idx < txt.length && p(txt(idx)) @@ -638,7 +623,7 @@ object Parsers: testChar(from, str.head) && testChars(from + 1, str.tail) def skipBlanks(idx: Int, step: Int = 1): Int = - if testChar(idx, c => c == ' ' || c == '\t' || c == Chars.CR) then skipBlanks(idx + step, step) + if (testChar(idx, c => c == ' ' || c == '\t' || c == Chars.CR)) skipBlanks(idx + step, step) else idx /** Parse indentation region `body` and rewrite it to be in braces instead */ @@ -705,127 +690,16 @@ object Parsers: val (start, end) = blankLinesAround(offset, offset + 1) if testChar(end, Chars.LF) then if testChar(start - 1, Chars.LF) then (start, end + 1) // skip the whole line - else (start, end) // skip the end of line - else (offset, end) // skip from last to end of token + else (start, end) // skip from previous char to end of line + else (offset, end) // skip from token to next char /** Expand the current span to its surrounding blank space */ def blankLinesAround(start: Offset, end: Offset): (Offset, Offset) = (skipBlanks(start - 1, -1) + 1, skipBlanks(end, 1)) - /** Parse brace-enclosed `body` and rewrite it to be an indentation region instead, if possible. - * If possible means: - * 1. not inside (...), [...], case ... => - * 2. opening brace `{` is at end of line - * 3. closing brace `}` is at start of line - * 4. there is at least one token between the braces - * 5. the closing brace is also at the end of the line, or it is followed by one of - * `then`, `else`, `do`, `catch`, `finally`, `yield`, or `match`. - * 6. the opening brace does not follow a closing `}` - * 7. last token is not a leading operator - * 8. not a block in a sequence of statements - * 9. cannot rewrite to colon after a NEWLINE, e.g. - * true || - * { // NEWLINE inserted between || and { - * false - * } - */ - def bracesToIndented[T](body: => T, inStatSeq: Boolean, rewriteWithColon: Boolean): T = - import IndentRewriteState.* - val lastSaved = in.last.saveCopy - val lastOffsetSaved = in.lastOffset - val underColonSyntax = possibleColonOffset == in.lastOffset - val colonRequired = rewriteWithColon || underColonSyntax - val (startOpening, endOpening) = elimRegion(in.offset) - def isBracesOrIndented(r: Region): Boolean = r match - case r: Indented => true - case r: InBraces => true - case _ => false - var canRewrite = isBracesOrIndented(in.currentRegion) && // test (1) - lastSaved.token != RBRACE && // test (6) - !(lastSaved.isOperator && lastSaved.isAfterLineEnd) && // test (7) - !inStatSeq // test (8) - val t = enclosed(LBRACE, { - if in.isAfterLineEnd && in.token != RBRACE then // test (2)(4) - toIndentedRegion: - try body - finally canRewrite &= in.isAfterLineEnd // test (3) - else - canRewrite = false - body - }) - canRewrite &= (in.isAfterLineEnd || in.token == EOF || statCtdTokens.contains(in.token)) && // test (5) - (!colonRequired || !lastSaved.isNewLine) // test (9) - if canRewrite && (!underColonSyntax || Feature.fewerBracesEnabled) then - val (startClosing, endClosing) = elimRegion(in.last.offset) - // patch over the added indentation to remove braces - patchOver(source, Span(startOpening, endOpening), "") - patchOver(source, Span(startClosing, endClosing), "") - if colonRequired then - if lastSaved.token == IDENTIFIER && lastSaved.isOperator then - patch(Span(lastSaved.offset, lastSaved.offset + lastSaved.name.length), s"`${lastSaved.name}`:") - else if lastSaved.token == IDENTIFIER && lastSaved.name.last == '_' then - patch(Span(lastOffsetSaved), " :") - else patch(Span(lastOffsetSaved), ":") - else - // no need to force outdentation after `}` - maximumIndent = None - t - end bracesToIndented - /** When rewriting to indent, make sure there is an indent after a `=>\n` */ def indentedRegionAfterArrow[T](body: => T, inCaseDef: Boolean = false): T = - if in.rewriteToIndent && (inCaseDef || in.isAfterLineEnd) then - // assert(in.last.isArrow || in.last.token == SELFARROW) - toIndentedRegion(body) - else body - - /** compute required indentation to indent region properly */ - def toIndentedRegion[T](body: => T): T = - import IndentRewriteState.* - val enclosingIndent = minimumIndent - minimumIndent = - if enclosingIndent < in.currentRegion.indentWidth then - in.currentRegion.indentWidth - else if - in.token == CASE && ( - in.currentRegion.enclosing == null || - in.currentRegion.indentWidth == in.currentRegion.enclosing.indentWidth - ) - then enclosingIndent - else enclosingIndent.increment - try body - finally - maximumIndent = Some(minimumIndent) - minimumIndent = enclosingIndent - - /** when rewriting to indent, check that indentaton is correct or patch */ - def patchIndent(): Unit = - if in.isAfterLineEnd && !in.isNewLine && in.token != OUTDENT && in.token != INDENT then - import IndentRewriteState.* - val currentIndent = in.indentWidth(in.offset) - val indentEndOffset = in.lineOffset + currentIndent.size - def isDotOrClosing = (closingParens + DOT).contains(in.token) - val needsOutdent = maximumIndent.exists: max => - currentIndent >= max || (!isDotOrClosing && currentIndent > minimumIndent) - val offByOne = - currentIndent != minimumIndent && currentIndent.isClose(minimumIndent) - if needsOutdent || !(currentIndent >= minimumIndent) || offByOne then - patch(Span(in.lineOffset, indentEndOffset), minimumIndent.toPrefix) - // no need to outdent anymore - if in.token != RBRACE then - maximumIndent = None - - def nextToken(): Unit = - if in.rewriteToIndent then patchIndent() - in.nextToken() - - def skipToken(): Offset = - if in.rewriteToIndent then patchIndent() - in.skipToken() - - def skipToken[T](res: T): T = - if in.rewriteToIndent then patchIndent() - in.skipToken(res) + body /** Drop (...) or { ... }, replacing the closing element with `endStr` */ def dropParensOrBraces(start: Offset, endStr: String): Unit = @@ -838,7 +712,7 @@ object Parsers: val preFill = if (closingStartsLine || endStr.isEmpty) "" else " " val postFill = if (in.lastOffset == in.offset) " " else "" val (startClosing, endClosing) = - if (closingStartsLine && endStr.isEmpty) elimRegion(in.last.offset) + if (closingStartsLine && endStr.isEmpty) elimRegion(in.lastOffset - 1) else (in.lastOffset - 1, in.lastOffset) patch(source, Span(startClosing, endClosing), s"$preFill$endStr$postFill") @@ -1049,7 +923,7 @@ object Parsers: colonAtEOLOpt() newLineOptWhenFollowing(canStartOperand) if isColonLambda then - nextToken() + in.nextToken() recur(expr(Location.InColonArg)) else if maybePostfix && !canStartOperand(in.token) then val topInfo = opStack.head @@ -1082,7 +956,7 @@ object Parsers: report.error( em"""Illegal backquoted identifier: `` and `` are forbidden""", in.sourcePos()) - nextToken() + in.nextToken() name else syntaxErrorOrIncomplete(ExpectedTokenButFound(IDENTIFIER, in.token)) @@ -1118,7 +992,7 @@ object Parsers: /** DotSelectors ::= { `.' id } */ def dotSelectors(t: Tree): Tree = - if (in.token == DOT) { nextToken(); dotSelectors(selector(t)) } + if (in.token == DOT) { in.nextToken(); dotSelectors(selector(t)) } else t private val id: Tree => Tree = x => x @@ -1131,11 +1005,11 @@ object Parsers: val start = in.offset def handleThis(qual: Ident) = - nextToken() + in.nextToken() atSpan(start) { This(qual) } def handleSuper(qual: Ident) = - nextToken() + in.nextToken() val mix = mixinQualifierOpt() val t = atSpan(start) { Super(This(qual), mix) } accept(DOT) @@ -1149,10 +1023,10 @@ object Parsers: def qual = cpy.Ident(t)(t.name.toTypeName) in.lookahead.token match case THIS => - nextToken() + in.nextToken() handleThis(qual) case SUPER => - nextToken() + in.nextToken() handleSuper(qual) case _ => t else t @@ -1187,7 +1061,7 @@ object Parsers: def simpleLiteral(): Tree = if isIdent(nme.raw.MINUS) then val start = in.offset - nextToken() + in.nextToken() literal(negOffset = start, inTypeOrSingleton = true) else literal(inTypeOrSingleton = true) @@ -1238,7 +1112,7 @@ object Parsers: case _ => syntaxErrorOrIncomplete(IllegalLiteral()) atSpan(negOffset) { Literal(Constant(null)) } - nextToken() + in.nextToken() t else atSpan(negOffset): if (in.token == QUOTEID) @@ -1249,7 +1123,7 @@ object Parsers: case TRUE | FALSE | NULL => literalOf(tok) case THIS => This(EmptyTypeIdent) case _ => Ident(in.name) - nextToken() + in.nextToken() Quote(t, Nil) else if !in.featureEnabled(Feature.symbolLiterals) then @@ -1264,11 +1138,11 @@ object Parsers: if migrateTo3 then patch(source, Span(in.offset, in.offset + 1), "Symbol(\"") patch(source, Span(in.charOffset - 1), "\")") - atSpan(skipToken()) { SymbolLit(in.strVal) } + atSpan(in.skipToken()) { SymbolLit(in.strVal) } else if (in.token == INTERPOLATIONID) interpolatedString(inPattern) else val t = literalOf(in.token) - nextToken() + in.nextToken() t private def interpolatedString(inPattern: Boolean = false): Tree = atSpan(in.offset): @@ -1278,7 +1152,7 @@ object Parsers: in.charOffset + 1 < in.buf.length && in.buf(in.charOffset) == '"' && in.buf(in.charOffset + 1) == '"' - nextToken() + in.nextToken() def nextSegment(literalOffset: Offset) = segmentBuf += Thicket( literal(literalOffset, inPattern = inPattern, inStringInterpolation = true), @@ -1286,10 +1160,10 @@ object Parsers: if (in.token == IDENTIFIER) termIdent() else if (in.token == USCORE && inPattern) - nextToken() + in.nextToken() Ident(nme.WILDCARD) else if (in.token == THIS) - nextToken() + in.nextToken() This(EmptyTypeIdent) else if (in.token == LBRACE) if (inPattern) Block(Nil, inBraces(pattern())) @@ -1311,21 +1185,21 @@ object Parsers: /* ------------- NEW LINES ------------------------------------------------- */ def newLineOpt(): Unit = - if in.token == NEWLINE then nextToken() + if in.token == NEWLINE then in.nextToken() def newLinesOpt(): Unit = - if in.isNewLine then nextToken() + if in.isNewLine then in.nextToken() def newLineOptWhenFollowedBy(token: Int): Unit = // note: next is defined here because current == NEWLINE - if in.token == NEWLINE && in.next.token == token then nextToken() + if in.token == NEWLINE && in.next.token == token then in.nextToken() def newLinesOptWhenFollowedBy(token: Int): Unit = - if in.isNewLine && in.next.token == token then nextToken() + if in.isNewLine && in.next.token == token then in.nextToken() def newLinesOptWhenFollowedBy(name: Name): Unit = if in.isNewLine && in.next.token == IDENTIFIER && in.next.name == name then - nextToken() + in.nextToken() def newLineOptWhenFollowing(p: Int => Boolean): Unit = // note: next is defined here because current == NEWLINE @@ -1336,16 +1210,15 @@ object Parsers: syntaxErrorOrIncomplete(em"indented definitions expected, ${in} found") def colonAtEOLOpt(): Unit = - IndentRewriteState.possibleColonOffset = in.lastOffset in.observeColonEOL(inTemplate = false) if in.token == COLONeol then - nextToken() + in.nextToken() acceptIndent() def argumentStart(): Unit = colonAtEOLOpt() if migrateTo3 && in.token == NEWLINE && in.next.token == LBRACE then - nextToken() + in.nextToken() if in.indentWidth(in.offset) == in.currentRegion.indentWidth then report.errorOrMigrationWarning( em"""This opening brace will start a new statement in Scala 3. @@ -1359,7 +1232,7 @@ object Parsers: if in.token == COLONeol then if in.lookahead.token == END then in.token = NEWLINE else - nextToken() + in.nextToken() if in.token != LBRACE then acceptIndent() else newLineOptWhenFollowedBy(LBRACE) @@ -1399,11 +1272,11 @@ object Parsers: didMatch if in.token == END then - val start = skipToken() + val start = in.skipToken() if stats.isEmpty || !matchesAndSetEnd(stats.last) then syntaxError(em"misaligned end marker", Span(start, in.lastCharOffset)) in.token = IDENTIFIER // Leaving it as the original token can confuse newline insertion - nextToken() + in.nextToken() end checkEndMarker /* ------------- TYPES ------------------------------------------------------ */ @@ -1492,10 +1365,10 @@ object Parsers: imods |= Impure if token == CTXARROW then - nextToken() + in.nextToken() imods |= Given else if token == ARROW || token == TLARROW then - nextToken() + in.nextToken() else accept(ARROW) @@ -1519,15 +1392,15 @@ object Parsers: val t = if (in.token == LPAREN) - nextToken() + in.nextToken() if (in.token == RPAREN) - nextToken() + in.nextToken() functionRest(Nil) else val paramStart = in.offset def addErased() = erasedArgs.addOne(isErasedKw) - if isErasedKw then { skipToken(); } + if isErasedKw then { in.skipToken(); } addErased() val ts = in.currentRegion.withCommasExpected: funArgType() match @@ -1566,9 +1439,9 @@ object Parsers: val start = in.offset val tparams = typeParamClause(ParamOwner.TypeParam) if (in.token == TLARROW) - atSpan(start, skipToken())(LambdaTypeTree(tparams, toplevelTyp())) + atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp())) else if (in.token == ARROW || isPureArrow(nme.PUREARROW)) - val arrowOffset = skipToken() + val arrowOffset = in.skipToken() val body = toplevelTyp() atSpan(start, arrowOffset): getFunction(body) match @@ -1679,7 +1552,7 @@ object Parsers: }) else if Feature.ccEnabled && in.isIdent(nme.UPARROW) && isCaptureUpArrow then val upArrowStart = in.offset - nextToken() + in.nextToken() def cs = if in.token == LBRACE then captureSet() else atSpan(upArrowStart)(captureRoot) :: Nil @@ -1694,7 +1567,7 @@ object Parsers: def withTypeRest(t: Tree): Tree = if in.token == WITH then val withOffset = in.offset - nextToken() + in.nextToken() if in.token == LBRACE || in.token == INDENT then t else @@ -1730,12 +1603,11 @@ object Parsers: val inPattern = (staged & StageKind.QuotedPattern) != 0 val expr = if (in.name.length == 1) - nextToken() - val inPattern = (staged & StageKind.QuotedPattern) != 0 + in.nextToken() withinStaged(StageKind.Spliced)(if (inPattern) inBraces(pattern()) else stagedBlock()) else atSpan(in.offset + 1): val id = Ident(in.name.drop(1)) - nextToken() + in.nextToken() id if isType then val msg = "Type splicing with `$` in quotes not supported anymore" @@ -1761,23 +1633,23 @@ object Parsers: SingletonTypeTree(simpleLiteral()) else if in.token == USCORE then if ctx.settings.YkindProjector.value == "underscores" then - val start = skipToken() + val start = in.skipToken() Ident(tpnme.USCOREkw).withSpan(Span(start, in.lastOffset, start)) else if sourceVersion.isAtLeast(future) then deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead") patch(source, Span(in.offset, in.offset + 1), "?") - val start = skipToken() + val start = in.skipToken() typeBounds().withSpan(Span(start, in.lastOffset, start)) // Allow symbols -_ and +_ through for compatibility with code written using kind-projector in Scala 3 underscore mode. // While these signify variant type parameters in Scala 2 + kind-projector, we ignore their variance markers since variance is inferred. else if (isIdent(nme.MINUS) || isIdent(nme.PLUS)) && in.lookahead.token == USCORE && ctx.settings.YkindProjector.value == "underscores" then val identName = in.name.toTypeName ++ nme.USCOREkw - val start = skipToken() - nextToken() + val start = in.skipToken() + in.nextToken() Ident(identName).withSpan(Span(start, in.lastOffset, start)) else if isIdent(nme.?) then - val start = skipToken() + val start = in.skipToken() typeBounds().withSpan(Span(start, in.lastOffset, start)) else def singletonArgs(t: Tree): Tree = @@ -1806,9 +1678,9 @@ object Parsers: else def singletonCompletion(t: Tree): Tree = if in.token == DOT then - nextToken() + in.nextToken() if in.token == TYPE then - nextToken() + in.nextToken() atSpan(startOffset(t)) { SingletonTypeTree(t) } else singletonCompletion(selector(t)) @@ -1885,7 +1757,7 @@ object Parsers: in.currentRegion.withCommasExpected: argType() match case Ident(name) if in.token == EQUALS => - nextToken() + in.nextToken() commaSeparatedRest(NamedArg(name, argType()), () => namedTypeArg()) case firstArg => commaSeparatedRest(firstArg, () => argType()) @@ -1894,7 +1766,7 @@ object Parsers: def paramTypeOf(core: () => Tree): Tree = if in.token == ARROW || isPureArrow(nme.PUREARROW) then val isImpure = in.token == ARROW - atSpan(skipToken()): + atSpan(in.skipToken()): val tp = if isImpure then core() else capturesAndResult(core) if isImpure && Feature.pureFunsEnabled then ImpureByNameTypeTree(tp) else ByNameTypeTree(tp) @@ -1905,7 +1777,7 @@ object Parsers: if in.isIdent(nme.into) && in.featureEnabled(Feature.into) && canStartTypeTokens.contains(in.lookahead.token) - then atSpan(skipToken()) { Into(tp()) } + then atSpan(in.skipToken()) { Into(tp()) } else tp() /** FunArgType ::= Type @@ -1925,7 +1797,7 @@ object Parsers: def paramValueType(): Tree = val t = maybeInto(toplevelTyp) if (isIdent(nme.raw.STAR)) - nextToken() + in.nextToken() atSpan(startOffset(t)) { PostfixOp(t, Ident(tpnme.raw.STAR)) } else t @@ -1948,7 +1820,7 @@ object Parsers: atSpan(in.offset) { TypeBoundsTree(bound(SUPERTYPE), bound(SUBTYPE)) } private def bound(tok: Int): Tree = - if (in.token == tok) { nextToken(); toplevelTyp() } + if (in.token == tok) { in.nextToken(); toplevelTyp() } else EmptyTree /** TypeParamBounds ::= TypeBounds {`<%' Type} {`:' Type} @@ -1961,21 +1833,21 @@ object Parsers: def contextBounds(pname: TypeName): List[Tree] = if in.isColon then - atSpan(skipToken()) { + atSpan(in.skipToken()) { AppliedTypeTree(toplevelTyp(), Ident(pname)) } :: contextBounds(pname) else if in.token == VIEWBOUND then report.errorOrMigrationWarning( em"view bounds `<%' are no longer supported, use a context bound `:' instead", in.sourcePos(), from = `3.0`) - atSpan(skipToken()) { + atSpan(in.skipToken()) { Function(Ident(pname) :: Nil, toplevelTyp()) } :: contextBounds(pname) else Nil def typedOpt(): Tree = - if in.isColon then { nextToken(); toplevelTyp() } + if in.isColon then { in.nextToken(); toplevelTyp() } else TypeTree().withSpan(Span(in.lastOffset)) def typeDependingOn(location: Location): Tree = @@ -2062,7 +1934,7 @@ object Parsers: def subExpr() = subPart(expr) - def expr(location: Location, inStatSeq: Boolean = false): Tree = + def expr(location: Location): Tree = val start = in.offset in.token match case IMPLICIT => @@ -2089,7 +1961,7 @@ object Parsers: else new WildcardFunction(placeholderParams.reverse, t) finally placeholderParams = saved - val t = expr1(location, inStatSeq) + val t = expr1(location) if in.isArrow then placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder wrapPlaceholders(closureRest(start, location, convertToParams(t))) @@ -2100,11 +1972,11 @@ object Parsers: checkNonParamTuple(t) wrapPlaceholders(t) - def expr1(location: Location = Location.ElseWhere, inStatSeq: Boolean = false): Tree = in.token match + def expr1(location: Location = Location.ElseWhere): Tree = in.token match case IF => ifExpr(in.offset, If) case WHILE => - atSpan(skipToken()): + atSpan(in.skipToken()): val cond = condExpr(DO) newLinesOpt() val body = subExpr() @@ -2114,10 +1986,10 @@ object Parsers: em"""`do while ` is no longer supported, |use `while ; do ()` instead.${rewriteNotice()}""", in.sourcePos(), from = `3.0`) - val start = skipToken() + val start = in.skipToken() atSpan(start): val body = expr() - if (isStatSep) nextToken() + if (isStatSep) in.nextToken() val whileStart = in.offset accept(WHILE) val cond = expr() @@ -2133,12 +2005,12 @@ object Parsers: WhileDo(Block(body, cond), Literal(Constant(()))) case TRY => val tryOffset = in.offset - atSpan(skipToken()): + atSpan(in.skipToken()): val body = expr() val (handler, handlerStart) = if in.token == CATCH then val span = in.offset - nextToken() + in.nextToken() (if in.token == CASE then Match(EmptyTree, caseClause(exprOnly = true) :: Nil) else subExpr(), span) @@ -2155,7 +2027,7 @@ object Parsers: val finalizer = if (in.token == FINALLY) - nextToken(); + in.nextToken(); val expr = subExpr() if expr.span.exists then expr else Literal(Constant(())) // finally without an expression @@ -2168,9 +2040,9 @@ object Parsers: EmptyTree ParsedTry(body, handler, finalizer) case THROW => - atSpan(skipToken()) { Throw(expr()) } + atSpan(in.skipToken()) { Throw(expr()) } case RETURN => - atSpan(skipToken()): + atSpan(in.skipToken()): Return(if (isExprIntro) expr() else EmptyTree, EmptyTree) case FOR => forExpr() @@ -2179,7 +2051,7 @@ object Parsers: && !in.inModifierPosition() && in.canStartExprTokens.contains(in.lookahead.token) then - val start = skipToken() + val start = in.skipToken() in.token match case IF => ifExpr(start, InlineIf) @@ -2190,20 +2062,20 @@ object Parsers: case t => syntaxError(em"`inline` must be followed by an `if` or a `match`", start) t - else expr1Rest(postfixExpr(location, inStatSeq), location) + else expr1Rest(postfixExpr(location), location) end expr1 def expr1Rest(t: Tree, location: Location): Tree = if in.token == EQUALS then t match case Ident(_) | Select(_, _) | Apply(_, _) | PrefixOp(_, _) => - atSpan(startOffset(t), skipToken()): + atSpan(startOffset(t), in.skipToken()): val loc = if location.inArgs then location else Location.ElseWhere Assign(t, subPart(() => expr(loc))) case _ => t else if in.isColon then - nextToken() + in.nextToken() ascription(t, location) else t @@ -2211,9 +2083,9 @@ object Parsers: def ascription(t: Tree, location: Location): Tree = atSpan(startOffset(t)): in.token match case USCORE if in.lookahead.isIdent(nme.raw.STAR) => - val uscoreStart = skipToken() + val uscoreStart = in.skipToken() val isVarargSplice = location.inArgs && followingIsVararg() - nextToken() + in.nextToken() if isVarargSplice then report.errorOrMigrationWarning( em"The syntax `x: _*` is no longer supported for vararg splices; use `x*` instead${rewriteNotice(`future-migration`)}", @@ -2243,18 +2115,18 @@ object Parsers: * `if' Expr `then' Expr [[semi] else Expr] */ def ifExpr(start: Offset, mkIf: (Tree, Tree, Tree) => If): If = - atSpan(start, skipToken()): + atSpan(start, in.skipToken()): val cond = condExpr(THEN) newLinesOpt() val thenp = subExpr() - val elsep = if (in.token == ELSE) { nextToken(); subExpr() } + val elsep = if (in.token == ELSE) { in.nextToken(); subExpr() } else EmptyTree mkIf(cond, thenp, elsep) /** MatchClause ::= `match' `{' CaseClauses `}' */ def matchClause(t: Tree): Match = - atSpan(startOffset(t), skipToken()): + atSpan(startOffset(t), in.skipToken()): Match(t, inBracesOrIndented(caseClauses(() => caseClause()))) /** `match' `{' TypeCaseClauses `}' @@ -2270,7 +2142,7 @@ object Parsers: */ def funParams(mods: Modifiers, location: Location): List[Tree] = if in.token == LPAREN then - nextToken() + in.nextToken() if in.token == RPAREN then Nil else @@ -2287,7 +2159,7 @@ object Parsers: em"This syntax is no longer supported; parameter needs to be enclosed in (...)${rewriteNotice(`future-migration`)}", source.atSpan(Span(start, in.lastOffset)), from = future) - nextToken() + in.nextToken() val t = infixType() if (sourceVersion == `future-migration`) patch(source, Span(start), "(") @@ -2305,7 +2177,7 @@ object Parsers: def bindingName(): TermName = if (in.token == USCORE) - nextToken() + in.nextToken() WildcardParamName.fresh() else ident() @@ -2320,7 +2192,7 @@ object Parsers: if in.token == CTXARROW then if params.isEmpty then syntaxError(em"context function literals require at least one formal parameter", Span(start, in.lastOffset)) - nextToken() + in.nextToken() else accept(ARROW) val body = indentedRegionAfterArrow: @@ -2335,10 +2207,10 @@ object Parsers: * | InfixExpr id ColonArgument * | InfixExpr MatchClause */ - def postfixExpr(location: Location = Location.ElseWhere, inStatSeq: Boolean = false): Tree = - val t = postfixExprRest(prefixExpr(location, inStatSeq), location) + def postfixExpr(location: Location = Location.ElseWhere): Tree = + val t = postfixExprRest(prefixExpr(location), location) if location.inArgs && followingIsVararg() then - Typed(t, atSpan(skipToken()) { Ident(tpnme.WILDCARD_STAR) }) + Typed(t, atSpan(in.skipToken()) { Ident(tpnme.WILDCARD_STAR) }) else t @@ -2349,7 +2221,7 @@ object Parsers: /** PrefixExpr ::= [PrefixOperator'] SimpleExpr * PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ (if not backquoted) */ - def prefixExpr(location: Location, inStatSeq: Boolean = false): Tree = + val prefixExpr: Location => Tree = location => if in.token == IDENTIFIER && nme.raw.isUnary(in.name) && in.canStartExprTokens.contains(in.lookahead.token) then @@ -2359,7 +2231,7 @@ object Parsers: simpleExprRest(literal(start), location, canApply = true) else atSpan(start) { PrefixOp(op, simpleExpr(location)) } - else simpleExpr(location, inStatSeq) + else simpleExpr(location) /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody] * | ‘new’ TemplateBody @@ -2385,7 +2257,7 @@ object Parsers: * Quoted ::= ‘'’ ‘{’ Block ‘}’ * | ‘'’ ‘[’ Type ‘]’ */ - def simpleExpr(location: Location, inStatSeq: Boolean = false): Tree = + def simpleExpr(location: Location): Tree = var canApply = true val t = in.token match case XMLSTART => @@ -2396,7 +2268,7 @@ object Parsers: case BACKQUOTED_IDENT | THIS | SUPER => simpleRef() case USCORE => - val start = skipToken() + val start = in.skipToken() val pname = WildcardParamName.fresh() val param = ValDef(pname, TypeTree(), EmptyTree).withFlags(SyntheticTermParam) .withSpan(Span(start)) @@ -2406,9 +2278,9 @@ object Parsers: atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOrBindings())) } case LBRACE | INDENT => canApply = false - blockExpr(inStatSeq) + blockExpr() case QUOTE => - atSpan(skipToken()): + atSpan(in.skipToken()): withinStaged(StageKind.Quoted | (if (location.inPattern) StageKind.QuotedPattern else 0)): val body = if (in.token == LBRACKET) inBrackets(typ()) @@ -2418,14 +2290,14 @@ object Parsers: canApply = false newExpr() case MACRO => - val start = skipToken() + val start = in.skipToken() MacroTree(simpleExpr(Location.ElseWhere)) case _ => if isLiteral then literal() else if in.isColon then syntaxError(IllegalStartSimpleExpr(tokenString(in.token))) - nextToken() + in.nextToken() simpleExpr(location) else val start = in.lastOffset @@ -2437,7 +2309,7 @@ object Parsers: if (canApply) argumentStart() in.token match case DOT => - nextToken() + in.nextToken() simpleExprRest(selectorOrMatch(t), location, canApply = true) case LBRACKET => val tapp = atSpan(startOffset(t), in.offset) { TypeApply(t, typeArgs(namedOK = true, wildOK = false)) } @@ -2446,7 +2318,7 @@ object Parsers: val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) } simpleExprRest(app, location, canApply = true) case USCORE => - atSpan(startOffset(t), skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) } + atSpan(startOffset(t), in.skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) } case _ => if in.isColon && location == Location.InParens && followingIsLambdaParams() then t match @@ -2458,7 +2330,7 @@ object Parsers: makeParameter(name.asTermName, typedOpt(), Modifiers(), isBackquoted = isBackquoted(id)) case _ => t else if isColonLambda then - val app = atSpan(startOffset(t), skipToken()): + val app = atSpan(startOffset(t), in.skipToken()): Apply(t, expr(Location.InColonArg) :: Nil) simpleExprRest(app, location, canApply = true) else t @@ -2468,7 +2340,7 @@ object Parsers: * | ‘new’ TemplateBody */ def newExpr(): Tree = - val start = skipToken() + val start = in.skipToken() def reposition(t: Tree) = t.withSpan(Span(start, in.lastOffset)) possibleTemplateStart() val parents = @@ -2504,7 +2376,7 @@ object Parsers: if in.token == RPAREN then (Nil, false) else if isIdent(nme.using) then - nextToken() + in.nextToken() (commaSeparated(argumentExpr), true) else (commaSeparated(argumentExpr), false) @@ -2557,12 +2429,12 @@ object Parsers: /** BlockExpr ::= <<< (CaseClauses | Block) >>> */ - def blockExpr(inStatSeq: Boolean = false): Tree = atSpan(in.offset): + def blockExpr(): Tree = atSpan(in.offset): val simplify = in.token == INDENT inDefScopeBraces({ if (in.token == CASE) Match(EmptyTree, caseClauses(() => caseClause())) else block(simplify) - }, inStatSeq = inStatSeq) + }) /** Block ::= BlockStatSeq * @note Return tree does not have a defined span. @@ -2580,7 +2452,7 @@ object Parsers: /** Guard ::= if PostfixExpr */ def guard(): Tree = - if (in.token == IF) { nextToken(); postfixExpr(Location.InGuard) } + if (in.token == IF) { in.nextToken(); postfixExpr(Location.InGuard) } else EmptyTree /** Enumerators ::= Generator {semi Enumerator | Guard} @@ -2589,7 +2461,7 @@ object Parsers: def enumeratorsRest(): List[Tree] = if (isStatSep) - nextToken() + in.nextToken() if (in.token == DO || in.token == YIELD || in.token == RBRACE) Nil else enumerator() :: enumeratorsRest() else if (in.token == IF) @@ -2605,13 +2477,13 @@ object Parsers: else if (in.token == CASE) generator() else val pat = pattern1() - if (in.token == EQUALS) atSpan(startOffset(pat), skipToken()) { GenAlias(pat, subExpr()) } + if (in.token == EQUALS) atSpan(startOffset(pat), in.skipToken()) { GenAlias(pat, subExpr()) } else generatorRest(pat, casePat = false) /** Generator ::= [‘case’] Pattern `<-' Expr */ def generator(): Tree = - val casePat = if (in.token == CASE) { nextToken(); true } else false + val casePat = if (in.token == CASE) { in.nextToken(); true } else false generatorRest(pattern1(), casePat) def generatorRest(pat: Tree, casePat: Boolean): GenFrom = @@ -2628,14 +2500,14 @@ object Parsers: * | ‘for’ Enumerators (‘do‘ | ‘yield’) Expr */ def forExpr(): Tree = - atSpan(skipToken()): + atSpan(in.skipToken()): var wrappedEnums = true val start = in.offset val forEnd = in.lastOffset val leading = in.token val enums = if (leading == LBRACE || leading == LPAREN && followingIsEnclosedGenerators()) - nextToken() + in.nextToken() val res = if (leading == LBRACE || in.token == CASE) enumerators() @@ -2679,11 +2551,11 @@ object Parsers: ts newLinesOpt() if (in.token == YIELD) - nextToken() + in.nextToken() ForYield(enums, subExpr()) else if (in.token == DO) if (rewriteToOldSyntax()) dropTerminator() - nextToken() + in.nextToken() ForDo(enums, subExpr()) else if (!wrappedEnums) syntaxErrorOrIncomplete(YieldOrDoExpectedInForComprehension()) @@ -2725,13 +2597,13 @@ object Parsers: accept(CASE) in.token match case USCORE if in.lookahead.isArrow => - val start = skipToken() + val start = in.skipToken() Ident(tpnme.WILDCARD).withSpan(Span(start, in.lastOffset, start)) case _ => rejectWildcardType(infixType()) CaseDef(pat, EmptyTree, atSpan(accept(ARROW)) { val t = indentedRegionAfterArrow(rejectWildcardType(typ()), inCaseDef = true) - if in.token == SEMI then nextToken() + if in.token == SEMI then in.nextToken() newLinesOptWhenFollowedBy(CASE) t }) @@ -2747,7 +2619,7 @@ object Parsers: else pat def patternAlts(location: Location): List[Tree] = - if (isIdent(nme.raw.BAR)) { nextToken(); pattern1(location) :: patternAlts(location) } + if (isIdent(nme.raw.BAR)) { in.nextToken(); pattern1(location) :: patternAlts(location) } else Nil /** Pattern1 ::= PatVar Ascription @@ -2769,7 +2641,7 @@ object Parsers: warnFrom = `3.3`, errorFrom = future ) - nextToken() + in.nextToken() ascription(p, location) else p @@ -2779,7 +2651,7 @@ object Parsers: def pattern3(): Tree = val p = infixPattern() if followingIsVararg() then - val start = skipToken() + val start = in.skipToken() p match case p @ Ident(name) if name.isVarPattern => Typed(p, atSpan(start) { Ident(tpnme.WILDCARD_STAR) }) @@ -2792,7 +2664,7 @@ object Parsers: */ val pattern2: () => Tree = () => pattern3() match case p @ Ident(name) if in.token == AT => - val offset = skipToken() + val offset = in.skipToken() pattern3() match case pt @ Bind(nme.WILDCARD, pt1: Typed) if pt.mods.is(Given) => atSpan(startOffset(p), 0) { Bind(name, pt1).withMods(pt.mods) } @@ -2842,7 +2714,7 @@ object Parsers: xmlLiteralPattern() case GIVEN => atSpan(in.offset): - val givenMod = atSpan(skipToken())(Mod.Given()) + val givenMod = atSpan(in.skipToken())(Mod.Given()) val typed = Typed(Ident(nme.WILDCARD), refinedType()) Bind(nme.WILDCARD, typed).withMods(addMod(Modifiers(), givenMod)) case _ => @@ -2856,7 +2728,7 @@ object Parsers: def simplePatternRest(t: Tree): Tree = if in.token == DOT then - nextToken() + in.nextToken() simplePatternRest(selector(t)) else var p = t @@ -2915,7 +2787,7 @@ object Parsers: private def addModifier(mods: Modifiers): Modifiers = val tok = in.token val name = in.name - val mod = atSpan(skipToken()) { modOfToken(tok, name) } + val mod = atSpan(in.skipToken()) { modOfToken(tok, name) } if (mods.isOneOf(mod.flags)) syntaxError(RepeatedModifier(mod.flags.flagsString)) addMod(mods, mod) @@ -2939,7 +2811,7 @@ object Parsers: if sourceVersion.isAtLeast(future) then deprecationWarning( em"The [this] qualifier will be deprecated in the future; it should be dropped.") - nextToken() + in.nextToken() mods | Local else mods.withPrivateWithin(ident().toTypeName) else mods @@ -2966,7 +2838,7 @@ object Parsers: val mods1 = addModifier(mods) loop(if (isAccessMod) accessQualifierOpt(mods1) else mods1) else if (in.isNewLine && (mods.hasFlags || mods.hasAnnotations)) - nextToken() + in.nextToken() loop(mods) else mods @@ -3060,7 +2932,7 @@ object Parsers: def checkVarianceOK(): Boolean = val ok = ownerKind != ParamOwner.Def && ownerKind != ParamOwner.TypeParam if !ok then syntaxError(em"no `+/-` variance annotation allowed here") - nextToken() + in.nextToken() ok def typeParam(): TypeDef = @@ -3071,7 +2943,7 @@ object Parsers: if Feature.ccEnabled && in.token == SEALED then if ownerKind == ParamOwner.Def then mods |= Sealed else syntaxError(em"`sealed` modifier only allowed for method type parameters") - nextToken() + in.nextToken() if isIdent(nme.raw.PLUS) && checkVarianceOK() then mods |= Covariant else if isIdent(nme.raw.MINUS) && checkVarianceOK() then @@ -3079,7 +2951,7 @@ object Parsers: atSpan(start, nameStart): val name = if (isAbstractOwner && in.token == USCORE) - nextToken() + in.nextToken() WildcardParamName.fresh().toTypeName else ident().toTypeName val hkparams = typeParamClauseOpt(ParamOwner.Type) @@ -3127,7 +2999,7 @@ object Parsers: ): List[ValDef] = var impliedMods: Modifiers = EmptyModifiers - def addParamMod(mod: () => Mod) = impliedMods = addMod(impliedMods, atSpan(skipToken()) { mod() }) + def addParamMod(mod: () => Mod) = impliedMods = addMod(impliedMods, atSpan(in.skipToken()) { mod() }) def paramMods() = if in.token == IMPLICIT then @@ -3145,10 +3017,10 @@ object Parsers: mods = addFlag(modifiers(start = mods), ParamAccessor) mods = if in.token == VAL then - nextToken() + in.nextToken() mods else if in.token == VAR then - val mod = atSpan(skipToken()) { Mod.Var() } + val mod = atSpan(in.skipToken()) { Mod.Var() } addMod(mods, mod) else if (!(mods.flags &~ (ParamAccessor | Inline | Erased | impliedMods.flags)).isEmpty) @@ -3167,7 +3039,7 @@ object Parsers: // needed?, it's checked later anyway val tpt = paramType() val default = - if (in.token == EQUALS) { nextToken(); subExpr() } + if (in.token == EQUALS) { in.nextToken(); subExpr() } else EmptyTree if (impliedMods.mods.nonEmpty) impliedMods = impliedMods.withMods(Nil) // keep only flags, so that parameter positions don't overlap @@ -3318,12 +3190,12 @@ object Parsers: in.sourcePos(), from = future) patch(source, Span(in.offset, in.offset + 1), "*") - ImportSelector(atSpan(skipToken()) { Ident(nme.WILDCARD) }) + ImportSelector(atSpan(in.skipToken()) { Ident(nme.WILDCARD) }) /** 'given [InfixType]' */ def givenSelector() = ImportSelector( - atSpan(skipToken()) { Ident(nme.EMPTY) }, + atSpan(in.skipToken()) { Ident(nme.EMPTY) }, bound = if canStartInfixTypeTokens.contains(in.token) then rejectWildcardType(infixType()) else EmptyTree) @@ -3339,7 +3211,7 @@ object Parsers: patch(source, Span(in.offset, in.offset + 2), if testChar(in.offset - 1, ' ') && testChar(in.offset + 2, ' ') then "as" else " as ") - atSpan(startOffset(from), skipToken()): + atSpan(startOffset(from), in.skipToken()): val to = if in.token == USCORE then wildcardIdent() else termIdent() ImportSelector(from, if to.name == nme.ERROR then EmptyTree else to) else ImportSelector(from) @@ -3408,16 +3280,16 @@ object Parsers: */ def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match case VAL => - nextToken() + in.nextToken() patDefOrDcl(start, mods) case VAR => - val mod = atSpan(skipToken()) { Mod.Var() } + val mod = atSpan(in.skipToken()) { Mod.Var() } val mod1 = addMod(mods, mod) patDefOrDcl(start, mod1) case DEF => - defDefOrDcl(start, skipToken(mods)) + defDefOrDcl(start, in.skipToken(mods)) case TYPE => - typeDefOrDcl(start, skipToken(mods)) + typeDefOrDcl(start, in.skipToken(mods)) case CASE if inEnum => enumCase(start, mods) case _ => @@ -3434,7 +3306,7 @@ object Parsers: val first = pattern2() var lhs = first match case id: Ident if in.token == COMMA => - nextToken() + in.nextToken() id :: commaSeparated(() => termIdent()) case _ => first :: Nil @@ -3497,7 +3369,7 @@ object Parsers: false if (in.token == THIS) - nextToken() + in.nextToken() val vparamss = termParamClauses(numLeadParams = numLeadParams) if (vparamss.isEmpty || vparamss.head.take(1).exists(_.mods.isOneOf(GivenOrImplicit))) in.token match @@ -3528,7 +3400,7 @@ object Parsers: if (migrateTo3) newLineOptWhenFollowedBy(LBRACE) val rhs = if in.token == EQUALS then - nextToken() + in.nextToken() subExpr() else if !tpt.isEmpty then EmptyTree @@ -3553,11 +3425,8 @@ object Parsers: atSpan(in.offset): inBracesOrIndented: val stats = selfInvocation() :: ( - if isStatSep then - nextToken() - blockStatSeq() - else Nil - ) + if (isStatSep) { in.nextToken(); blockStatSeq() } + else Nil) Block(stats, Literal(Constant(()))) else Block(selfInvocation() :: Nil, Literal(Constant(()))) @@ -3584,12 +3453,12 @@ object Parsers: finalizeDef(tdef, mods, start) in.token match case EQUALS => - nextToken() + in.nextToken() makeTypeDef(toplevelTyp()) case SUBTYPE | SUPERTYPE => val bounds = typeBounds() if (in.token == EQUALS) - val eqOffset = skipToken() + val eqOffset = in.skipToken() var rhs = toplevelTyp() rhs match case mtt: MatchTypeTree => @@ -3619,19 +3488,19 @@ object Parsers: def tmplDef(start: Int, mods: Modifiers): Tree = in.token match case TRAIT => - classDef(start, skipToken(addFlag(mods, Trait))) + classDef(start, in.skipToken(addFlag(mods, Trait))) case CLASS => - classDef(start, skipToken(mods)) + classDef(start, in.skipToken(mods)) case CASECLASS => - classDef(start, skipToken(mods | Case)) + classDef(start, in.skipToken(mods | Case)) case OBJECT => - objectDef(start, skipToken(mods | Module)) + objectDef(start, in.skipToken(mods | Module)) case CASEOBJECT => - objectDef(start, skipToken(mods | Case | Module)) + objectDef(start, in.skipToken(mods | Case | Module)) case ENUM => - enumDef(start, skipToken(mods | Enum)) + enumDef(start, in.skipToken(mods | Enum)) case GIVEN => - givenDef(start, mods, atSpan(skipToken()) { Mod.Given() }) + givenDef(start, mods, atSpan(in.skipToken()) { Mod.Given() }) case _ => val start = in.lastOffset syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition()) @@ -3695,7 +3564,7 @@ object Parsers: atSpan(start, nameStart): val id = termIdent() if (in.token == COMMA) - nextToken() + in.nextToken() val ids = commaSeparated(() => termIdent()) PatDef(mods1, id :: ids, TypeTree(), EmptyTree) else @@ -3712,7 +3581,7 @@ object Parsers: def caseTemplate(constr: DefDef): Template = val parents = if (in.token == EXTENDS) - nextToken() + in.nextToken() constrApps() else Nil Template(constr, parents, Nil, EmptyValDef, Nil) @@ -3784,7 +3653,7 @@ object Parsers: * {UsingParamClause} ExtMethods */ def extension(): ExtMethods = - val start = skipToken() + val start = in.skipToken() val tparams = typeParamClauseOpt(ParamOwner.Def) val leadParamss = ListBuffer[List[ValDef]]() def numLeadParams = leadParamss.map(_.length).sum @@ -3796,7 +3665,7 @@ object Parsers: leadParamss ++= termParamClauses(givenOnly = true, numLeadParams = numLeadParams) if in.isColon then syntaxError(em"no `:` expected here") - nextToken() + in.nextToken() val methods: List[Tree] = if in.token == EXPORT then exportClause() @@ -3859,7 +3728,7 @@ object Parsers: val ts = val tok = in.token if (tok == WITH || tok == COMMA) && tok != exclude then - nextToken() + in.nextToken() constrApps(exclude = if tok == WITH then COMMA else WITH) else Nil t :: ts @@ -3871,7 +3740,7 @@ object Parsers: val la = in.lookahead la.isAfterLineEnd || la.token == LBRACE if in.token == WITH && !isTemplateStart then - nextToken() + in.nextToken() constrApp() :: withConstrApps() else Nil @@ -3881,7 +3750,7 @@ object Parsers: def template(constr: DefDef, isEnum: Boolean = false): Template = val parents = if (in.token == EXTENDS) - nextToken() + in.nextToken() if (in.token == LBRACE || in.token == COLONeol) report.errorOrMigrationWarning( em"`extends` must be followed by at least one parent", @@ -3892,7 +3761,7 @@ object Parsers: newLinesOptWhenFollowedBy(nme.derives) val derived = if (isIdent(nme.derives)) - nextToken() + in.nextToken() commaSeparated(() => convertToTypeId(qualId())) else Nil possibleTemplateStart() @@ -3929,10 +3798,10 @@ object Parsers: Template(constr, parents, derived, self, stats) def templateBody(parents: List[Tree], rewriteWithColon: Boolean = true): (ValDef, List[Tree]) = - val r = inDefScopeBraces(templateStatSeq(), rewriteWithColon = rewriteWithColon) + val r = inDefScopeBraces(templateStatSeq(), rewriteWithColon) if in.token == WITH && parents.isEmpty then syntaxError(EarlyDefinitionsNotSupported()) - nextToken() + in.nextToken() template(emptyConstructor) r @@ -3971,9 +3840,9 @@ object Parsers: while var empty = false if (in.token == PACKAGE) - val start = skipToken() + val start = in.skipToken() if (in.token == OBJECT) - nextToken() + in.nextToken() stats += objectDef(start, Modifiers(Package)) else stats += packaging(start) else if (in.token == IMPORT) @@ -4001,19 +3870,19 @@ object Parsers: atSpan(in.offset): val selfName = if in.token == THIS then - nextToken() + in.nextToken() nme.WILDCARD else ident() val selfTpt = if in.isColon then - nextToken() + in.nextToken() infixType() else if selfName == nme.WILDCARD then accept(COLONfollow) TypeTree() if in.token == ARROW then in.token = SELFARROW // suppresses INDENT insertion after `=>` - nextToken() + in.nextToken() else syntaxError(em"`=>` expected after self type") makeSelfDef(selfName, selfTpt) @@ -4046,7 +3915,7 @@ object Parsers: else if (isDefIntro(modifierTokensOrCase)) stats +++= defOrDcl(in.offset, defAnnotsMods(modifierTokens)) else if (isExprIntro) - stats += expr1(inStatSeq = true) + stats += expr1() else empty = true statSepOrEnd(stats, noPrevStat = empty) @@ -4120,7 +3989,7 @@ object Parsers: if (in.token == IMPORT) stats ++= importClause() else if (isExprIntro) - stats += expr(Location.InBlock, inStatSeq = true) + stats += expr(Location.InBlock) else if in.token == IMPLICIT && !in.inModifierPosition() then stats += closure(in.offset, Location.InBlock, modifiers(BitSet(IMPLICIT))) else if isIdent(nme.extension) && followingIsExtension() then @@ -4138,12 +4007,12 @@ object Parsers: def compilationUnit(): Tree = checkNoEscapingPlaceholders: def topstats(): List[Tree] = val ts = new ListBuffer[Tree] - while (in.token == SEMI) nextToken() + while (in.token == SEMI) in.nextToken() val start = in.offset if (in.token == PACKAGE) - nextToken() + in.nextToken() if (in.token == OBJECT) - nextToken() + in.nextToken() ts += objectDef(start, Modifiers(Package)) if (in.token != EOF) statSepOrEnd(ts, what = "toplevel definition") @@ -4181,10 +4050,140 @@ object Parsers: def skipBracesHook(): Option[Tree] = if (in.token == XMLSTART) Some(xmlLiteral()) else None - override def blockExpr(inStatSeq: Boolean): Tree = + override def blockExpr(): Tree = skipBraces() EmptyTree override def templateBody(parents: List[Tree], rewriteWithColon: Boolean): (ValDef, List[Thicket]) = skipBraces() (EmptyValDef, List(EmptyTree)) + + /** The Scala parser that can rewrite to indent */ + private class ToIndentParser(source: SourceFile)(using Context) extends Parser(source): + + override def createScanner(): Scanner = new Scanner(source): + override def nextToken(): Unit = + if token != EMPTY then patchIndent() + prev = saveCopy + super.nextToken() + + assert(in.rewriteToIndent) + + private var prev: TokenData = Scanners.newTokenData + + /** The last offset where a colon at the end of line would be required if a subsequent { ... } + * block would be converted to an indentation region. */ + private var possibleColonOffset: Int = -1 + + /** the minimum indent width to rewrite to */ + private var minimumIndent: IndentWidth = IndentWidth.Zero + + /** the maximum indent width to ensure an indent region is properly closed by outdentation */ + private var maximumIndent: Option[IndentWidth] = None + + override def colonAtEOLOpt(): Unit = + possibleColonOffset = in.lastOffset + super.colonAtEOLOpt() + + /** make sure there is an indent after a `=>\n` */ + override def indentedRegionAfterArrow[T](body: => T, inCaseDef: Boolean = false): T = + if in.rewriteToIndent && (inCaseDef || in.isAfterLineEnd) then toIndentedRegion(body) + else body + + override def inBracesOrIndented[T](body: => T, rewriteWithColon: Boolean = false): T = + if in.token == INDENT then + if isAfterArrow then enclosed(INDENT, body) + else enclosed(INDENT, toIndentedRegion(body)) + else + if isAfterArrow then enclosed(LBRACE, toIndentedRegion(body)) + else bracesToIndented(body, rewriteWithColon) + + private val bracesToIndentPredecessors = + colonEOLPredecessors | canStartIndentTokens | BitSet(IDENTIFIER) + + /** Parse brace-enclosed `body` and rewrite it to be an indentation region instead, if possible. + * If possible means: + * 1. not inside (...), [...], case ... => + * 2. opening brace `{` is at end of line + * 3. closing brace `}` is at start of line + * 4. there is at least one token between the braces + * 5. the closing brace is also at the end of the line, or it is followed by one of + * `then`, `else`, `do`, `catch`, `finally`, `yield`, or `match`. + * 6. the opening brace `}` follows a colonEOLPredecessors, a canStartIndentTokens or an + * identifier + * 7. last token is not a leading operator + */ + private def bracesToIndented[T](body: => T, rewriteWithColon: Boolean): T = + val prevSaved = prev.saveCopy + val lastOffsetSaved = in.lastOffset + val underColonSyntax = possibleColonOffset == in.lastOffset + val colonRequired = rewriteWithColon || underColonSyntax + val (startOpening, endOpening) = elimRegion(in.offset) + def isBracesOrIndented(r: Region): Boolean = r match + case r: (Indented | InBraces) => true + case _ => false + var canRewrite = + isBracesOrIndented(in.currentRegion) // test (1) + && bracesToIndentPredecessors.contains(prevSaved.token) // test (6) + && !(prevSaved.isOperator && prevSaved.isAfterLineEnd) // test (7) + val t = enclosed(LBRACE, { + if in.isAfterLineEnd && in.token != RBRACE then // test (2)(4) + toIndentedRegion: + try body + finally canRewrite &= in.isAfterLineEnd // test (3) + else + canRewrite = false + body + }) + canRewrite &= in.isAfterLineEnd || in.token == EOF || statCtdTokens.contains(in.token) // test (5) + if canRewrite && (!underColonSyntax || Feature.fewerBracesEnabled) then + val (startClosing, endClosing) = elimRegion(in.lastOffset - 1) + // patch over the added indentation to remove braces + patchOver(source, Span(startOpening, endOpening), "") + patchOver(source, Span(startClosing, endClosing), "") + if colonRequired then + if prevSaved.token == IDENTIFIER && prevSaved.isOperator then + patch(Span(prevSaved.offset, lastOffsetSaved), s"`${prevSaved.name}`:") + else if prevSaved.token == IDENTIFIER && prevSaved.name.last == '_' then + patch(Span(lastOffsetSaved), " :") + else patch(Span(lastOffsetSaved), ":") + else + // no need to force outdentation after `}` + maximumIndent = None + t + end bracesToIndented + + /** compute required indentation to indent region properly */ + private def toIndentedRegion[T](body: => T): T = + val enclosingIndent = minimumIndent + minimumIndent = + if enclosingIndent < in.currentRegion.indentWidth then + in.currentRegion.indentWidth + else if + in.token == CASE && ( + in.currentRegion.enclosing == null || + in.currentRegion.indentWidth == in.currentRegion.enclosing.indentWidth + ) + then enclosingIndent + else enclosingIndent.increment + try body + finally + maximumIndent = Some(minimumIndent) + minimumIndent = enclosingIndent + + /** check that indentaton is correct or patch */ + private def patchIndent(): Unit = + if in.isAfterLineEnd && !in.isNewLine && in.token != OUTDENT && in.token != INDENT then + val currentIndent = in.indentWidth(in.offset) + val indentEndOffset = in.lineOffset + currentIndent.size + def isDotOrClosing = (closingParens + DOT).contains(in.token) + val needsOutdent = maximumIndent.exists: max => + currentIndent >= max || (!isDotOrClosing && currentIndent > minimumIndent) + val offByOne = + currentIndent != minimumIndent && currentIndent.isClose(minimumIndent) + if needsOutdent || !(currentIndent >= minimumIndent) || offByOne then + patch(Span(in.lineOffset, indentEndOffset), minimumIndent.toPrefix) + // no need to outdent anymore + if in.token != RBRACE then + maximumIndent = None + end ToIndentParser diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 4c430cc33901..bcaa72c0e548 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -375,7 +375,6 @@ object Scanners: /** Produce next token, filling TokenData fields of Scanner. */ def nextToken(): Unit = - last.copyFrom(this) val lastToken = token val lastName = name adjustSepRegions(lastToken) @@ -748,6 +747,9 @@ object Scanners: if lookahead.token == EOF || source.offsetToLine(lookahead.offset) > endLine then return true + + if lookahead.token == LBRACE && rewriteToIndent then + patch(Span(offset, offset + 3), s"`end`") false /** Is there a blank line between the current token and the last one? @@ -1454,7 +1456,7 @@ object Scanners: /* Initialization: read first char, then first token */ nextChar() - nextToken() + (this: @unchecked).nextToken() currentRegion = topLevelRegion(indentWidth(offset)) end Scanner diff --git a/compiler/src/dotty/tools/dotc/parsing/ScriptParsers.scala b/compiler/src/dotty/tools/dotc/parsing/ScriptParsers.scala deleted file mode 100644 index 8eb49387c7af..000000000000 --- a/compiler/src/dotty/tools/dotc/parsing/ScriptParsers.scala +++ /dev/null @@ -1,145 +0,0 @@ -package dotty.tools -package dotc -package parsing - -import util.SourceFile -import core._ -import Contexts._ -import Parsers._ - - -/**

Performs the following context-free rewritings:

- *
    - *
  1. - * Places all pattern variables in Bind nodes. In a pattern, for - * identifiers x:
    - *                 x  => x @ _
    - *               x:T  => x @ (_ : T)
    - *
  2. - *
  3. Removes pattern definitions (PatDef's) as follows: - * If pattern is a simple (typed) identifier:
    - *        val x = e     ==>  val x = e
    - *        val x: T = e  ==>  val x: T = e
    - * - * if there are no variables in pattern
    - *        val p = e  ==>  e match (case p => ())
    - * - * if there is exactly one variable in pattern
    - *        val x_1 = e match (case p => (x_1))
    - * - * if there is more than one variable in pattern
    - *        val p = e  ==>  private synthetic val t$ = e match (case p => (x_1, ..., x_N))
    - *                        val x_1 = t$._1
    - *                        ...
    - *                        val x_N = t$._N
    - *
  4. - *
  5. - * Removes function types as follows:
    - *        (argtpes) => restpe   ==>   scala.Function_n[argtpes, restpe]
    - *
  6. - *
  7. - * Wraps naked case definitions in a match as follows:
    - *        { cases }   ==>   (x => x.match {cases}), except when already argument to match
    - *
  8. - *
- */ -object ScriptParsers: - - import ast.untpd._ - - class ScriptParser(source: SourceFile)(using Context) extends Parser(source): - - /** This is the parse entry point for code which is not self-contained, e.g. - * a script which is a series of template statements. They will be - * swaddled in Trees until the AST is equivalent to the one returned - * by compilationUnit(). - */ - override def parse(): Tree = unsupported("parse") - - /* TODO: reinstantiate - - val stmts = templateStatSeq(false)._2 - accept(EOF) - - def mainModuleName = ctx.settings.script.value - - /** If there is only a single object template in the file and it has a - * suitable main method, we will use it rather than building another object - * around it. Since objects are loaded lazily the whole script would have - * been a no-op, so we're not taking much liberty. - */ - def searchForMain(): Option[Tree] = { - /** Have to be fairly liberal about what constitutes a main method since - * nothing has been typed yet - for instance we can't assume the parameter - * type will look exactly like "Array[String]" as it could have been renamed - * via import, etc. - */ - def isMainMethod(t: Tree) = t match { - case DefDef(_, nme.main, Nil, List(_), _, _) => true - case _ => false - } - /** For now we require there only be one top level object. */ - var seenModule = false - val newStmts = stmts collect { - case t @ Import(_, _) => t - case md @ ModuleDef(mods, name, template) - if !seenModule && (template.body exists isMainMethod) => - seenModule = true - /** This slightly hacky situation arises because we have no way to communicate - * back to the scriptrunner what the name of the program is. Even if we were - * willing to take the sketchy route of settings.script.value = progName, that - * does not work when using fsc. And to find out in advance would impose a - * whole additional parse. So instead, if the actual object's name differs from - * what the script is expecting, we transform it to match. - */ - md.derivedModuleDef(mods, mainModuleName.toTermName, template) - case _ => - /** If we see anything but the above, fail. */ - return None - } - Some(makePackaging(0, emptyPkg, newStmts)) - } - - if (mainModuleName == ScriptRunner.defaultScriptMain) - searchForMain() foreach { return _ } - - /** Here we are building an AST representing the following source fiction, - * where is from -Xscript (defaults to "Main") and are - * the result of parsing the script file. - * - * object { - * def main(argv: Array[String]): Unit = { - * val args = argv - * new AnyRef { - * - * } - * } - * } - */ - import definitions._ - - def emptyPkg = atPos(0, 0, 0) { Ident(nme.EMPTY_PACKAGE_NAME) } - def emptyInit = DefDef( - Modifiers(), - nme.CONSTRUCTOR, - Nil, - List(Nil), - TypeTree(), - Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), Nil)), Literal(Constant(()))) - ) - - // def main - def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String))) - def mainParameter = List(ValDef(Modifiers(Param), "argv", mainParamType, EmptyTree)) - def mainSetArgv = List(ValDef(Modifiers(), "args", TypeTree(), Ident("argv"))) - def mainNew = makeNew(Nil, emptyValDef, stmts, List(Nil), NoPosition, NoPosition) - def mainDef = DefDef(Modifiers(), nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), Block(mainSetArgv, mainNew)) - - // object Main - def moduleName = ScriptRunner scriptMain settings - def moduleBody = Template(List(scalaScalaObjectConstr), emptyValDef, List(emptyInit, mainDef)) - def moduleDef = ModuleDef(Modifiers(), moduleName, moduleBody) - - // package { ... } - makePackaging(0, emptyPkg, List(moduleDef)) - }*/ diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala index e39e22cb6420..0b20a030f0d6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala @@ -344,7 +344,7 @@ object MarkupParsers: assert(ts.length == 1, "Require one tree") ts(0) }, - msg => parser.incompleteInputError(msg.toMessage) + msg => parser.incompleteInputError(msg.toMessage) ) /** @see xmlPattern. resynchronizes after successful parse @@ -359,7 +359,7 @@ object MarkupParsers: xSpaceOpt() tree }, - msg => parser.syntaxError(msg.toMessage, curOffset) + msg => parser.syntaxError(msg.toMessage, curOffset) ) def escapeToScala[A](op: => A, kind: String): A = diff --git a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala index 2ce80cbb4840..3b64f7898b5d 100644 --- a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala +++ b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala @@ -6,7 +6,7 @@ import scala.language.unsafeNulls import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.core.Contexts._ import dotty.tools.dotc.core.StdNames._ -import dotty.tools.dotc.parsing.Parsers.Parser +import dotty.tools.dotc.parsing.Parsers import dotty.tools.dotc.parsing.Scanners.Scanner import dotty.tools.dotc.parsing.Tokens._ import dotty.tools.dotc.reporting.Reporter @@ -117,7 +117,7 @@ object SyntaxHighlighting: case _ => traverseChildren(tree) - val parser = new Parser(source) + val parser = Parsers.parser(source) val trees = parser.blockStatSeq() TreeHighlighter.highlight(trees) diff --git a/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala b/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala index 7fe3c9f4156c..76e5300d2d14 100644 --- a/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala +++ b/compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala @@ -25,7 +25,8 @@ object Rewrites: pbuf += Patch(span, replacement) def patchOver(span: Span, replacement: String): Unit = - pbuf.indices.reverse.find(i => span.contains(pbuf(i).span)).foreach(pbuf.remove) + val prevPatchIdx = pbuf.lastIndexWhere(p => span.contains(p.span)) + if prevPatchIdx >= 0 then pbuf.remove(prevPatchIdx) pbuf += Patch(span, replacement) def apply(cs: Array[Char]): Array[Char] = diff --git a/compiler/src/dotty/tools/dotc/semanticdb/internal/SemanticdbInputStream.scala b/compiler/src/dotty/tools/dotc/semanticdb/internal/SemanticdbInputStream.scala index 946881b22ef6..189e2e4c007c 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/internal/SemanticdbInputStream.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/internal/SemanticdbInputStream.scala @@ -312,13 +312,18 @@ class SemanticdbInputStream private (buffer: Array[Byte], input: InputStream): val buffer: Array[Byte] = this.buffer var pos: Int = bufferPos var i: Int = 0 - while (i < 10) - if (buffer(({ - pos += 1; pos - 1 - })) >= 0) - bufferPos = pos - return - i += 1; i - 1 + while (i < 10) { + { + if (buffer(({ + pos += 1; pos - 1 + })) >= 0) + bufferPos = pos + return + } + ({ + i += 1; i - 1 + }) + } skipRawVarintSlowPath @throws(classOf[IOException]) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index eccbf537f85f..22749e6b7b9e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -19,7 +19,7 @@ import config.{Config, Feature} import config.Printers.typr import inlines.{Inlines, PrepareInlineable} import parsing.JavaParsers.JavaParser -import parsing.Parsers.Parser +import parsing.Parsers import Annotations._ import Inferencing._ import transform.ValueClasses._ @@ -687,7 +687,7 @@ class Namer { typer: Typer => unit.untpdTree = if (unit.isJava) new JavaParser(unit.source).parse() - else new Parser(unit.source).parse() + else Parsers.parser(unit.source).parse() atPhase(Phases.typerPhase): inContext(PrepareInlineable.initContext(ctx)): diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 874c194539df..4253d1807ac0 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -43,6 +43,7 @@ object RefChecks: defaultGetterClass <- List(clazz, clazz.companionModule.moduleClass); if defaultGetterClass.isClass } + { val defaultGetterNames = defaultGetterClass.asClass.memberNames(defaultMethodFilter) val defaultMethodNames = defaultGetterNames map { _ replace { case DefaultGetterName(methName, _) => methName @@ -60,6 +61,7 @@ object RefChecks: if owners.forall(_ == clazz) then "." else i".\nThe members with defaults are defined in ${owners.map(_.showLocated).mkString("", " and ", ".")}"}", clazz.srcPos) + } // Check for doomed attempt to overload applyDynamic if (clazz derivesFrom defn.DynamicClass) diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index a9935548d1c2..d8f20c6d883c 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -5,7 +5,7 @@ import dotc.CompilationUnit import dotc.ast.untpd import dotc.core.Contexts._ import dotc.core.StdNames.str -import dotc.parsing.Parsers.Parser +import dotc.parsing.Parsers import dotc.parsing.Tokens import dotc.reporting.{Diagnostic, StoreReporter} import dotc.util.SourceFile @@ -113,7 +113,7 @@ object ParseResult: @sharable private val CommandExtract = """(:[\S]+)\s*(.*)""".r private def parseStats(using Context): List[untpd.Tree] = - val parser = new Parser(ctx.source) + val parser = Parsers.parser(ctx.source) val stats = parser.blockStatSeq() parser.accept(Tokens.EOF) stats diff --git a/compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala b/compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala index b507e3cb2600..5fdcff4adbed 100644 --- a/compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala +++ b/compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala @@ -98,7 +98,7 @@ object SourceCode: def printTree(tree: Tree)(using elideThis: Option[Symbol] = None): this.type = tree match case PackageObject(body)=> - printTree(body) // Print package object + printTree(body) // Print package object case PackageClause(Ident(name), (inner @ PackageClause(_, _)) :: Nil) if name != "" && PackageObject.unapply(inner).isEmpty => // print inner package as `package outer.inner { ... }` diff --git a/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala b/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala index 472e47d859f3..f5ba121308d8 100644 --- a/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala +++ b/compiler/test/dotty/tools/dotc/ast/UntypedTreeMapTest.scala @@ -6,7 +6,7 @@ import org.junit.Test import org.junit.Assert._ import dotc.core.Contexts._ -import dotc.parsing.Parsers.Parser +import dotc.parsing.Parsers import dotc.util.SourceFile class UntpdTreeMapTest extends DottyTest { @@ -14,7 +14,7 @@ class UntpdTreeMapTest extends DottyTest { import untpd._ def parse(code: String): Tree = { - val (_, stats) = new Parser(SourceFile.virtual("", code)).templateStatSeq() + val (_, stats) = Parsers.parser(SourceFile.virtual("", code)).templateStatSeq() stats match { case List(stat) => stat; case stats => untpd.Thicket(stats) } } diff --git a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala index 15d43653025a..65d291245df1 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ModifiersParsingTest.scala @@ -17,7 +17,7 @@ object ModifiersParsingTest { given Context = (new ContextBase).initialCtx def parse(code: String): Tree = { - val (_, stats) = new Parser(SourceFile.virtual("", code)).templateStatSeq() + val (_, stats) = Parsers.parser(SourceFile.virtual("", code)).templateStatSeq() stats match { case List(stat) => stat; case stats => Thicket(stats) } } diff --git a/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala b/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala index 4b166f838d5e..ebf119a6930c 100644 --- a/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/ParserTest.scala @@ -25,7 +25,7 @@ class ParserTest extends DottyTest { private def parseSource(source: SourceFile): Tree = { //println("***** parsing " + source.file) - val parser = new Parser(source) + val parser = Parsers.parser(source) val tree = parser.parse() parsed += 1 parsedTrees += tree diff --git a/tests/rewrites/indent-rewrite.check b/tests/rewrites/indent-rewrite.check index 5d21af14cc85..592d1c9f4dd9 100644 --- a/tests/rewrites/indent-rewrite.check +++ b/tests/rewrites/indent-rewrite.check @@ -162,6 +162,7 @@ do not indent in a multiline string""" o match case Some(x) => x case None => "" + end match o match case None => @@ -221,6 +222,14 @@ do not indent in a multiline string""" m18 } + // back-quote end indent before match + def m20 = + val end = "Foo" + `end` match + case "Foo" => + case _ => + end take 3 + // indent template after self type class C2 { self => val x = "" diff --git a/tests/rewrites/indent-rewrite.scala b/tests/rewrites/indent-rewrite.scala index c3d3a6c5b66b..e00eaf535357 100644 --- a/tests/rewrites/indent-rewrite.scala +++ b/tests/rewrites/indent-rewrite.scala @@ -182,6 +182,7 @@ m10 { 5 } { o match case Some(x) => x case None => "" + end match o match { case None => @@ -249,6 +250,15 @@ m10 { 5 } { m18 } } + + // back-quote end indent before match + def m20 = + val end = "Foo" + end match { + case "Foo" => + case _ => + } + end take 3 } // indent template after self type