I’ve been working for the past couple of weeks on a little project for improving the integration of SWI-Prolog with GNU Emacs. The idea was to create a setup where Emacs can call Prolog predicates and examine their output as seamlessly as possible, in order to allow Emacs to utilize the Prolog runtime in time-sensitive tasks, such as semantic highlighting of Prolog source code, on-the-fly documentation, etc.
I started with a reexamination of @jamesnvc’s
lsp_server as the obvious suspect for these use cases, but I felt that the overhead imposed by the JSON-based Language Server Protocol is not the best starting point. Instead, I’ve set up a UDP-based channel between Emacs and Prolog where Emacs sends raw Prolog queries to Prolog, which Prolog executes and responds to Emacs with raw strings obtained from the query’s output.
Last week I’ve shown @jan a demo of this work which included semantic highlighting, autocompletion, interactive code formatting, and such bells and whistles built on top of this setup. Jan provided some good feedback and asked about the performance of this setup on large buffers. This made me wonder if it would be possible to achieve a performance that is as good as the built-in editor’s, whose biggest inherent advantage AFAICT is the ability to open buffers directly as Prolog streams without going through costly IPC mechanisms.
So I decided to take a step back and see if I can make SWI-Prolog and Emacs talk to each other without resorting to OS-based IPC, which brings me to the actual subject of this post:
sweep is an embedding of SWI-Prolog in Emacs. It uses the C interfaces of both SWI-Prolog and Emacs Lisp to create a dynamically loaded Emacs module that contains the SWI-Prolog runtime.
Its core functionality is the ability to execute Prolog queries from Emacs Lisp and examine their results. This is achieved via a set of C-implemented Elisp functions,
sweep-cut-query, etc., which expose corresponding functions from the SWI-Prolog C interface.
I’m sharing this work in its initial stage (currently lacking most of its intended user-facing features) to collect some comments on the core functionality of embedding Prolog. Notably, there is currently an annoying limitation that I’m wondering how best to overcome:
sweep builds SWI-Prolog without GMP support (using the
-DUSE_GMP=OFF). Initializing SWI-Prolog inside Emacs with GMP support enabled for SWI-Prolog causes Emacs to crash during garbage collection, AFAICT because the SWI-Prolog
mp_free routine is mistakenly invoked to cleanup Elisp big integers.
Aside from the obvious problem of not being able to utilize SWI-Prolog support for unbounded integer arithmetic, this issue also prevents us from using an existing
libswipl since it is most likely to have been built with GMP enabled.
Thoughts on how to address this issue will be greatly appreciated
The source code for
sweep is available at ~eshel/sweep: / - sourcehut git, and some initial documentation can be found at sweep: SWI-Prolog Embedded in Emacs.
I’ve included Emacs commands for listing and jumping to modules and predicate definitions (
sweep-find-predicate) to show the basic utility:
Added a command
sweep-pack-install for interactively installing SWI-Prolog packages