Skip to content

Commit ffaea68

Browse files
committed
Implement step over and step out
- Implemented step over and step out logic. - Step in is currently doing the proper thing, fixed in a different PR. Closes #5 Closes #1089
1 parent 6cd4d99 commit ffaea68

1 file changed

Lines changed: 87 additions & 11 deletions

File tree

  • debugger/src/main/scala/org.apache.daffodil.debugger.dap

debugger/src/main/scala/org.apache.daffodil.debugger.dap/Parse.scala

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,16 @@ object Parse {
12511251
*/
12521252
def await(): IO[Boolean]
12531253

1254+
/** Update the control with the current element depth (set by the parser thread before awaiting). Depth is used to
1255+
* implement step/stepOut semantics.
1256+
*/
1257+
def setCurrentDepth(depth: Int): IO[Unit]
1258+
1259+
/** Indicate the kind of the upcoming await (e.g. "start" or "end"). Parser hooks should set this before calling
1260+
* await().
1261+
*/
1262+
def setAwaitingKind(kind: String): IO[Unit]
1263+
12541264
/** Start running. */
12551265
def continue(): IO[Unit]
12561266

@@ -1280,6 +1290,9 @@ object Parse {
12801290
for {
12811291
waiterArrived <- Deferred[IO, Unit]
12821292
state <- Ref[IO].of[State](AwaitingFirstAwait(waiterArrived))
1293+
currentDepth <- Ref[IO].of[Int](0)
1294+
awaitingKind <- Ref[IO].of[String]("")
1295+
stopTarget <- Ref[IO].of[Option[(Int, String)]](None)
12831296
} yield new Control {
12841297
def await(): IO[Boolean] =
12851298
for {
@@ -1291,12 +1304,37 @@ object Parse {
12911304
.complete(()) *> nextContinue.get.as(true)
12921305
case Running => Running -> IO.pure(false)
12931306
case s @ Stopped(whenContinued, nextAwaitStarted) =>
1294-
s -> nextAwaitStarted.complete(()) *> // signal next await happened
1295-
whenContinued.get.as(true) // block
1307+
s -> nextAwaitStarted.complete(()) *>
1308+
// Decide whether to block or let parser continue
1309+
stopTarget.get.flatMap {
1310+
case None => whenContinued.get.as(true)
1311+
case Some((targetDepth, mode)) =>
1312+
for {
1313+
cur <- currentDepth.get
1314+
kind <- awaitingKind.get
1315+
res <- mode match {
1316+
// Allow running while deeper than target.
1317+
// When at or above target and we're at an end-element, block once then clear target
1318+
case "stepOut" =>
1319+
if (cur > targetDepth) IO.pure(false)
1320+
else if (kind == "end") whenContinued.get.flatMap(_ => stopTarget.set(None).as(true))
1321+
else IO.pure(false)
1322+
1323+
// Allow running until we reach a deeper depth, then pause at the start-element and clear target
1324+
case "stepIn" =>
1325+
if (cur < targetDepth) IO.pure(false)
1326+
else if (kind == "start") whenContinued.get.flatMap(_ => stopTarget.set(None).as(true))
1327+
else IO.pure(false)
1328+
1329+
// Block once and clear the stopTarget so subsequent awaits don't re-trigger
1330+
case _ => whenContinued.get.flatMap(_ => stopTarget.set(None).as(true))
1331+
}
1332+
} yield res
1333+
}
12961334
}.flatten
12971335
} yield awaited
12981336

1299-
def performStep(stepType: String): IO[Unit] =
1337+
def performStep(stepType: String, addedDepth: Int): IO[Unit] =
13001338
for {
13011339
nextContinue <- Deferred[IO, Unit]
13021340
nextAwaitStarted <- Deferred[IO, Unit]
@@ -1310,23 +1348,31 @@ object Parse {
13101348
case Running => Running -> IO.unit
13111349
case Stopped(whenContinued, _) =>
13121350
Stopped(nextContinue, nextAwaitStarted) -> (
1313-
whenContinued.complete(()) *> // wake up await-ers
1314-
nextAwaitStarted.get // block until next await is invoked
1351+
for {
1352+
d <- currentDepth.get
1353+
_ <- stopTarget.set(Some((d + addedDepth, stepType)))
1354+
_ <- whenContinued.complete(())
1355+
_ <- nextAwaitStarted.get
1356+
} yield ()
13151357
)
13161358
}.flatten
13171359
} yield ()
13181360

1319-
def stepOver(): IO[Unit] = performStep("stepOver")
1320-
def stepIn(): IO[Unit] = performStep("stepIn")
1321-
def stepOut(): IO[Unit] = performStep("stepOut")
1361+
def stepOver(): IO[Unit] = performStep("stepOver", 0)
1362+
def stepIn(): IO[Unit] = performStep("stepIn", 1)
1363+
def stepOut(): IO[Unit] = performStep("stepOut", -1)
1364+
1365+
// Helper functions for stepping
1366+
def setCurrentDepth(depth: Int): IO[Unit] = currentDepth.set(depth)
1367+
def setAwaitingKind(kind: String): IO[Unit] = awaitingKind.set(kind)
13221368

13231369
def continue(): IO[Unit] =
13241370
state.modify {
13251371
case s @ AwaitingFirstAwait(waiterArrived) =>
13261372
s -> waiterArrived.get *> continue()
13271373
case Running => Running -> IO.unit
13281374
case Stopped(whenContinued, _) =>
1329-
Running -> whenContinued.complete(()).void // wake up await-ers
1375+
Running -> (stopTarget.set(None) *> whenContinued.complete(())).void // wake up await-ers
13301376
}.flatten
13311377

13321378
def pause(): IO[Unit] =
@@ -1383,7 +1429,22 @@ object Parse {
13831429

13841430
for {
13851431
_ <- logger.debug("pre-control await")
1386-
isStepping <- control.await() // may block until external control says to unblock, for stepping behavior
1432+
_ <- control.setCurrentDepth(
1433+
Convert
1434+
.daffodilMaybeToOption(pstate.currentNode)
1435+
.map { node =>
1436+
var depth = 0
1437+
var n = node
1438+
while (n.diParent != null) {
1439+
depth += 1
1440+
n = n.diParent
1441+
}
1442+
depth
1443+
}
1444+
.getOrElse(0)
1445+
)
1446+
_ <- control.setAwaitingKind("start")
1447+
isStepping <- control.await()
13871448
_ <- logger.debug("post-control await")
13881449
location = createLocation(pstate.schemaFileLocation)
13891450
shouldBreak <- breakpoints.shouldBreak(location)
@@ -1416,7 +1477,22 @@ object Parse {
14161477

14171478
override def endElement(pstate: PState, processor: Parser): Unit =
14181479
dispatcher.unsafeRunSync {
1419-
control.await() *> // ensure no events while debugger is paused
1480+
val depth = Convert
1481+
.daffodilMaybeToOption(pstate.currentNode)
1482+
.map { node =>
1483+
var d = 0
1484+
var n = node
1485+
while (n.diParent != null) {
1486+
d += 1
1487+
n = n.diParent
1488+
}
1489+
d
1490+
}
1491+
.getOrElse(0)
1492+
1493+
control.setCurrentDepth(depth) *>
1494+
control.setAwaitingKind("end") *>
1495+
control.await() *>
14201496
events.send(Event.EndElement(pstate.copyStateForDebugger)).void
14211497
}
14221498
}

0 commit comments

Comments
 (0)