Skip to content

Commit e3b7d80

Browse files
authoredApr 2, 2025··
line number adjustment for more cases (#201)
2 parents 44c35f7 + dc2c127 commit e3b7d80

File tree

7 files changed

+66
-41
lines changed

7 files changed

+66
-41
lines changed
 

‎core/src/main/scala/replpp/DottyReplDriver.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import dotty.tools.dotc.core.Symbols.{Symbol, defn}
2424
import dotty.tools.dotc.interfaces
2525
import dotty.tools.dotc.interactive.Completion
2626
import dotty.tools.dotc.printing.SyntaxHighlighting
27-
import dotty.tools.dotc.reporting.{ConsoleReporter, StoreReporter}
27+
import dotty.tools.dotc.reporting.{ConsoleReporter, Diagnostic, HideNonSensicalMessages, Reporter, StoreReporter, UniqueMessagePositions}
2828
import dotty.tools.dotc.reporting.Diagnostic
2929
import dotty.tools.dotc.util.Spans.Span
3030
import dotty.tools.dotc.util.{SourceFile, SourcePosition}
@@ -51,6 +51,7 @@ class DottyReplDriver(settings: Array[String],
5151
out: PrintStream,
5252
maxHeight: Option[Int],
5353
classLoader: Option[ClassLoader])(using Colors) extends Driver:
54+
private var invocationCount = 0
5455

5556
/** Overridden to `false` in order to not have to give sources on the
5657
* commandline
@@ -79,7 +80,8 @@ class DottyReplDriver(settings: Array[String],
7980
}
8081

8182
/** the initial, empty state of the REPL session */
82-
final def initialState: State = State(0, 0, Map.empty, Set.empty, rootCtx)
83+
final def initialState: State =
84+
State(0, 0, Map.empty, Set.empty, rootCtx)
8385

8486
/** Reset state of repl to the initial state
8587
*

‎core/src/main/scala/replpp/InteractiveShell.scala

+20-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package replpp
22

33
import dotty.tools.repl.State
44

5-
import java.lang.System.lineSeparator
65
import scala.util.control.NoStackTrace
76

87
object InteractiveShell {
@@ -19,24 +18,31 @@ object InteractiveShell {
1918
prompt = config0.prompt.getOrElse("scala"),
2019
maxHeight = config0.maxHeight,
2120
runAfter = config0.runAfter,
22-
verbose = verbose,
21+
verbose = verbose
2322
)
2423

25-
val initialState: State = replDriver.initialState
26-
val runBeforeLines = (DefaultRunBeforeLines ++ globalRunBeforeLines ++ config.runBefore).mkString(lineSeparator)
27-
val state: State = {
28-
if (verbose) {
29-
println(s"compiler arguments: ${compilerArgs.mkString(",")}")
30-
println(runBeforeLines)
31-
replDriver.run(runBeforeLines)(using initialState)
32-
} else {
33-
replDriver.runQuietly(runBeforeLines)(using initialState)
24+
if (verbose) println(s"compiler arguments: ${compilerArgs.mkString(",")}")
25+
26+
var state: State = replDriver.initialState
27+
var expectedStateObjectIndex = 0
28+
Seq(DefaultRunBeforeLines, globalRunBeforeLines, config.runBefore).foreach { runBeforeLines =>
29+
val runBeforeCode = runBeforeLines.mkString("\n").trim
30+
if (runBeforeCode.nonEmpty) {
31+
expectedStateObjectIndex += 1
32+
state =
33+
if (verbose) {
34+
println(s"executing runBeforeCode: $runBeforeCode")
35+
replDriver.run(runBeforeCode)(using state)
36+
} else {
37+
replDriver.runQuietly(runBeforeCode)(using state)
38+
}
3439
}
3540
}
3641

37-
if (runBeforeLines.nonEmpty && state.objectIndex != 1) {
38-
throw new AssertionError(s"compilation error for predef code - error should have been reported above ^") with NoStackTrace
39-
}
42+
assert(
43+
state.objectIndex == expectedStateObjectIndex,
44+
s"compilation error(s) for predef code - see error above ^^^"
45+
)
4046

4147
replDriver.runUntilQuit(using state)()
4248
}

‎core/src/main/scala/replpp/ReplDriver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class ReplDriver(compilerArgs: Array[String],
2424
/** Run REPL with `state` until `:quit` command found
2525
* Main difference to the 'original': different greeting, trap Ctrl-c
2626
*/
27-
override def runUntilQuit(using initialState: State = initialState)(): State = {
27+
override def runUntilQuit(using initialState: State)(): State = {
2828
val terminal = new replpp.JLineTerminal {
2929
override protected def promptStr = prompt
3030
}

‎core/src/main/scala/replpp/scripting/ScriptingDriver.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ class ScriptingDriver(compilerArgs: Array[String],
4848
executed = true
4949
val inputFiles = (wrappedScript +: predefFiles).filter(Files.exists(_))
5050
try {
51-
new SimpleDriver(lineNumberReportingAdjustment = -wrappingResult.linesBeforeWrappedCode)
52-
.compile(compilerArgs, inputFiles, verbose) { (ctx, outDir) =>
51+
new SimpleDriver(
52+
linesBeforeRunBeforeCode = wrappingResult.linesBeforeRunBeforeCode,
53+
linesBeforeScript = wrappingResult.linesBeforeScript
54+
).compile(compilerArgs, inputFiles, verbose) { (ctx, outDir) =>
5355
given Context = ctx
5456
tempFiles += outDir
5557

‎core/src/main/scala/replpp/scripting/WrapForMainArgs.scala

+18-14
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,55 @@ package replpp.scripting
44
* https://github.com/com-lihaoyi/mainargs */
55
object WrapForMainArgs {
66

7-
/** linesBeforeWrappedCode: allows us to adjust line numbers in error reporting... */
8-
case class WrappingResult(fullScript: String, linesBeforeWrappedCode: Int)
7+
/** linesBeforeScript: allows us to adjust line numbers in error reporting... */
8+
case class WrappingResult(fullScript: String, linesBeforeRunBeforeCode: Int, linesBeforeScript: Int)
99

1010
def apply(scriptCode: String, runBefore: Seq[String], runAfter: Seq[String]): WrappingResult = {
11-
val runBeforeCode = runBefore.mkString("\n")
12-
val runAfterCode = runAfter.mkString("\n")
13-
14-
val wrapperCodeStart =
11+
val wrapperCodeStart0 =
1512
s"""import replpp.shaded.mainargs
1613
|import mainargs.main // intentionally shadow any potentially given @main
1714
|
1815
|// ScriptingDriver expects an object with a predefined name and a main entrypoint method
1916
|object ${ScriptingDriver.MainClassName} {
2017
|// runBeforeCode START
21-
|$runBeforeCode
18+
|""".stripMargin
19+
val linesBeforeRunBeforeCode =
20+
wrapperCodeStart0.lines().count().toInt
21+
+ 1 // for the line break after `wrapperCodeStart0`
22+
23+
val wrapperCodeStart1 =
24+
s"""$wrapperCodeStart0
25+
|${runBefore.mkString("\n")}
2226
|// runBeforeCode END
2327
|""".stripMargin
2428

25-
var linesBeforeWrappedCode = 0 // to adjust line number reporting
29+
var linesBeforeScript = 0 // to adjust line number reporting
2630

2731
val mainImpl =
2832
if (scriptCode.contains("@main"))
2933
scriptCode
3034
else {
31-
linesBeforeWrappedCode += 1 // because we added the following line _before_ the wrapped script code
35+
linesBeforeScript += 1 // because we added the following line _before_ the wrapped script code
3236
s"""@main def _execMain(): Unit = {
3337
|$scriptCode
3438
|}""".stripMargin
3539
}
3640

37-
linesBeforeWrappedCode += wrapperCodeStart.lines().count().toInt
38-
linesBeforeWrappedCode += 1 // for the line break after $wrapperCodeStart
41+
linesBeforeScript += wrapperCodeStart1.lines().count().toInt
42+
linesBeforeScript += 1 // for the line break after `wrapperCodeStart1`
3943
val fullScript =
40-
s"""$wrapperCodeStart
44+
s"""$wrapperCodeStart1
4145
|$mainImpl
4246
|
4347
| def ${ScriptingDriver.MainMethodName}(args: Array[String]): Unit = {
4448
| mainargs.ParserForMethods(this).runOrExit(args.toSeq)
4549
|
46-
| $runAfterCode
50+
| ${runAfter.mkString("\n")}
4751
| }
4852
|}
4953
|""".stripMargin
5054

51-
WrappingResult(fullScript, linesBeforeWrappedCode)
55+
WrappingResult(fullScript, linesBeforeRunBeforeCode, linesBeforeScript)
5256
}
5357

5458
}

‎core/src/main/scala/replpp/util/SimpleDriver.scala

+17-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import replpp.scripting.CompilerError
1111
import java.nio.file.{Files, Path}
1212
import scala.language.unsafeNulls
1313
import scala.util.Try
14+
import scala.util.control.NoStackTrace
1415

1516
/** Compiles input files to a temporary directory
1617
*
@@ -23,7 +24,7 @@ import scala.util.Try
2324
* i.e. store hash of all inputs?
2425
* that functionality must exist somewhere already, e.g. zinc incremental compiler, or even in dotty itself?
2526
*/
26-
class SimpleDriver(lineNumberReportingAdjustment: Int = 0) extends Driver {
27+
class SimpleDriver(linesBeforeRunBeforeCode: Int = 0, linesBeforeScript: Int = 0) extends Driver {
2728

2829
def compileAndGetOutputDir[A](compilerArgs: Array[String], inputFiles: Seq[Path], verbose: Boolean): Try[Path] =
2930
compile(compilerArgs, inputFiles, verbose) { (ctx, outDir) => outDir }
@@ -45,7 +46,9 @@ class SimpleDriver(lineNumberReportingAdjustment: Int = 0) extends Driver {
4546

4647
given ctx0: Context = {
4748
val ctx = rootCtx.fresh.setSetting(rootCtx.settings.outputDir, new PlainDirectory(Directory(outDir)))
48-
if (lineNumberReportingAdjustment != 0) ctx.setReporter(createAdjustedReporter(rootCtx.reporter))
49+
if (linesBeforeRunBeforeCode != 0 || linesBeforeScript != 0) {
50+
ctx.setReporter(createReporter(linesBeforeRunBeforeCode, linesBeforeScript, rootCtx.reporter))
51+
}
4952

5053
if (verbose) {
5154
ctx.setSetting(rootCtx.settings.help, true)
@@ -58,19 +61,27 @@ class SimpleDriver(lineNumberReportingAdjustment: Int = 0) extends Driver {
5861

5962
if (doCompile(newCompiler, toCompile).hasErrors) {
6063
val msgAddonMaybe = if (verbose) "" else " - try `--verbose` for more output"
61-
throw CompilerError(s"Errors encountered during compilation$msgAddonMaybe")
64+
throw new CompilerError(s"Errors encountered during compilation$msgAddonMaybe") with NoStackTrace
6265
} else {
6366
fun(ctx0, outDir)
6467
}
6568
}
6669
}
6770

68-
// creates a new reporter based on the original reporter that copies Diagnostic and changes line numbers
69-
private def createAdjustedReporter(originalReporter: Reporter): Reporter = {
71+
private def createReporter(linesBeforeRunBeforeCode: Int, linesBeforeScript: Int, originalReporter: Reporter): Reporter = {
7072
new Reporter {
7173
override def doReport(dia: Diagnostic)(using Context): Unit = {
7274
val adjustedPos = new SourcePosition(source = dia.pos.source, span = dia.pos.span, outer = dia.pos.outer) {
73-
override def line: Int = super.line + lineNumberReportingAdjustment
75+
override def line: Int = {
76+
val original = super.line
77+
val adjusted = original - linesBeforeScript
78+
if (adjusted >= 0) {
79+
adjusted
80+
} else {
81+
// adjusted line number is negative, i.e. the error must be in the `runBefore` code
82+
original - linesBeforeRunBeforeCode
83+
}
84+
}
7485
}
7586
originalReporter.doReport(new Diagnostic(dia.msg, adjustedPos, dia.level))
7687
}

‎core/src/main/scala/replpp/util/package.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package replpp
22

3-
import replpp.shaded.fansi
4-
53
import java.nio.file.{FileSystems, Files, Path}
4+
import replpp.shaded.fansi
65
import scala.collection.immutable.Seq
76
import scala.io.Source
87
import scala.util.{Try, Using}
@@ -51,4 +50,5 @@ package object util {
5150

5251
def pathAsString(path: Path): String =
5352
path.toAbsolutePath.toString
53+
5454
}

0 commit comments

Comments
 (0)
Please sign in to comment.