A Node.js interface to the SWI-Prolog.
You need to have SWI-Prolog installed and swipl
binary available in
PATH
and compiler installed. See "Platform support" for operating system
support. The library requires Node.js version 7+ and SWI-Prolog 8+.
npm install swipl
Also see "Known issues" for currently unsolved problems.
Calling a predicate and returning bindings with the first solution:
const swipl = require('swipl');
const ret = swipl.call('member(X, [1,2,3,4])');
if (ret) {
console.log(`Variable X value is: ${ret.X}`);
} else {
console.log('Call failed.');
}
Outputs:
Variable X value is: 1
Calling a predicate and returning all solutions:
const swipl = require('swipl');
const query = new swipl.Query('member(X, [1,2,3,4])');
let ret = null;
while (ret = query.next()) {
console.log(`Variable X value is: ${ret.X}`);
}
Outputs:
Variable X value is: 1
Variable X value is: 2
Variable X value is: 3
Variable X value is: 4
There can be only one query open at a time.
Use module operator :
to call code in different
modules. The default call assumes the user
module.
swipl.call('assert(mymodule:test(1))');
console.log(swipl.call('mymodule:test(X)'));
Load code from external files. You might have to set the working directory if you want to use relative paths.
swipl.call('working_directory(_, prolog)');
swipl.call('consult(mycode)');
Queries with data requiring proper escaping can be constructed by using helper functions from swipl.term.
Example:
const swipl = require('./');
const { list, compound, variable, serialize } = swipl.term;
const escaped = serialize(
compound('member', [
variable('X'),
list([1, 2, 3, 4])]));
console.log(swipl.call(escaped));
Blobs and dicts are not supported.
Prolog terms in variable bindings are converted into JavaScript objects under the following rules:
- Integers are converted to numbers.
- Floats are converted to numbers.
- Atoms and strings are converted to strings.
- Empty list is converted to string
[]
. - List head tail pair is converted to object
{ head, tail }
wherehead
andtail
are converted terms. - Compound term is converted to object
{ name, args }
wherename
is the compound functor name andargs
is the array of converted argument terms. - Blobs and dicts are not supported and will throw an error.
Syntax errors in queries are thrown. Error messages are read from the prolog. The current query is automatically closed.
Invalid query example: member(X, [1,2,3,4]
(missing closing paren):
swipl.call('member(X, [1,2,3,4]');
Throws error with message:
Error: Error during query execution. Syntax error:
Operator expected
member(X, 1,2,3,4
** here **
Known errors are thrown with the error message.
swipl.call('error:must_be(ground, _)');
Throws error with message:
Error: Error during query execution. Arguments are
not sufficiently instantiated.
Custom errors without a message are thrown with JavaScript error containing the error term:
swipl.call('throw(error(test))');
Throws error with message:
Error: Error during query execution. Unknown message: error(test).
The embedded SWI-Prolog engine is automatically initialized
when creating the first query. This behavior can be disabled
by calling swipl.autoInitialise(false)
before any query is
executed. The engine can be initialized later manually with
the swipl.initialise()
function.
The bindings are tested on various Linux distributions, on Windows,
and on MacOS. SWI-Prolog command swipl
must be available in PATH
on all of these operating systems.
Microsoft build tools must be installed:
npm install --global --production windows-build-tools
SWI-Prolog command swipl
must be available in PATH
.
SWI-Prolog must be installed or compiled through Macports. This is
described here http://www.swi-prolog.org/build/macos.html. The setup was
tested on MacOS Sierra by installing dependencies from ports and compiling
with prefix /usr/local
(adjust build.templ
).
- Unicode data cannot be exchanged.
- Exporting PL_BLOB terms is not handled.
- Exporting PL_DICT terms is not supported. It is not supported at all by SWI-Prolog foreign interface.
- Installed files cannot be copied around on *nix. The linker has
libswipl
location specified absolutely in the binding object file. The location ofSWI_HOME_DIR
is determined install-time and written into the fileplbase.conf
. - Attempt to use native SWI packages leads to symbol lookup errors
like
readutil.so: undefined symbol: PL_new_atom
. - Custom initialization parameters are not yet implemented.
A list of helpful resources:
- SWI-Prolog Foreign Interface documentation: http://www.swi-prolog.org/pldoc/man?section=foreign
- Node.js native addons: https://nodejs.org/api/addons.html
- PySWIP sources: https://code.google.com/archive/p/pyswip/
- Pengines package.
- Package swipl-stdio.
- Run SWI as HTTP server and create a JSON API.
Please see the AUTHORS file.
Licensed under LGPL 3.0. A copy is available in the LICENSE.txt file.
File lib/serialize_string.js
is ported from the pengines project and is licensed
under BSD (see the file header).