From 6425d68bad0c1ed73fab08e6467a2b11646ede87 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Sat, 27 Aug 2022 11:34:08 +0300 Subject: [PATCH] Add README.org --- .gitignore | 4 ++ Makefile | 5 ++- README.org | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ sweep.c | 105 ++++++----------------------------------------------- sweep.el | 4 ++ sweep.pl | 5 ++- 6 files changed, 122 insertions(+), 97 deletions(-) create mode 100644 README.org diff --git a/.gitignore b/.gitignore index 641c18c..4cd36b4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ /bin/ /lib/ /share/ +/sweep.html +/sweep.info +/sweep.info~ +/sweep.texi diff --git a/Makefile b/Makefile index d11f967..e8d6113 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ $(TARGET): $(SOURCE) swipl clean: rm -rf bin lib share swipl/build - rm -f $(TARGET) + rm -f $(TARGET) $(BASENAME).info swipl: cd swipl; \ @@ -43,3 +43,6 @@ swipl: cmake $(CMAKE_OPTIONS) -G Ninja ..; \ ninja; \ ninja install + +$(BASENAME).info: + emacs -Q --batch --eval '(require (quote ox-texinfo))' --eval "(with-current-buffer (find-file \"README.org\") (org-export-to-file (quote texinfo) \"$@\" nil nil nil nil nil (quote org-texinfo-compile)))" diff --git a/README.org b/README.org new file mode 100644 index 0000000..263dfce --- /dev/null +++ b/README.org @@ -0,0 +1,96 @@ +#+title: sweep: SWI-Prolog Embedded in Emacs +#+author: Eshel Yaron +#+email: me@eshelyaron.com +#+language: en +#+options: ':t toc:nil author:t email:t num:t +#+startup: content indent +#+export_file_name: sweep.texi +#+texinfo_filename: sweep.info +#+texinfo_dir_category: Prolog +#+texinfo_dir_title: Sweep: (sweep) +#+texinfo_dir_desc: SWI-Prolog Embedded in Emacs +#+texinfo_header: @set MAINTAINERSITE @uref{https://eshelyaron.com,maintainer webpage} +#+texinfo_header: @set MAINTAINER Eshel Yaron +#+texinfo_header: @set MAINTAINEREMAIL @email{me@eshelyaron.com} +#+texinfo_header: @set MAINTAINERCONTACT @uref{mailto:me@eshelyaron.com,contact the maintainer} + +# The "kbd" macro turns KBD into @kbd{KBD}. Additionally, it +# encloses case-sensitive special keys (SPC, RET...) within @key{...}. +#+macro: kbd (eval (let ((case-fold-search nil) (regexp (regexp-opt '("SPC" "RET" "LFD" "TAB" "BS" "ESC" "DELETE" "SHIFT" "Ctrl" "Meta" "Alt" "Cmd" "Super" "UP" "LEFT" "RIGHT" "DOWN") 'words))) (format "@@texinfo:@kbd{@@%s@@texinfo:}@@" (replace-regexp-in-string regexp "@@texinfo:@key{@@\\&@@texinfo:}@@" $1 t)))) + +This manual describes the Emacs package =sweep=, which provides an +embedded SWI-Prolog runtime inside of Emacs. + +#+toc: headlines 8 insert TOC here, with eight headline levels + +* Installation +:PROPERTIES: +:END: + +1. Clone the =sweep= repository: + #+begin_src sh + git clone --recursive https://git.sr.ht/~eshel/sweep + #+end_src +2. Optionally, build the C module =sweep-module=: + #+begin_src sh + cd sweep + make + #+end_src +3. Add =sweep= to Emacs' =load-path=: + #+begin_src emacs-lisp + (add-to-list 'load-path "/path/to/sweep") + #+end_src +4. Load =sweep= into Emacs: + #+begin_src emacs-lisp + (require 'sweep) + #+end_src + If =sweep-module= is not already built, =sweep= will suggest to build + it when loaded. Note that this may take a couple of minutes as the + SWI-Prolog runtime may need to be built as well. + +* Querying Prolog + +=sweep= provides the Elisp function =sweep-open-query= for initiating +Prolog queries. To examine the results of the query, the function +=sweep-next-solution= is used. When no more solutions are available, or +when otherwise further solutions are not required, the query must be +close with either =sweep-cut-query= or =sweep-close-query=. + +#+FINDEX: sweep-open-query +#+FINDEX: sweep-next-solution +#+FINDEX: sweep-cut-query +#+FINDEX: sweep-close-query + +As an example, we show an invocation of the non-deterministic +predicate =lists:permutation/2= from Elisp, which yields the number of +different permutations of the list =(1 2 3 4 5)=: + +#+begin_src emacs-lisp + (sweep-open-query "user" "lists" "permutation" '(1 2 3 4 5)) + (let ((num 0) + (sol (sweep-next-solution))) + (while sol + (setq num (1+ num)) + (setq sol (sweep-next-solution))) + (sweep-close-query) + num) +#+end_src + +* Indices +:PROPERTIES: +:END: + +** Function index +:PROPERTIES: +:INDEX: fn +:END: + +** Variable index +:PROPERTIES: +:INDEX: vr +:END: + +** Concept index +:PROPERTIES: +:INDEX: cp +:END: diff --git a/sweep.c b/sweep.c index c57a273..1d6a6af 100644 --- a/sweep.c +++ b/sweep.c @@ -32,19 +32,6 @@ estring_to_cstring(emacs_env *eenv, emacs_value estring, ptrdiff_t *len_p) { return buf; } -/* int */ -/* estring_to_atom(emacs_env *eenv, emacs_value estring, term_t t) { */ -/* ptrdiff_t len = 0; */ -/* char *buf = NULL; */ -/* int i = 0; */ - -/* if ((buf = estring_to_cstring(eenv, estring, &len)) == NULL) return -1; */ - -/* i = PL_put_atom_nchars(t, len - 1, buf); */ -/* free(buf); */ -/* return i; */ -/* } */ - int estring_to_pstring(emacs_env *eenv, emacs_value estring, term_t t) { ptrdiff_t len = 0; @@ -58,18 +45,6 @@ estring_to_pstring(emacs_env *eenv, emacs_value estring, term_t t) { return i; } -/* static IOSTREAM * */ -/* estring_to_stream(emacs_env *eenv, emacs_value estring) { */ -/* ptrdiff_t len = 0; */ -/* size_t slen = 0; */ -/* char *buf = NULL; */ - -/* if ((buf = estring_to_cstring(eenv, estring, &len)) == NULL) return NULL; */ - -/* slen = len - 1; */ -/* return Sopenmem(&buf, &slen, "r"); */ -/* } */ - static emacs_value econs(emacs_env *env, emacs_value car, emacs_value cdr) { emacs_value args[2] = {car, cdr}; @@ -392,68 +367,10 @@ sweep_open_query(emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) if (c != NULL) free(c); if (m != NULL) free(m); if (f != NULL) free(f); - // if (s != NULL) Sclose(s); return et(env); } -/* emacs_value */ -/* sweep_open_query(emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) */ -/* { */ -/* predicate_t p = NULL; */ -/* IOSTREAM * s = NULL; */ -/* char * m = NULL; */ -/* module_t n = NULL; */ -/* char * c = NULL; */ -/* char * f = NULL; */ -/* term_t a = PL_new_term_refs(3); */ - -/* (void)data; */ -/* (void)nargs; */ - -/* if (PL_current_query() != 0) { */ -/* ethrow(env, "Prolog is already executing a query"); */ -/* goto cleanup; */ -/* } */ - -/* if ((c = estring_to_cstring(env, args[0], NULL)) == NULL) { */ -/* goto cleanup; */ -/* } */ - -/* n = PL_new_module(PL_new_atom(c)); */ - -/* if ((m = estring_to_cstring(env, args[1], NULL)) == NULL) { */ -/* goto cleanup; */ -/* } */ - -/* if ((f = estring_to_cstring(env, args[2], NULL)) == NULL) { */ -/* goto cleanup; */ -/* } */ - -/* p = PL_predicate(f, 3, m); */ - -/* if (estring_to_atom(env, args[3], a+0) < 0) { */ -/* goto cleanup; */ -/* } */ - -/* if ((s = estring_to_stream(env, args[4])) == NULL) { */ -/* goto cleanup; */ -/* } */ - -/* PL_unify_stream(a+1, s); */ - -/* PL_open_query(n, PL_Q_NODEBUG | PL_Q_EXT_STATUS | PL_Q_CATCH_EXCEPTION, p, a); */ -/* o = a+2; */ - -/* cleanup: */ -/* if (c != NULL) free(c); */ -/* if (m != NULL) free(m); */ -/* if (f != NULL) free(f); */ -/* // if (s != NULL) Sclose(s); */ - -/* return et(env); */ -/* } */ - static emacs_value sweep_initialize(emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) { @@ -516,8 +433,8 @@ emacs_module_init (struct emacs_runtime *runtime) env->make_function(env, 1, emacs_variadic_function, sweep_initialize, - "Initialize Prolog.\ -ARG1 is passed as argv[0] to `PL_initialise()', which see.\ + "Initialize Prolog.\n\ +ARG1 is passed as argv[0] to `PL_initialise()', which see.\n\ REST is passed as the rest of the command line arguments to Prolog.", NULL); emacs_value args_initialize[] = {symbol_initialize, func_initialize}; @@ -538,12 +455,12 @@ REST is passed as the rest of the command line arguments to Prolog.", env->make_function(env, 4, 4, sweep_open_query, - "Query Prolog.\ -ARG1 is a string denoting the context module for the query.\ -ARG2 and ARG3 are strings designating the module and predicate name of the Prolog predicate to invoke, which must be of arity 3.\ -ARG4 is a string that is converted to an atom and passed as the first argument of the invoked predicate.\ -ARG5 is a string that is converted to a Prolog stream and passed as the second argument of the invoked predicate.\ -The third and final argument of the predicate is left unbound and is assumed to be an output variable, whose further instantiations can be examined via `sweep-next-solution'.", + "Query Prolog.\n\ +ARG1 is a string denoting the context module for the query.\n\ +ARG2 and ARG3 are strings designating the module and predicate name of the Prolog predicate to invoke, which must be of arity 2.\n\ +ARG4 is any object that can be converted to a Prolog term, and will be passed as the first argument of the invoked predicate.\n\ +The second argument of the predicate is left unbound and is assumed to treated by the invoked predicate as an output variable.\n\ +Further instantiations of the output variable can be examined via `sweep-next-solution'.", NULL); emacs_value args_open_query[] = {symbol_open_query, func_open_query}; env->funcall (env, env->intern (env, "defalias"), 2, args_open_query); @@ -553,7 +470,7 @@ The third and final argument of the predicate is left unbound and is assumed to env->make_function(env, 0, 0, sweep_next_solution, - "Return the next solution from Prolog, or nil if there are none.\ + "Return the next solution from Prolog, or nil if there are none.\n\ See also `sweep-open-query'.", NULL); emacs_value args_next_solution[] = {symbol_next_solution, func_next_solution}; @@ -564,7 +481,7 @@ See also `sweep-open-query'.", env->make_function(env, 0, 0, sweep_cut_query, - "Finalize the current Prolog query.\ + "Finalize the current Prolog query.\n\ This function retains the current instantiation of the query variables.", NULL); emacs_value args_cut_query[] = {symbol_cut_query, func_cut_query}; @@ -575,7 +492,7 @@ This function retains the current instantiation of the query variables.", env->make_function(env, 0, 0, sweep_close_query, - "Finalize the current Prolog query.\ + "Finalize the current Prolog query.\n\ This function drops the current instantiation of the query variables.", NULL); emacs_value args_close_query[] = {symbol_close_query, func_close_query}; diff --git a/sweep.el b/sweep.el index 72bd95a..7691637 100644 --- a/sweep.el +++ b/sweep.el @@ -80,6 +80,9 @@ (completing-read "Predicate: " col))) (defun sweep-find-predicate (mfn) + "Jump to the definiton of the Prolog predicate MFN. +MFN must be a string of the form \"M:F/N\" where M is a Prolog +module name, F is a functor name and N is its arity." (interactive (list (sweep-read-predicate))) (let* ((loc (sweep-predicate-location mfn)) (path (car loc)) @@ -113,6 +116,7 @@ (completing-read "Module: " col))) (defun sweep-find-module (mod) + "Jump to the source file of the Prolog module MOD." (interactive (list (sweep-read-module-name))) (find-file (sweep-module-path mod))) diff --git a/sweep.pl b/sweep.pl index 3ecbd0f..5e90a74 100644 --- a/sweep.pl +++ b/sweep.pl @@ -166,11 +166,12 @@ sweep_module_path(ModuleName, Path) :- sweep_module_path_(Module, Path) :- module_property(Module, file(Path)), !. sweep_module_path_(Module, Path) :- - '$autoload':library_index(_, Module, Path), !. + '$autoload':library_index(_, Module, Path0), !, string_concat(Path0, ".pl", Path). + sweep_modules_collection([], Modules) :- findall([M|P], ( module_property(M0, file(P0)), atom_string(M0, M), atom_string(P0, P) ), Modules0, Tail), - setof([M|P], M0^P0^N^('$autoload':library_index(N, M0, P0), atom_string(M0, M), atom_string(P0, P) ), Tail), + setof([M|P], M0^P0^N^('$autoload':library_index(N, M0, P0), string_concat(P0, ".pl", P), atom_string(M0, M) ), Tail), list_to_set(Modules0, Modules). sweep_predicate_location(MFN, [Path|Line]) :- -- 2.39.2