Debug Adapter Protocol Server 0.2.13

Hi,
There have been some recent updates to the SWI-Prolog DAP server implementation.
The latest version is available for installation by running:

?- pack_install(debug_adapter).
...
Package:                debug_adapter
Title:                  Debug Adapter Protocol package for SWI-Prolog
Installed version:      0.2.13
...
true.

Notable changes include:

  • Remove autotools dependency to ease packaging and installation
  • Fix issue with debugging non-module source files
  • Support next request to skip over a goal
  • Support stepOut request to skip to the end of a goal
  • Support exceptionInfo request

Hereā€™s an example of using debug_adapter to step through code in various directions:
dap-step.gif

Please let me know if you hit any issues stepping around youā€™re code. SWI-Prolog is complicated and Iā€™d like to collect some test cases :slight_smile:

Comments and requests are welcome. There are still several desirable features to be implemented, specifically I intend to tackle breakpoints of all sorts next.

3 Likes

Is this simply orthogonal to the LSP (Language Server Protocol) as done my @jamesnvc ?

The stuff missing shouldnā€™t be too hard to add. Just ask if you canā€™t figure out how to perform the required low-level stuff quickly.

Yes, the way I see it LSP and DAP serve different and complementary goals - an LSP server is in charge of exposing semantic analysis of a language (Prolog) to the IDE, while the DAP server is in charge of facilitating debugging code.
So a DAP server essentially handles runtime notions where LSP may rely on static analysis for most of its operations.

And thanks you! Iā€™ll definitely ask for help if/when I get stuck. Up to this point xpce source code was a great resource.

1 Like

Note that wrong behavior may well not be your mistake. Verify how the built-in debugger works first. Notably unifications immediately following the head, the => rules and $ are not all correctly handled by the debugger.

can you explain this a bit more ā€“ and give an example of a semantic analysis ā€“ if possible.

Basic examples would include finding references to some defined predicate and deciding whether a certain term in a body of a clause written in a source file represents ā€œcodeā€ or ā€œdataā€, and providing these insights to the IDE.

LSP is described here Official page for Language Server Protocol and DAP here Official page for Debug Adapter Protocol

Added support for basic breakpoints functionality in ADD: Initial support for breakpoints with `setBreakpoints` request Ā· eshelyaron/debug_adapter@b7e48c5 Ā· GitHub.

Hereā€™s an example of setting a breakpoint on the fly and using (c)ontinue from inside test_noun1/2 to run until backtracking and hitting the breakpoint inside test_noun2/2:
breakpoint.gif

Now, DAP also defines conditional breakpoints where the user submits a piece of code to act as a condition for entering the tracer while setting a breakpoint. This feature should be straightforward to support with break_hook/6 (in fact this is the first use case listed in this hookā€™s docs), and dap-mode implements support for it on the client-side for Emacs (certainly also VSCode has it, but I havenā€™t checked), so I think it can be a nice addition in the next version, although Iā€™m not sure how often itā€™ll actually come useful.

1 Like

re: conditional breakpoints

I use it often when i debug more complex use cases that have to generate all kinds of structures first, before the one is reached that requires debugging.

Usually, i then place an (Arg = ā€˜known valueā€™ ā†’ trace ; true) into the code to conditionally start the debugger exactly there ā€¦

1 Like

Conditional breakpoints are now available in version 0.4.5 of the debug_adapter, along with DAP ā€œlog pointsā€ which are a similar feature to the familiar trace points SWI-Prolog provides via trace/1,2.
Hereā€™s an illustration:

Each breakpoint can be associated with a condition, which is a Prolog goal that will be executed in the context of the frame where the breakpoint was hit, including variables bindings.

Also visible in the above screenshot is the ā€œHit Conditionā€ feature, which is a simple skip count that can be set per breakpoint using e.g. M-x dap-breakpoint-hit-condition with dap-mode - requesting that the breakpoint will be skipped for the specified number of visits periodically, so in the example above the first breakpoint only fires every other time.

Lastly, one can also turn a breakpoint into a logpoint (with e.g. M-x dap-breakpoint-log-message), causing the specified message to be logged whenever the breakpoint is hit, instead of breaking the program run, as exemplified with the print me! message printed in the above example.
Logpoints also respect breakpoint conditions and hit conditions, so the message is only logged when X = 2 in the screenshot.

2 Likes