11package dotty .tools .debug
22
33import com .sun .jdi .Location
4- import dotty .tools .io .JFile
4+ import dotty .tools .io .JPath
55import dotty .tools .readLines
66
77/**
@@ -10,9 +10,22 @@ import dotty.tools.readLines
1010 */
1111private [debug] case class DebugStepAssert [T ](step : DebugStep [T ], assert : T => Unit )
1212
13+ /** A location in the check file */
14+ private [debug] case class CheckFileLocation (checkFile : JPath , line : Int ):
15+ override def toString : String = s " $checkFile: $line"
16+
17+ /** When a DebugStepAssert fails it throws a DebugStepException */
18+ private [debug] case class DebugStepException (message : String , location : CheckFileLocation ) extends Exception
19+
20+ private [debug] enum DebugStep [T ]:
21+ case Break (className : String , line : Int ) extends DebugStep [Location ]
22+ case Step extends DebugStep [Location ]
23+ case Next extends DebugStep [Location ]
24+ case Eval (expression : String ) extends DebugStep [Either [String , String ]]
25+
1326private [debug] object DebugStepAssert :
1427 import DebugStep .*
15- def parseCheckFile (checkFile : JFile ): Seq [DebugStepAssert [? ]] =
28+ def parseCheckFile (checkFile : JPath ): Seq [DebugStepAssert [? ]] =
1629 val sym = " [a-zA-Z0-9$.]+"
1730 val line = " \\ d+"
1831 val trailing = s " \\ s*(?: \\ / \\ /.*)? " .r // empty or comment
@@ -24,13 +37,15 @@ private[debug] object DebugStepAssert:
2437 val result = " result (.*)" .r
2538 val error = " error (.*)" .r
2639 val multiLineError = s " error $trailing" .r
40+ val allLines = readLines(checkFile.toFile)
2741
2842 def loop (lines : List [String ], acc : List [DebugStepAssert [? ]]): List [DebugStepAssert [? ]] =
43+ given CheckFileLocation = CheckFileLocation (checkFile, allLines.size - lines.size + 1 )
2944 lines match
3045 case Nil => acc.reverse
3146 case break(className , lineStr) :: tail =>
32- val line = lineStr.toInt
33- val step = DebugStepAssert (Break (className, line ), checkClassAndLine(className, line ))
47+ val breakpointLine = lineStr.toInt
48+ val step = DebugStepAssert (Break (className, breakpointLine ), checkClassAndLine(className, breakpointLine ))
3449 loop(tail, step :: acc)
3550 case step(pattern) :: tail =>
3651 val step = DebugStepAssert (Step , checkLineOrMethod(pattern))
@@ -52,6 +67,7 @@ private[debug] object DebugStepAssert:
5267 case invalid :: tail => throw new Exception (s " Cannot parse debug step: $invalid" )
5368
5469 def parseEvalAssertion (lines : List [String ]): (Either [String , String ] => Unit , List [String ]) =
70+ given CheckFileLocation = CheckFileLocation (checkFile, allLines.size - lines.size + 1 )
5571 lines match
5672 case Nil => throw new Exception (s " Missing result or error " )
5773 case result(expected) :: tail => (checkResult(expected), tail)
@@ -61,58 +77,54 @@ private[debug] object DebugStepAssert:
6177 (checkError(expected.map(_.stripPrefix(" " ))), tail1)
6278 case invalid :: _ => throw new Exception (s " Cannot parse as result or error: $invalid" )
6379
64- loop(readLines(checkFile) , Nil )
80+ loop(allLines , Nil )
6581 end parseCheckFile
6682
67- private def checkClassAndLine (className : String , line : Int )(location : Location ): Unit =
68- assert(className == location.declaringType.name, s " obtained ${location.declaringType.name} , expected ${ className} " )
69- checkLine(line )(location)
83+ private def checkClassAndLine (className : String , breakpointLine : Int )( using CheckFileLocation )(location : Location ): Unit =
84+ debugStepAssertEquals( location.declaringType.name, className)
85+ checkLine(breakpointLine )(location)
7086
71- private def checkLineOrMethod (pattern : String ): Location => Unit =
87+ private def checkLineOrMethod (pattern : String )( using CheckFileLocation ) : Location => Unit =
7288 if " (\\ d+)" .r.matches(pattern) then checkLine(pattern.toInt) else checkMethod(pattern)
7389
74- private def checkLine (line : Int )(location : Location ): Unit =
75- assert (location.lineNumber == line, s " obtained ${location.lineNumber} , expected $line " )
90+ private def checkLine (expected : Int )( using CheckFileLocation )(location : Location ): Unit =
91+ debugStepAssertEquals (location.lineNumber, expected)
7692
77- private def checkMethod (methodName : String )(location : Location ): Unit = assert(methodName == location.method.name)
93+ private def checkMethod (expected : String )(using CheckFileLocation )(location : Location ): Unit =
94+ debugStepAssertEquals(location.method.name, expected)
7895
79- private def checkResult (expected : String )(obtained : Either [String , String ]): Unit =
96+ private def checkResult (expected : String )(using CheckFileLocation )( obtained : Either [String , String ]): Unit =
8097 obtained match
8198 case Left (obtained) =>
82- val message =
99+ debugStepFailed(
83100 s """ |Evaluation failed:
84101 | ${obtained.replace(" \n " , " \n |" )}""" .stripMargin
85- throw new AssertionError (message)
86- case Right (obtained) =>
87- val message =
88- s """ |Expected: $expected
89- |Obtained: $obtained""" .stripMargin
90- assert(expected.r.matches(obtained.toString), message)
102+ )
103+ case Right (obtained) => debugStepAssertEquals(obtained, expected)
91104
92- private def checkError (expected : Seq [String ])(obtained : Either [String , String ]): Unit =
105+ private def checkError (expected : Seq [String ])(using CheckFileLocation )( obtained : Either [String , String ]): Unit =
93106 obtained match
94107 case Left (obtained) =>
95- val message =
108+ debugStepAssert(
109+ expected.forall(e => e.r.findFirstMatchIn(obtained).isDefined),
96110 s """ |Expected:
97- | ${expected.mkString(" \n " )}
111+ | ${expected.mkString(" \n | " )}
98112 |Obtained:
99113 | ${obtained.replace(" \n " , " \n |" )}""" .stripMargin
100- assert(expected.forall(e => e.r.findFirstMatchIn(obtained).isDefined), message )
114+ )
101115 case Right (obtained) =>
102- val message =
116+ debugStepFailed(
103117 s """ |Evaluation succeeded but failure expected.
104118 |Obtained: $obtained
105119 | """ .stripMargin
106- throw new AssertionError (message)
107-
108-
109- end DebugStepAssert
110-
111- private [debug] enum DebugStep [T ]:
112- case Break (className : String , line : Int ) extends DebugStep [Location ]
113- case Step extends DebugStep [Location ]
114- case Next extends DebugStep [Location ]
115- case Eval (expression : String ) extends DebugStep [Either [String , String ]]
120+ )
116121
122+ private def debugStepAssertEquals [T ](obtained : T , expected : T )(using CheckFileLocation ): Unit =
123+ debugStepAssert(obtained == expected, s " Obtained $obtained, Expected: $expected" )
117124
125+ private def debugStepAssert (assertion : Boolean , message : String )(using CheckFileLocation ): Unit =
126+ if ! assertion then debugStepFailed(message)
118127
128+ private def debugStepFailed (message : String )(using location : CheckFileLocation ): Unit =
129+ throw DebugStepException (message, location)
130+ end DebugStepAssert
0 commit comments