]> git.eshelyaron.com Git - sweep.git/commitdiff
Support defining DCG non-terminals in sweeprolog-insert-term-dwim
authorEshel Yaron <me@eshelyaron.com>
Mon, 21 Nov 2022 16:39:37 +0000 (18:39 +0200)
committerEshel Yaron <me@eshelyaron.com>
Mon, 21 Nov 2022 16:39:37 +0000 (18:39 +0200)
* sweep.pl (sweep_color_normalized_/4): expose DCG term "kind" to
Elisp.
* sweeprolog.el (sweeprolog-new-predicate-location-function): change
expected function signature.
(sweeprolog-default-new-predicate-location)
(sweeprolog-new-predicate-location-above-current): update arguments.
(sweeprolog-maybe-define-predicate): support defining DCGs.

.gitignore
NEWS.org
sweep.pl
sweeprolog-tests.el
sweeprolog.el

index ee9db441d10e3f2aeb27ad7bf157d790b1be9452..dd499e604d3440efe0018de98aa9dd7304f41aa8 100644 (file)
@@ -16,3 +16,5 @@
 /#sweep.pl#
 /sweeprolog-tests.elc
 /sweeprolog.elc
+/.dir-locals.el
+/NEWS.md
index 8bc9bff191b373eaf74208d723074a911fc43845..cae8769da72df745fa5eea3e15023ac15f18f2f0 100644 (file)
--- a/NEWS.org
+++ b/NEWS.org
@@ -11,17 +11,35 @@ SWI-Prolog in Emacs.
 For further details, please consult the manual:
 <https://eshelyaron.com/sweep.html>.
 
+* Version 0.8.11 on 2022-11-21
+
+** ~sweeprolog-new-predicate-location-function~ signature changed
+
+The function specified by ~sweeprolog-new-predicate-location-function~
+should now take three arguments, namely the functor, arity and neck of
+the new predicate, instead of taking only the predicate indicator as a
+sole argument.
+
+** ~sweeprolog-insert-term-dwim~ now supports defining undefined DCG non-terminals
+
+Defining a previously undefined predicate with
+~sweeprolog-insert-term-dwim~ now analyzes the context of the undefined
+predicate invocation to determine if it is expected to be a DCG
+non-terminal, in which case an appropriate non-terminal definition is
+inserted instead of a regular predicate.
+
 * Version 0.8.10 on 2022-11-21
 
 ** ~sweeprolog-top-level-signal-current~ now calls ~trace/0~ by default
 
-Calling ~sweeprolog-top-level-signal-current~ (e.g. with ~C-c C-c~) now
-signals the top-level thread with the goal specified by the user
-option ~sweeprolog-top-level-signal-default-goal~, instead of prompting
-for a goal.  By default this user option is set to ~"trace"~, causing
-the top-level thread to enter trace mode.  To have
-~sweeprolog-top-level-signal-current~ prompt for a different goal on
-invocation, call it with a prefix argument, i.e. ~C-u C-c C-c~.
+Calling ~sweeprolog-top-level-signal-current~ (~C-c C-c~ in
+~sweeprolog-top-level~ buffers) now signals the top-level thread with
+the goal specified by the user option
+~sweeprolog-top-level-signal-default-goal~, instead of prompting for a
+goal.  By default this user option is set to ~"trace"~, causing the
+top-level thread to enter trace mode.  To have
+~sweeprolog-top-level-signal-current~ prompt for a different goal
+instead, call it with a prefix argument, i.e. ~C-u C-c C-c~.
 
 ** Fixes
 
@@ -32,7 +50,7 @@ invocation, call it with a prefix argument, i.e. ~C-u C-c C-c~.
 
 * Version 0.8.9 on 2022-11-19
 
-** Predicate completions now use holes for arguments
+** Predicate completions now uses holes for arguments
 
 When completing a predicate with ~completion-at-point~ (~C-M-i~) and
 choosing a predicate that takes arguments, holes are inserted is place
