]> git.eshelyaron.com Git - sweep.git/commitdiff
FIXED: exporting predicates in presence of exported operators
authorEshel Yaron <me@eshelyaron.com>
Sat, 19 Nov 2022 16:38:32 +0000 (18:38 +0200)
committerEshel Yaron <me@eshelyaron.com>
Sat, 19 Nov 2022 16:38:32 +0000 (18:38 +0200)
* sweep.pl (sweep_exportable_predicates/2): new predicate.
* sweeprolog.el (sweeprolog--module-term)
(sweeprolog--exportable-predicates)
(sweeprolog-analyze-start-exportable)
(sweeprolog-analyze-fragment-exportable): no longer used, deleted.
(sweeprolog-exportable-predicates): new function.
(sweeprolog-read-exportable-predicate): use it.
(sweeprolog-export-predicate): handle exported operators.

sweep.pl
sweeprolog-tests.el
sweeprolog.el

index 646cfbc4fe2864bb3df47d171825a0f7d7f357ee..ec1be7af96884f3212118067527152e81b092893 100644 (file)
--- a/sweep.pl
+++ b/sweep.pl
@@ -65,7 +65,8 @@
             sweep_beginning_of_last_predicate/2,
             sweep_atom_collection/2,
             sweep_context_callable/2,
-            sweep_predicate_completion_candidates/2
+            sweep_predicate_completion_candidates/2,
+            sweep_exportable_predicates/2
           ]).
 
 :- use_module(library(pldoc)).
