@@ -1310,40 +1310,41 @@ object Parse {
13101310 .complete(()) *> nextContinue.get.as(true )
13111311 case Running => Running -> IO .pure(false )
13121312 case s @ Stopped (whenContinued, nextAwaitStarted) =>
1313- s -> nextAwaitStarted.complete(()) *>
1314- // Decide whether to block or let parser continue
1315- stopTarget.get.flatMap {
1316- case None => whenContinued.get.as(true )
1317- case Some ((targetDepth, mode)) =>
1318- for {
1319- cur <- currentDepth.get
1320- kind <- awaitingKind.get
1321- res <- mode match {
1322- // Allow running while deeper than target.
1323- // When at or above target and we're at an end-element, block once then clear target
1324- case " stepOut" =>
1325- if (cur > targetDepth) IO .pure(false )
1326- else if (kind == " end" ) whenContinued.get.flatMap(_ => stopTarget.set(None ).as(true ))
1327- else IO .pure(false )
1328-
1329- // Allow running until we reach a deeper depth, then pause at the start-element and clear target
1330- case " stepOver" =>
1331- if (cur < targetDepth) IO .pure(false )
1332- else if (kind == " start" ) whenContinued.get.flatMap(_ => stopTarget.set(None ).as(true ))
1333- else IO .pure(false )
1334-
1335- // Block once and clear the stopTarget so subsequent awaits don't re-trigger
1336- case _ => whenContinued.get.flatMap(_ => stopTarget.set(None ).as(true ))
1337- }
1338- } yield res
1339- }
1313+ s -> stopTarget.get.flatMap {
1314+ case None =>
1315+ // No step target, pause immediately and signal that we've stopped
1316+ nextAwaitStarted.complete(()).void *> whenContinued.get.as(true )
1317+ case Some ((targetDepth, mode)) =>
1318+ for {
1319+ cur <- currentDepth.get
1320+ kind <- awaitingKind.get
1321+ res <- mode match {
1322+ // stepIn: Stop at the very next 'start' event, completely ignoring 'end' events
1323+ case " stepIn" =>
1324+ if (kind == " start" )
1325+ stopTarget.set(None ) *> nextAwaitStarted.complete(()).void *> whenContinued.get.as(true )
1326+ else IO .pure(false )
1327+
1328+ // stepOver / stepOut: Run invisibly until we hit a 'start' event at the target depth or shallower
1329+ case " stepOver" | " stepOut" =>
1330+ if (kind == " start" && cur <= targetDepth)
1331+ stopTarget.set(None ) *> nextAwaitStarted.complete(()).void *> whenContinued.get.as(true )
1332+ else
1333+ IO .pure(false ) // Ignore ALL 'end' events and any 'start' events deeper than our target
1334+
1335+ // Block once and clear the stopTarget so subsequent awaits don't re-trigger
1336+ case _ =>
1337+ stopTarget.set(None ) *> nextAwaitStarted.complete(()).void *> whenContinued.get.as(true )
1338+ }
1339+ } yield res
1340+ }
13401341 }.flatten
13411342 } yield awaited
13421343
13431344 def performStep (stepType : String , addedDepth : Int ): IO [Unit ] =
13441345 for {
13451346 nextContinue <- Deferred [IO , Unit ]
1346- nextAwaitStarted <- Deferred [IO , Unit ]
1347+ newAwaitStarted <- Deferred [IO , Unit ]
13471348 _ <- state.modify {
13481349 case s @ AwaitingFirstAwait (waiterArrived) =>
13491350 s -> waiterArrived.get *> (stepType match {
@@ -1353,12 +1354,12 @@ object Parse {
13531354 })
13541355 case Running => Running -> IO .unit
13551356 case Stopped (whenContinued, _) =>
1356- Stopped (nextContinue, nextAwaitStarted ) -> (
1357+ Stopped (nextContinue, newAwaitStarted ) -> (
13571358 for {
13581359 d <- currentDepth.get
13591360 _ <- stopTarget.set(Some ((d + addedDepth, stepType)))
1360- _ <- whenContinued.complete(())
1361- _ <- nextAwaitStarted .get
1361+ _ <- whenContinued.complete(()) // Unblock the parser to continue running invisibly
1362+ _ <- newAwaitStarted .get // WAIT here until the parser hits the target 'start' event and stops
13621363 } yield ()
13631364 )
13641365 }.flatten
@@ -1376,20 +1377,23 @@ object Parse {
13761377 state.modify {
13771378 case s @ AwaitingFirstAwait (waiterArrived) =>
13781379 s -> waiterArrived.get *> continue()
1379- case Running => Running -> IO .unit
1380- case Stopped (whenContinued, _ ) =>
1381- Running -> (stopTarget.set(None ) *> whenContinued .complete(())) .void // wake up await-ers
1380+ case Running => Running -> IO .unit
1381+ case Stopped (whenContinued, nextAwaitStarted ) =>
1382+ Running -> (stopTarget.set(None ) *> nextAwaitStarted .complete(()).void *> whenContinued.complete(())).void
13821383 }.flatten
13831384
13841385 def pause (): IO [Unit ] =
13851386 for {
13861387 nextContinue <- Deferred [IO , Unit ]
1387- nextAwaitStarted <- Deferred [IO , Unit ]
1388- _ <- state.update {
1389- case Running => Stopped (nextContinue, nextAwaitStarted)
1390- case s : AwaitingFirstAwait => s
1391- case s : Stopped => s
1392- }
1388+ newAwaitStarted <- Deferred [IO , Unit ]
1389+ _ <- state.modify {
1390+ case Running =>
1391+ Stopped (nextContinue, newAwaitStarted) -> IO .unit
1392+ case s : AwaitingFirstAwait => s -> IO .unit
1393+ case s @ Stopped (_, nextAwaitStarted) =>
1394+ // If we are hit by a breakpoint during a step, clear target and unblock performStep
1395+ s -> (stopTarget.set(None ) *> nextAwaitStarted.complete(()).void)
1396+ }.flatten
13931397 } yield ()
13941398 }
13951399 }
0 commit comments