index 84f6dbc9b0ffc79f5e13b0cc26d791cc10dbbed8..13424857062bd7f24792e8010584fab24fa6520d 100644 (file)
--- a/sweep.pl
+++ b/sweep.pl
@@ -481,6 +481,9 @@ sweep_color_normalized_(Offset, syntax_error, [Message0,Start0-End0|_], ["syntax
 sweep_color_normalized_(_, comment, [Kind0|_], ["comment"|Kind]) :-
     !,
     atom_string(Kind0, Kind).
+sweep_color_normalized_(_, dcg, [Kind0|_], ["dcg"|Kind]) :-
+    !,
+    atom_string(Kind0, Kind).
 sweep_color_normalized_(_, qq_content, [Type0|_], ["qq_content"|Type]) :-
     !,
     atom_string(Type0, Type).
index 4fa1a4f87eb7358e9999f2bfda1e5eb7eb18457a..0a0f723073896edefde66ce40a02f1b82df38a42 100644 (file)
@@ -434,6 +434,92 @@ foo :- bar.
 foo :- Body.
 "))))
 
+(ert-deftest dwim-define-nested-phrase- ()
+  "Tests complex undefined predicate scenario"
+  (let ((temp (make-temp-file "sweeprolog-test"
+                              nil
+                              "pl"
+                              "
+foo --> {baz, phrase(bar, Baz)}.
+"
+                              )))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (goto-char (point-max))
+    (backward-word 2)
+    (sweeprolog-insert-term-dwim)
+    (call-interactively #'kill-region)
+    (insert "foo")
+    (should (string= (buffer-string)
+                     "
+foo --> {baz, phrase(bar, Baz)}.
+
+bar --> foo.
+"
+                     ))))
+
+(ert-deftest dwim-define-phrase-non-terminal ()
+  "Tests defining an undefined DCG non-terminal from a clause."
+  (let ((temp (make-temp-file "sweeprolog-test"
+                              nil
+                              "pl"
+                              "
+foo :- phrase(bar, Baz).
+"
+                              )))
+    (find-file-literally temp)
+    (sweeprolog-mode)
+    (goto-char (point-max))
+    (backward-word 2)
+    (sweeprolog-insert-term-dwim)
+    (call-interactively #'kill-region)
+    (insert "foo")
+    (should (string= (buffer-string)
+                     "
+foo :- phrase(bar, Baz).
+
+bar --> foo.
+"
+                     ))))
+
+(ert-deftest dwim-define-braces-predicate ()
+  "Tests defining an undefined predicate from a DCG non-terminal."
+  (with-temp-buffer
+    (sweeprolog-mode)
+    (insert "
+foo --> {bar}.
+")
+    (backward-word)
+    (sweeprolog-insert-term-dwim)
+    (call-interactively #'kill-region)
+    (insert "foo")
+    (should (string= (buffer-string)
+                     "
+foo --> {bar}.
+
+bar :- foo.
+"
+                     ))))
+
+(ert-deftest dwim-define-non-terminal ()
+  "Tests defining an undefined DCG non-terminal."
+  (with-temp-buffer
+    (sweeprolog-mode)
+    (insert "
+foo --> bar.
+")
+    (backward-word)
+    (sweeprolog-insert-term-dwim)
+    (call-interactively #'kill-region)
+    (insert "foo")
+    (should (string= (buffer-string)
+                     "
+foo --> bar.
+
+bar --> foo.
+"
+                     ))))
+
 (ert-deftest dwim-define-predicate ()
   "Tests defining a new predicate with `sweeprolog-insert-term-dwim'."
   (with-temp-buffer
@@ -450,7 +536,8 @@ foo :- bar.
 foo :- bar.
 
 bar :- foo.
-"))))
+"
+                     ))))
 
 
 (ert-deftest dwim-define-predicate-above ()
@@ -475,7 +562,8 @@ bar :- foo.
 %!  foo is det.
 
 foo :- bar.
-"))))
+"
+                     ))))
 
 (ert-deftest end-of-top-term-with-univ ()
   "Tests detecting the fullstop in presence of `=..'."
index dc489791cab3f83b02fcbc8bc61e55fc2484ab90..0dce7857aa5deafc15da0ba5e1a61218cbe617ab 100644 (file)
@@ -314,10 +314,17 @@ clause."
 (defcustom sweeprolog-new-predicate-location-function
   #'sweeprolog-default-new-predicate-location
   "Function used to choose a location for a new predicate definition.
-It should take one argument, the name of the new predicate given
-as a string, and move point to a suitable position in the current
-buffer where the new predicate defintion should be inserted."
-  :package-version '((sweeprolog "0.8.6"))
+
+It should take three arguments describing the new predicate,
+FUNCTOR, ARITY and NECK, and move point to a suitable position in
+the current buffer where the new predicate defintion should be
+inserted.
+
+FUNCTOR is the predicate name given as a string, ARITY is its
+arity given as an integer, and NECK is the neck operator of the
+predicate (e.g. \":-\" for regular clauses and \"-->\" for DCG
+non-terminals)."
+  :package-version '((sweeprolog "0.8.11"))
   :type '(choice (const    :tag "Below Current Predicate"
                         sweeprolog-default-new-predicate-location)
                  (const    :tag "Above Current Predicate"
@@ -2626,22 +2633,44 @@ instead."
                               neck)
     t))
 
-(defun sweeprolog-default-new-predicate-location (_pred)
+(defun sweeprolog-default-new-predicate-location (&rest _)
   (sweeprolog-end-of-predicate-at-point))
 
-(defun sweeprolog-new-predicate-location-above-current (_pred)
+(defun sweeprolog-new-predicate-location-above-current (&rest _)
   (sweeprolog-beginning-of-predicate-at-point)
   (let ((last (or (caddr (sweeprolog-last-token-boundaries))
                   (point-min))))
     (while (re-search-backward (rx bol "%" (or "%" "!")) last t))))
 
 (defun sweeprolog-maybe-define-predicate (point _kind _beg _end)
-  (when-let ((pred (sweeprolog-identifier-at-point point)))
-    (unless (sweeprolog-predicate-properties pred)
-      (funcall sweeprolog-new-predicate-location-function pred)
-      (let ((functor-arity (sweeprolog--mfn-to-functor-arity pred)))
-        (sweeprolog-insert-clause (car functor-arity)
-                                  (cdr functor-arity)))
+  (let ((functor nil)
+        (arity nil)
+        (neck ":-"))
+    (sweeprolog-analyze-term-at-point
+     (lambda (beg end arg)
+       (pcase arg
+         (`("goal_term" "undefined" ,f ,a)
+          (when (<= beg point end)
+            (setq functor f
+                  arity   a)))
+         ("neck"
+          (setq neck
+                (buffer-substring-no-properties beg end)))
+         (`("goal_term" "built_in" "phrase" ,a)
+          (when (and (<= beg point end)
+                     (member a '(2 3))
+                     (string= neck ":-"))
+            (setq neck "-->")))
+         (`("dcg" . "plain")
+          (when (and (<= beg point end)
+                     (string= neck "-->"))
+            (setq neck ":-"))))))
+    (when functor
+      (funcall sweeprolog-new-predicate-location-function
+               functor arity neck)
+      (sweeprolog-insert-clause functor
+                                (- arity (if (string= neck "-->") 2 0))
+                                neck)
       t)))
 
 (defun sweeprolog-insert-term-dwim (&optional point)