@@ -813,3 +814,13 @@ callable_arg(N) :- integer(N), !.
 callable_arg(^) :- !.
 callable_arg(//) :- !.
 callable_arg(:) :- !.
+
+sweep_exportable_predicates(Path0, Preds) :-
+    atom_string(Path, Path0),
+    findall(D,
+            (   xref_defined(Path, D0, _),
+                \+ xref_exported(Path, D0),
+                pi_head(D1, D0),
+                term_string(D1, D)
+            ),
+            Preds).
index 5decdae0025b64b1ff6ebd930da888add9aa730a..9bc0ad82865c1041b2b4cc0bfd1bd740a2d9a82b 100644 (file)
@@ -217,7 +217,7 @@ bar(Bar) :- baz(Bar).
                               "
 :- module(sweeprolog_test_export_predicate, []).
 
-%!  foo(+Bar) is det
+%!  foo(+Bar) is det.
 
 foo(Bar) :- bar(Bar).
 ")))
@@ -231,11 +231,77 @@ foo(Bar) :- bar(Bar).
 :- module(sweeprolog_test_export_predicate, [foo/1  % +Bar
                                             ]).
 
-%!  foo(+Bar) is det
+%!  foo(+Bar) is det.
 
 foo(Bar) :- bar(Bar).
 "))))
 
+(ert-deftest export-predicate-with-op ()
+  "Test exporting a predicate in presence of an exported operator."
+  (let ((temp (make-temp-file "sweeprolog-test"
+                              nil
+                              ".pl"
+                              "
+:- module(tester,
+          [ instantiate_test_template/4,  % +In,+Replacement,-Dict,-Map
+            op(200, fy, @)               % @name
+          ]).
+
+%!  foo(+Bar) is det.
+
+foo(Bar).
+")))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (goto-char (point-max))
+    (backward-word)
+    (call-interactively #'sweeprolog-export-predicate)
+    (should (equal (buffer-string)
+                  "
+:- module(tester,
+          [ instantiate_test_template/4, % +In,+Replacement,-Dict,-Map
+            foo/1,                       % +Bar
+            op(200, fy, @)              % @name
+          ]).
+
+%!  foo(+Bar) is det.
+
+foo(Bar).
+"
+                  ))))
+
+(ert-deftest export-predicate-with-only-op ()
+  "Test exporting a predicate in presence of only exported operators."
+  (let ((temp (make-temp-file "sweeprolog-test"
+                              nil
+                              ".pl"
+                              "
+:- module(tester,
+          [ op(200, fy, @)               % @name
+          ]).
+
+%!  foo(+Bar) is det.
+
+foo(Bar).
+")))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (goto-char (point-max))
+    (backward-word)
+    (call-interactively #'sweeprolog-export-predicate)
+    (should (equal (buffer-string)
+                  "
+:- module(tester,
+          [ foo/1,         % +Bar
+            op(200, fy, @) % @name
+          ]).
+
+%!  foo(+Bar) is det.
+
+foo(Bar).
+"
+                  ))))
+
 (ert-deftest identifier-at-point ()
   "Test recognizing predicate invocations."
   (let ((temp (make-temp-file "sweeprolog-test"
index b514c5be741d8d622e5be4693d9af451f2b3348a..74af0879cdc6f37441140fd823cf43003f7d1c58 100644 (file)
@@ -438,8 +438,6 @@ buffer where the new predicate defintion should be inserted."
 
 ;;;; Local variables
 
-(defvar-local sweeprolog--module-term nil)
-
 (defvar-local sweeprolog--diagnostics nil)
 
 (defvar-local sweeprolog--diagnostics-report-fn nil)
@@ -448,8 +446,6 @@ buffer where the new predicate defintion should be inserted."
 
 (defvar-local sweeprolog--diagnostics-changes-end nil)
 
-(defvar-local sweeprolog--exportable-predicates nil)
-
 (defvar-local sweeprolog--timer nil)
 
 (defvar-local sweeprolog--analyze-buffer-duration 0.2)
@@ -2009,21 +2005,6 @@ resulting list even when found in the current clause."
              :region (cons beg end))
     (setq sweeprolog--diagnostics-report-fn nil)))
 
-(defun sweeprolog-analyze-start-exportable (&rest _)
-  (setq sweeprolog--exportable-predicates nil
-        sweeprolog--module-term           nil))
-
-(defun sweeprolog-analyze-fragment-exportable (beg end arg)
-  (pcase arg
-    (`("head" ,(rx (or "dynamic "
-                       "unreferenced"
-                       "local("))
-       ,f ,a)
-     (add-to-list 'sweeprolog--exportable-predicates
-                  (concat f "/" (number-to-string a))))
-    (`("goal_term" "built_in" "module" 2)
-     (setq sweeprolog--module-term (cons beg end)))))
-
 (defun sweeprolog-analyze-fragment-variable (beg end arg)
   (pcase arg
     ((or "var"
@@ -3144,10 +3125,16 @@ predicate definition at or directly above POINT."
   (sweeprolog--query-once "sweep" "sweep_local_predicate_export_comment"
                           (list (buffer-file-name) fun ari)))
 
+(defun sweeprolog-exportable-predicates ()
+  "Return a list of exportable predicates from the current buffer."
+  (sweeprolog-xref-buffer)
+  (sweeprolog--query-once "sweep" "sweep_exportable_predicates"
+                          (buffer-file-name)))
+
 (defun sweeprolog-read-exportable-predicate ()
   "Read a predicate name that can be exported in the current buffer."
   (completing-read sweeprolog-read-exportable-predicate-prompt
-                   sweeprolog--exportable-predicates))
+                   (sweeprolog-exportable-predicates)))
 
 (defun sweeprolog-export-predicate (pred &optional comm)
   "Add PRED to the export list of the current module.
@@ -3169,48 +3156,74 @@ non-exported predicates defined in the current buffer."
                     (sweeprolog-read-exportable-predicate)
                     (read-string "Export comment: ")))
                sweeprolog-mode)
-  (add-hook 'sweeprolog-analyze-region-start-hook
-            #'sweeprolog-analyze-start-exportable nil t)
-  (add-hook 'sweeprolog-analyze-region-fragment-hook
-            #'sweeprolog-analyze-fragment-exportable nil t)
-  (sweeprolog-analyze-buffer t)
-  (remove-hook 'sweeprolog-analyze-region-fragment-hook
-               #'sweeprolog-analyze-fragment-exportable t)
-  (remove-hook 'sweeprolog-analyze-region-start-hook
-               #'sweeprolog-analyze-start-exportable t)
-  (unless (member pred sweeprolog--exportable-predicates)
-    (user-error "Cannot add %s to export list" pred))
-  (if-let ((mbeg (car sweeprolog--module-term))
-           (mend (cdr sweeprolog--module-term)))
-      (save-excursion
-        (goto-char mend)
-        (let ((pos (- (point-max) (point))))
-          (unless (search-backward "]" (car sweeprolog--module-term) t)
-            (user-error "Cannot find export list"))
-          (combine-after-change-calls
-            (pcase (sweeprolog-last-token-boundaries)
-              (`(open ,_ ,_)
-               (insert pred)
-               (when (and comm (not (string-empty-p comm)))
-                 (insert "  % " comm))
-               (insert "\n")
-               (indent-region mbeg (1+ (point))))
-              (`(symbol ,_ ,oend)
-               (let ((point (point)))
-                 (goto-char oend)
-                 (insert ",")
-                 (goto-char (1+ point))
-                 (insert "\n")
-                 (backward-char)
-                 (insert pred)
-                 (when (and comm (not (string-empty-p comm)))
-                   (insert "  % " comm))
-                 (indent-region mbeg (- (point-max) pos))
-                 (align-regexp mbeg (- (point-max) pos) (rx (group (zero-or-more blank)) "%"))))
-              (_ (user-error "Unexpected token while looking for export list")))))
-        (sweeprolog-analyze-buffer t)
-        (message "Exported %s" pred))
-    (user-error "Buffer is not a module")))
+  (save-restriction
+    (widen)
+    (save-excursion
+      (goto-char (point-min))
+      (unless (or (sweeprolog-at-beginning-of-top-term-p)
+                  (sweeprolog-beginning-of-next-top-term))
+        (user-error "No module declaration found"))
+      (let* ((indent-tabs-mode nil)
+             (target-position nil)
+             (module-term-beg nil)
+             (module-term-end nil)
+             (exported-operator nil)
+             (func (lambda (beg end arg)
+                     (pcase arg
+                       (`("goal_term" "built_in" "module" 2)
+                        (setq module-term-beg beg
+                              module-term-end end))
+                       ((or "list"
+                            "empty_list")
+                        (when (and (not target-position)
+                                   (< module-term-beg beg)
+                                   (< end module-term-end))
+                          (setq target-position (1- end))))
+                       ("exported_operator"
+                        (unless exported-operator
+                          (setq exported-operator t
+                                target-position beg)))))))
+        (sweeprolog-analyze-term-at-point func)
+        (unless (member pred (sweeprolog-exportable-predicates))
+          (user-error "Cannot add %s to export list" pred))
+        (if target-position
+            (save-excursion
+              (goto-char target-position)
+              (let ((pos (- (point-max) (line-end-position))))
+                (combine-after-change-calls
+                  (if exported-operator
+                      (progn
+                        (insert pred ",\n")
+                        (backward-char)
+                        (when (and comm (not (string-empty-p comm)))
+                          (insert "  % " comm))
+                        (indent-region module-term-beg (- (point-max) pos))
+                        (align-regexp module-term-beg (- (point-max) pos)
+                                      (rx (group (zero-or-more blank)) "%")))
+                    (pcase (sweeprolog-last-token-boundaries)
+                      (`(open ,_ ,_)
+                       (insert pred)
+                       (when (and comm (not (string-empty-p comm)))
+                         (insert "  % " comm))
+                       (insert "\n")
+                       (indent-region module-term-beg (1+ (point))))
+                      (`(symbol ,_ ,oend)
+                       (let ((point (point)))
+                         (goto-char oend)
+                         (insert ",")
+                         (goto-char (1+ point))
+                         (insert "\n")
+                         (backward-char)
+                         (insert pred)
+                         (when (and comm (not (string-empty-p comm)))
+                           (insert "  % " comm))
+                         (indent-region module-term-beg (- (point-max) pos))
+                         (align-regexp module-term-beg (- (point-max) pos)
+                                       (rx (group (zero-or-more blank)) "%"))))
+                      (tok (user-error "Unexpected token %s while looking for export list" tok))))))
+              (sweeprolog-analyze-buffer t)
+              (message "Exported %s" pred))
+          (user-error "No export list found"))))))
 
 (defun sweeprolog-align-spaces (&optional _)
   "Adjust in-line whitespace between the previous next Prolog tokens.