/#sweep.pl#
/sweeprolog-tests.elc
/sweeprolog.elc
+/.dir-locals.el
+/NEWS.md
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
* 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
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).
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
foo :- bar.
bar :- foo.
-"))))
+"
+ ))))
(ert-deftest dwim-define-predicate-above ()
%! foo is det.
foo :- bar.
-"))))
+"
+ ))))
(ert-deftest end-of-top-term-with-univ ()
"Tests detecting the fullstop in presence of `=..'."
(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"
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)