I like the lint work. I think that is a very good direction to improve code.
The linter is useable also for plain SWI-Prolog code?
I assume that you’re referring specifically to the linter?
Although Logtalk cannot cope with everything proprietary in SWI-Prolog, specially when a mix of Prolog modules and term-expansion is used, it’s often able to compile Prolog modules as objects without changes. The linter will automatically run on the code (but note that some lint checks are turned off by default). To experiment, simply pass the path to the Prolog module file to the logtalk_load/1-2
predicates or to the top-level abbreviation, {}/1
. For example, assuming a foo.pl
module file:
?- {foo}.
You may also want pass specific compiler options. E.g.
?- logtalk_load(foo, [duplicated_clauses(warning)]).
If you have plain Prolog code (i.e. Prolog code not encapsulated in a module), you can quickly define an object that includes it and compile that object. For example, assuming a bar.pl
plain Prolog file:
:- object(bar).
:- include(bar).
:- end_object.
And then:
?- {bar}.
By default, at startup, Logtalk prints the default flag values, including for the linter flags. These flags are described at:
https://logtalk.org/manuals/userman/programming.html#compiler-linter
Let me know if I can be of further assistance. Hope the linter prove useful in your case. For a live chat on your experiments with the Logtalk linter, try the chat room (you only need a GitHub account).
I guess except for wrapping the Prolog code in an object, the answer is no. Quite a few things (some more and some less) are in the SWI-Prolog compiler and library(check). Ideally we would have some high level pattern language to find notably dubious code patterns. I recently thought about that. Unfortunately, many of these patterns involve some sort of type, mode and/or determinism reasoning.
In the past couple of days I loaded Michael Leuschel’s ecce partial evaluation tool into SWI-Prolog and was quite surprised how many small glitches the compiler found. Some of them merely lead to inefficiencies. Others were obvious semantic errors where sometimes it was quite clear what was intended and sometimes not. Not sure how many could really surface as there is also dead code. Surely, old code is a nice testbed for linter like tools
At most, virtual wrapping using Logtalk’s include/1
directive.
My work on the Logtalk linter have been a learning experience, specially on the required compiler support to make several of the checks possible. First and foremost, the linter makes a strong case for a multi-pass compiler. Although some lint checks only require the directive or clause being parser, others require more extensive context information and often a global view of the compilation context (e.g. the object containing the terms). This additional information is normally not available from the reflection API.
I regularly test new Logtalk compiler versions, including its linter, in both existing Logtalk and Prolog code bases. It’s eye opening the number of issues that I often find, some of them style issues but also bona fide bugs.
That is mostly because you want to be portable. Virtually all SWI-Prolog’s code analysis tools run on the generated code. The library(prolog_xref) is one of the few exceptions. In fact, for code analysis the more recent library(prolog_codewalk)
makes cross referencing on the loaded code much easier (as well as many additional tasks). The source code cross-referencer is mostly used to support syntax highlighting. It is less accurate as it may miss source translations, but nice to support editors or highlighting for HTML without the need to load the code.
The only exceptions are checks that are based on variable names (these are part of the compiler) and discontinuous messages (also part of the compiler and with some work you could do them from the compiled program based on the line numbers stored with clauses).
Portability is only a partial issue. SWI-Prolog reflection API and native tools are oblivious of Logtalk language constructs and thus of limited usefulness for Logtalk developer tools. The only notable usage exception is the diagrams
tool but there the SWI-Prolog reflection API is only used when generating diagrams for Prolog module applications.
Logtalk objects, protocols, and categories are not an abstraction over Prolog modules. Message sending is not an abstraction over module-qualified calls. Not to mention the Logtalk predicate semantics that don’t exist in Prolog. Thus, trying to reconstruct the related contextual information from the generated intermediate code, either for the linter or for Logtalk own reflection API, would be too much work for little to no gain.
The links in the paper are dead. Are you aware of working links for downloading the tools?
See: http://wyvern.cs.uni-duesseldorf.de/ecce/index.php
How I found it
Since a GitHub search did not work as expected.
I tried to find it at GitHub searching for ecce but no luck.
Then I used an old trick I don’t use often but does work sometimes in these cases of broken links to professors at universities.
So the broken link is: http://stups.cs.uni-duesseldorf.de/~pe/ecce
First I try to see if the person is still there and the website just reorganized their pages:
http://stups.cs.uni-duesseldorf.de/~pe
That failed.
Then I try to see if the host URL is still valid
http://stups.cs.uni-duesseldorf.de
That did not work either, but in this case it starts with stups
So trying the more general URL for the university
And that works and returns
So now I know the university changed its URL
Using the university home page search for ecce returns:
Universität Düsseldorf: Yacy Suche
And one of the links on the result page gets me to the home page for Michael Leuschel
Universität Düsseldorf: Leuschel
which has the links desired
Anyway, it is a nice tool (methodology) to have in the tool box.
GitHub - leuschel/ecce: Online partial evaluator for pure Prolog programs (with built-ins)
Haven’t published my port yet. Not sure what to do with it. I got one example running. It will take some time to get it all running and reorganised such that it might be useful as a tool in SWI-Prolog to optimize queries using partial evaluation.
Expanding my previous hints for using the Logtalk linter to check Prolog modules code.
Since yesterday, I have been doing just that on the SWI-Prolog libraries and packages plus on some non-trivial open source Prolog applications. This work resulted in opening issues on code repos and mailing authors for other codebases I checked. Some of the issues found have already been fixed.
A recipe that you can apply is:
- Install Logtalk if not already done. For this use case, you can use the pack:
?- pack_install(logtalk).
- Change directory to where your Prolog modules files reside and load Logtalk:
$ cd .....
$ swipl
?- use_module(library(logtalk).
- Load a required library and set linter flags (we turn a number of them off to minimize noise):
?- {os(loader)}.
...
true
?- set_logtalk_flag(duplicated_clauses,warning), set_logtalk_flag(unknown_entities,silent), set_logtalk_flag(unknown_predicates,silent), set_logtalk_flag(undefined_predicates,silent), set_logtalk_flag(unknown_entities,silent), set_logtalk_flag(missing_directives,silent).
true.
- Try to Prolog compile the code as Logtalk in order to use the linter:
?- os::directory_files('.', Files, [type(regular),extensions(['.pl']),paths(relative)]), forall(member(File,Files), ignore(logtalk_compile(File))).
Ignore the errors (Logtalk cannot cope with everything proprietary found in all Prolog systems and the code and its loading order would need some changes to avoid some other errors) and instead look for the warnings. A few reported issues will be false positives. Several will likely be programming style issues. Some will be performance issues (e.g. using =../2
when not necessary). Any duplicated clauses/grammar rules are most likely bugs. Feel free to ask if some of the reported issues are not clear.
P.S. If you need explanations for (some of) the warnings, before trying to compile the Prolog module files as objects, type:
?- {tutor(loader)}.
I’m continuing to improve the Logtalk linter and tutor tools for next release and I would like to draw from your experience: is there a coding error that you find yourself making in the past that wished to be alerted by a linter and that’s not already listed at https://logtalk.org/tools.html#lint-checker, please let me know. If you want to try it with the current work in progress, please use the current git version (for Windows, you can download an installer for the latest commit). Feedback most welcome.
A quick update for the instructions on how to use the Logtalk linter to look for possible issues in Prolog modules given the recently released Logtalk 3.30.0, which includes new and improved lint checks plus improved support for compiling modules as objects.
To account for module code (yours or from libraries) that makes use of the (SWI-Prolog) term-expansion, use the following improved recipe:
?- {os(loader), hook_flows(loader)}.
...
true.
?- set_logtalk_flag(hook, hook_set([user,system])).
true.
?- os::directory_files('.', Files, [type(regular),extensions(['.pl']),paths(relative)]), forall(member(File,Files), ignore((load_files(File),logtalk_compile(File)))).
...
If you’re curious about the hook objects and hook flows see:
https://logtalk.org/manuals/userman/expansion.html#hook-objects
https://logtalk.org/library/library_index.html#hook-flows
I successfully used this recipe to find the issues mentioned in the SWI-Prolog 8.1.14 release notes and a much larger number of issues in other systems and applications.