summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Bergeron <[email protected]>2025-03-25 01:17:02 -0400
committerB. Bergeron <[email protected]>2025-03-25 02:18:40 -0400
commit561874f8fa0b0bb3fc04e1e16d8601e53fab1902 (patch)
tree07b13a4a416796550e78ce9e30743ba3830481b7
Initial commitHEADmaster
-rw-r--r--.editorconfig8
-rw-r--r--.gitignore2
-rw-r--r--LICENSE20
-rw-r--r--Makefile20
-rw-r--r--README42
-rw-r--r--uswipl.c68
6 files changed, 160 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..316e750
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,8 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style=tab
+charset = utf-8
+trim_trailing_whitespace = true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6fb0fe3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+uswipl
+*.o
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0d8d4d6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+MIT License
+
+Copyright (c) 2025 B. Bergeron <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..88e5ace
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+# uswipl - dumbed-Down SWI-Prolog REPL
+# See LICENSE file for copyright and license details.
+
+.POSIX:
+
+CFLAGS = -std=c99 -Wall -Wextra $(shell pkg-config --cflags swipl) -D_POSIX_C_SOURCE=200809L
+LDFLAGS = $(shell pkg-config --libs swipl) -Wl,-rpath,$(shell pkg-config --variable=libdir swipl)
+
+TARGET = uswipl
+SRC = uswipl.c
+
+all: $(TARGET)
+
+$(TARGET): $(SRC)
+ $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS)
+
+clean:
+ rm -f $(TARGET)
+
+.PHONY: all clean
diff --git a/README b/README
new file mode 100644
index 0000000..177543a
--- /dev/null
+++ b/README
@@ -0,0 +1,42 @@
+uswipl - dumbed-Down SWI-Prolog REPL
+====================================
+uswipl is a dumbed-down, IPC-friendly Prolog REPL built on top of SWI-Prolog.
+
+Requirements
+------------
+To build uswipl, you need SWI-Prolog installed.
+
+Installation
+------------
+Enter the following command to build uswipl:
+
+ make uswipl
+
+Running uswipl
+--------------
+uswipl takes the same arguments as `swipl(1)`, it's REPL only allows two types
+of interactions:
+
+1. Assertions, which are done by entering an exclamation mark followed by a
+ term, e.g.:
+
+ !a :- b
+
+2. Queries on unary predicates, which are done by entering a question mark
+ followed by a predicate name. uswipl will then proceed to print each result
+ for that predicate, one per line. e.g.:
+
+ ?mypred
+
+uswipl will terminate on error, misinput, upon receiving a signal, or when
+reading EOF from stdin.
+
+Ok, but why?
+------------
+Because (SWI/GNU) Prolog is awesome but a pain to call from other languages. The C API is
+what it is, and the REPL doesn't seem to have been built with IPC in mind.
+
+You can start uswipl from any other programming language, provide an init `-f`
+or a state `-x` file containing your main Prolog logic, and, through a few
+queries and assertions, be done with gluing your software together.
+
diff --git a/uswipl.c b/uswipl.c
new file mode 100644
index 0000000..1c92515
--- /dev/null
+++ b/uswipl.c
@@ -0,0 +1,68 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <SWI-Prolog.h>
+
+int main(int argc, char **argv)
+{
+ char *input;
+ size_t input_size;
+ ssize_t input_len;
+ char *output;
+ term_t term;
+ predicate_t pred;
+ qid_t query;
+
+ if (!PL_initialise(argc, argv))
+ return EXIT_FAILURE;
+
+ input = NULL;
+ while (errno = 0, (input_len = getline(&input, &input_size, stdin)) != -1) {
+ switch (input[0]) {
+ case '!':
+ if ((term = PL_new_term_ref()) == (term_t)0)
+ return EXIT_FAILURE;
+
+ if (PL_put_term_from_chars(term, REP_UTF8 | CVT_EXCEPTION, -1, &input[1]) == FALSE)
+ return EXIT_FAILURE;
+
+ if (PL_assert(term, NULL, PL_ASSERTZ) == FALSE)
+ return EXIT_FAILURE;
+
+ break;
+
+ case '?':
+ input[input_len - 1] = '\0';
+ if ((pred = PL_predicate(&input[1], 1, NULL)) == (predicate_t)0)
+ return EXIT_FAILURE;
+
+ if ((term = PL_new_term_ref()) == (term_t)0)
+ return EXIT_FAILURE;
+
+ query = PL_open_query(NULL, PL_Q_NODEBUG, pred, term);
+ while (PL_next_solution(query) == TRUE) {
+ if (PL_get_chars(term, &output, CVT_ALL | CVT_VARIABLE | CVT_EXCEPTION | BUF_MALLOC | REP_UTF8) == FALSE)
+ return EXIT_FAILURE;
+ puts(output);
+ PL_free(output);
+ }
+ PL_close_query(query);
+
+ break;
+
+ default:
+ fputs("Unexpected input\n", stderr);
+ return EXIT_FAILURE;
+ }
+ }
+
+ free(input);
+
+ if (errno) {
+ perror("Failed to read line from standard input");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}