@@ -818,8 +818,13 @@ object Parse {
818818 )
819819 _ <- data.send(newState.data)
820820 } yield newState
821- case (state, Parse .Event .EndElement (_)) => IO .pure(state.copy(data = state.data.pop()))
822- case (state, _ : Parse .Event .Fini .type ) => IO .pure(state)
821+ case (state, e : Parse .Event .EndElement ) =>
822+ val newState = state.copy(
823+ data = state.data.pop(),
824+ infoset = e.infoset // Update the state with the new infoset
825+ )
826+ data.send(newState.data).as(newState)
827+ case (state, _ : Parse .Event .Fini .type ) => IO .pure(state)
823828 case (state, Event .Control (DAPodil .Debugee .State .Stopped (reason))) =>
824829 val events =
825830 List (
@@ -1092,7 +1097,7 @@ object Parse {
10921097 infoset
10931098 )
10941099 }
1095- case class EndElement (state : StateForDebugger ) extends Event
1100+ case class EndElement (state : StateForDebugger , infoset : Option [ InfosetEvent ] ) extends Event
10961101 case object Fini extends Event
10971102 case class Control (state : DAPodil .Debugee .State ) extends Event
10981103 case class Error (message : String ) extends Events .DebugEvent (" daffodil.parseError" )
@@ -1256,7 +1261,18 @@ object Parse {
12561261 /** Blocks if the current state is stopped, unblocking when a `step` or `continue` happens. Returns true if blocking
12571262 * happened, false otherwise.
12581263 */
1259- def await (): IO [Boolean ]
1264+ // def await(): IO[Boolean]
1265+ def await (onStop : IO [Unit ] = IO .unit): IO [Boolean ] // Add onStop here
1266+
1267+ /** Update the control with the current element depth (set by the parser thread before awaiting). Depth is used to
1268+ * implement step/stepOut semantics.
1269+ */
1270+ def setCurrentDepth (depth : Int ): IO [Unit ]
1271+
1272+ /** Indicate the kind of the upcoming await (e.g. "start" or "end"). Parser hooks should set this before calling
1273+ * await().
1274+ */
1275+ def setAwaitingKind (kind : String ): IO [Unit ]
12601276
12611277 /** Start running. */
12621278 def continue (): IO [Unit ]
@@ -1294,26 +1310,61 @@ object Parse {
12941310 for {
12951311 waiterArrived <- Deferred [IO , Unit ]
12961312 state <- Ref [IO ].of[State ](AwaitingFirstAwait (waiterArrived))
1313+ currentDepth <- Ref [IO ].of[Int ](0 )
1314+ awaitingKind <- Ref [IO ].of[String ](" " )
1315+ stopTarget <- Ref [IO ].of[Option [(Int , StepType )]](None )
12971316 } yield new Control {
1298- def await (): IO [Boolean ] =
1317+ def await (onStop : IO [ Unit ] = IO .unit ): IO [Boolean ] =
12991318 for {
13001319 nextContinue <- Deferred [IO , Unit ]
13011320 nextAwaitStarted <- Deferred [IO , Unit ]
13021321 awaited <- state.modify {
13031322 case AwaitingFirstAwait (waiterArrived) =>
1304- Stopped (nextContinue, nextAwaitStarted) -> waiterArrived
1305- .complete(()) *> nextContinue.get.as(true )
1323+ // Stopped(nextContinue, nextAwaitStarted) -> waiterArrived
1324+ // .complete(()) *> nextContinue.get.as(true)
1325+ Stopped (nextContinue, nextAwaitStarted) -> (waiterArrived
1326+ .complete(()) *> onStop *> nextAwaitStarted.complete(()).void *> nextContinue.get.as(true ))
13061327 case Running => Running -> IO .pure(false )
13071328 case s @ Stopped (whenContinued, nextAwaitStarted) =>
1308- s -> nextAwaitStarted.complete(()) *> // signal next await happened
1309- whenContinued.get.as(true ) // block
1329+ s -> stopTarget.get.flatMap {
1330+ case None =>
1331+ // No step target, pause immediately and signal that we've stopped
1332+ onStop *> nextAwaitStarted.complete(()).void *> whenContinued.get.as(true )
1333+ case Some ((targetDepth, mode)) =>
1334+ for {
1335+ cur <- currentDepth.get
1336+ kind <- awaitingKind.get
1337+ res <- mode match {
1338+ // stepIn: Stop at the very next 'start' event, completely ignoring 'end' events
1339+ case StepType .StepIn =>
1340+ if (kind == " start" )
1341+ stopTarget.set(None ) *> onStop *> nextAwaitStarted.complete(()).void *> whenContinued.get
1342+ .as(true )
1343+ else IO .pure(false )
1344+
1345+ // stepOver / stepOut: Run invisibly until we hit a 'start' event at the target depth or shallower
1346+ case StepType .StepOver | StepType .StepOut =>
1347+ if (kind == " start" && cur <= targetDepth)
1348+ stopTarget.set(None ) *> onStop *> nextAwaitStarted.complete(()).void *> whenContinued.get
1349+ .as(true )
1350+ else
1351+ IO .pure(false ) // Ignore ALL 'end' events and any 'start' events deeper than our target
1352+
1353+ // Block once and clear the stopTarget so subsequent awaits don't re-trigger
1354+ case null =>
1355+ stopTarget.set(None ) *> onStop *> nextAwaitStarted.complete(()).void *> whenContinued.get.as(
1356+ true
1357+ )
1358+ }
1359+ } yield res
1360+ }
13101361 }.flatten
13111362 } yield awaited
13121363
1313- def performStep (stepType : StepType ): IO [Unit ] =
1364+ def performStep (stepType : StepType , addedDepth : Int ): IO [Unit ] =
13141365 for {
13151366 nextContinue <- Deferred [IO , Unit ]
1316- nextAwaitStarted <- Deferred [IO , Unit ]
1367+ newAwaitStarted <- Deferred [IO , Unit ]
13171368 _ <- state.modify {
13181369 case s @ AwaitingFirstAwait (waiterArrived) =>
13191370 s -> waiterArrived.get *> (stepType match {
@@ -1323,35 +1374,46 @@ object Parse {
13231374 })
13241375 case Running => Running -> IO .unit
13251376 case Stopped (whenContinued, _) =>
1326- Stopped (nextContinue, nextAwaitStarted) -> (
1327- whenContinued.complete(()) *> // wake up await-ers
1328- nextAwaitStarted.get // block until next await is invoked
1377+ Stopped (nextContinue, newAwaitStarted) -> (
1378+ for {
1379+ d <- currentDepth.get
1380+ _ <- stopTarget.set(Some ((d + addedDepth, stepType)))
1381+ _ <- whenContinued.complete(()) // Unblock the parser to continue running invisibly
1382+ _ <- newAwaitStarted.get // WAIT here until the parser hits the target 'start' event and stops
1383+ } yield ()
13291384 )
13301385 }.flatten
13311386 } yield ()
13321387
1333- def stepOver (): IO [Unit ] = performStep(StepType .StepOver )
1334- def stepIn (): IO [Unit ] = performStep(StepType .StepIn )
1335- def stepOut (): IO [Unit ] = performStep(StepType .StepOut )
1388+ def stepOver (): IO [Unit ] = performStep(StepType .StepOver , 0 )
1389+ def stepIn (): IO [Unit ] = performStep(StepType .StepIn , 1 )
1390+ def stepOut (): IO [Unit ] = performStep(StepType .StepOut , - 1 )
1391+
1392+ // Helper functions for stepping
1393+ def setCurrentDepth (depth : Int ): IO [Unit ] = currentDepth.set(depth)
1394+ def setAwaitingKind (kind : String ): IO [Unit ] = awaitingKind.set(kind)
13361395
13371396 def continue (): IO [Unit ] =
13381397 state.modify {
13391398 case s @ AwaitingFirstAwait (waiterArrived) =>
13401399 s -> waiterArrived.get *> continue()
1341- case Running => Running -> IO .unit
1342- case Stopped (whenContinued, _ ) =>
1343- Running -> whenContinued. complete(()).void // wake up await-ers
1400+ case Running => Running -> IO .unit
1401+ case Stopped (whenContinued, nextAwaitStarted ) =>
1402+ Running -> (stopTarget.set( None ) *> nextAwaitStarted. complete(()).void *> whenContinued.complete(())).void
13441403 }.flatten
13451404
13461405 def pause (): IO [Unit ] =
13471406 for {
13481407 nextContinue <- Deferred [IO , Unit ]
1349- nextAwaitStarted <- Deferred [IO , Unit ]
1350- _ <- state.update {
1351- case Running => Stopped (nextContinue, nextAwaitStarted)
1352- case s : AwaitingFirstAwait => s
1353- case s : Stopped => s
1354- }
1408+ newAwaitStarted <- Deferred [IO , Unit ]
1409+ _ <- state.modify {
1410+ case Running =>
1411+ Stopped (nextContinue, newAwaitStarted) -> IO .unit
1412+ case s : AwaitingFirstAwait => s -> IO .unit
1413+ case s @ Stopped (_, nextAwaitStarted) =>
1414+ // If we are hit by a breakpoint during a step, clear target and unblock performStep
1415+ s -> (stopTarget.set(None ) *> nextAwaitStarted.complete(()).void)
1416+ }.flatten
13551417 } yield ()
13561418 }
13571419 }
@@ -1371,6 +1433,34 @@ object Parse {
13711433 ) extends Debugger {
13721434 implicit val logger : Logger [IO ] = Slf4jLogger .getLogger
13731435
1436+ // Helper function to get the infoset
1437+ private def getFullInfoset (pstate : PState ): Option [InfosetEvent ] = {
1438+ var node = pstate.infoset
1439+ while (node.diParent != null ) node = node.diParent
1440+ node match {
1441+ case d : DIDocument if d.numChildren == 0 => None
1442+ case _ => Some (InfosetEvent (infosetFormat, node))
1443+ }
1444+ }
1445+
1446+ // Helper function to calculate the current depth
1447+ private def calculateDepth (pstate : PState ): Int =
1448+ Convert
1449+ .daffodilMaybeToOption(pstate.currentNode)
1450+ .map { node =>
1451+ var d = 0
1452+ var n = node
1453+ while (n.diParent != null ) {
1454+ n = n.diParent
1455+ // Only count actual elements and document root, ignore hidden DIArray wrappers
1456+ if (n.isInstanceOf [DIElement ] || n.isInstanceOf [DIDocument ]) {
1457+ d += 1
1458+ }
1459+ }
1460+ d
1461+ }
1462+ .getOrElse(0 )
1463+
13741464 override def init (pstate : PState , processor : Parser ): Unit =
13751465 dispatcher.unsafeRunSync {
13761466 events.send(Event .Init (pstate.copyStateForDebugger)).void
@@ -1385,26 +1475,17 @@ object Parse {
13851475
13861476 override def startElement (pstate : PState , processor : Parser ): Unit =
13871477 dispatcher.unsafeRunSync {
1388- // Generating the infoset requires a PState, not a StateForDebugger, so we can't generate it later from the Event.StartElement (which contains the StateForDebugger).
1389- lazy val infoset = {
1390- var node = pstate.infoset
1391- while (node.diParent != null ) node = node.diParent
1392- node match {
1393- case d : DIDocument if d.numChildren == 0 => None
1394- case _ => Some (InfosetEvent (infosetFormat, node))
1395- }
1396- }
1397-
13981478 for {
13991479 _ <- logger.debug(" pre-control await" )
1400- isStepping <- control.await() // may block until external control says to unblock, for stepping behavior
1480+ _ <- control.setCurrentDepth(calculateDepth(pstate))
1481+ _ <- control.setAwaitingKind(" start" )
1482+ isStepping <- control.await(
1483+ onStop = events.send(new Event .StartElement (pstate, getFullInfoset(pstate))).void
1484+ )
14011485 _ <- logger.debug(" post-control await" )
14021486 location = createLocation(pstate.schemaFileLocation)
14031487 shouldBreak <- breakpoints.shouldBreak(location)
1404- startElement =
1405- if (isStepping || shouldBreak) new Event .StartElement (pstate, infoset)
1406- else new Event .StartElement (pstate, None )
1407- _ <- events.send(startElement)
1488+ _ <- events.send(new Event .StartElement (pstate, None )).unlessA(isStepping)
14081489 _ <- onBreakpointHit(location).whenA(shouldBreak)
14091490 } yield ()
14101491 }
@@ -1430,8 +1511,16 @@ object Parse {
14301511
14311512 override def endElement (pstate : PState , processor : Parser ): Unit =
14321513 dispatcher.unsafeRunSync {
1433- control.await() *> // ensure no events while debugger is paused
1434- events.send(Event .EndElement (pstate.copyStateForDebugger)).void
1514+ for {
1515+ _ <- logger.debug(" pre-control await" )
1516+ _ <- control.setCurrentDepth(calculateDepth(pstate))
1517+ _ <- control.setAwaitingKind(" end" )
1518+ isStepping <- control.await(
1519+ onStop = events.send(new Event .EndElement (pstate, getFullInfoset(pstate))).void
1520+ )
1521+ _ <- logger.debug(" post-control await" )
1522+ _ <- events.send(new Event .EndElement (pstate, None )).unlessA(isStepping)
1523+ } yield ()
14351524 }
14361525 }
14371526
0 commit comments