Skip to content

Commit

Permalink
Various improvements to tests and signalling errors. Bug fixes.
Browse files Browse the repository at this point in the history
- Separate, clean up, and add tests.

- Unify most command tests for `loopy` and `loopy-iter`.

- Add more errors which can be signaled in `loopy-misc.el`.
  Use these signals to better test expected failures.

- Simplify explanation of boolean commands.

- Remove unused functions.
  - `loopy--quoted-symbol-p`: We still use `loopy--quoted-form-p`.
  - `loopy--quote-if-car-not-symbol-or-lambda`

- Remove unused functions `loopy--get-optimized-accum`,
  `loopy--accum-code-expansion`. We replaced these functions with
  `loopy--expand-optimized-accum` and using Emacs's own macro expansion
  facilities a while ago.
  - Remove functions.
  - Replace references to removed function with references to the new function.

- Replace use of removed `loopy--quoted-symbol-p` with `loopy--quoted-form-p` in
  `find`.

- Make `loopy--with-bound-p` return value and place.

- Make `loopy--command-bound-p` return value and place.

- Remove unused `loopy-test-structure` from default tests.  Still used
  elsewhere.

- Clarify examples for `find`.

- Mark that a test is expected to fail on Emacs 27 due to byte compilation
  errors.

- Remove duplicate tests from `iter-tests.el`.
  • Loading branch information
okamsn committed Aug 12, 2023
1 parent 5bf0bfa commit f4f389f
Show file tree
Hide file tree
Showing 9 changed files with 5,409 additions and 8,071 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/emacs-matrix-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- '27.2'
- '28.1'
- '28.2'
# - 'release-snapshot'
- 'release-snapshot'
# - 'snapshot'
steps:
- uses: actions/checkout@v3
Expand Down
78 changes: 63 additions & 15 deletions doc/loopy-doc.org
Original file line number Diff line number Diff line change
Expand Up @@ -2820,32 +2820,69 @@ Sequence accumulation commands are used to join lists (such as =union= and
(loopy (list i '(1 2 3))
(finding i (> i 2)))

;; Equivalent to above.
(loopy (list i '(1 2 3))
(when (> i 2) (return i)))

;; => nil
(loopy (list i '(1 2 3))
(finding i (> i 4)))

;; Equivalent to above.
(loopy (list i '(1 2 3))
(when (> i 4) (return i)))

;; => "not found"
(loopy (list i '(1 2 3))
(finding i (> i 4) :on-failure "not found"))

;; Equivalent to above.
(loopy (list i '(1 2 3))
(when (> i 4) (return i))
(else-do (cl-return "not found")))

;; Does not display message.
;; => 2
(loopy (list i '(1 2 3))
(finding i (= i 2) :into found)
(after-do (message "found: %s" found))
(finally-return found))

;; Equivalent to above.
(loopy (list i '(1 2 3))
(when (= i 2)
(set found i)
(leave))
(after-do (message "found: %s" found))
(finally-return found))

;; Messages "found: 2" in echo area.
;; => 2
(loopy (list i '(1 2 3))
(finding found i (= i 2))
(finally-do (message "found: %s" found))
(finally-return found))

;; Equivalent to above.
(loopy (list i '(1 2 3))
(when (= i 2)
(set found i)
(leave))
(finally-do (message "found: %s" found))
(finally-return found))

;; => "not found"
(loopy (list i '(1 2 3))
(finding whether-found i (> i 4) :on-failure "not found")
(finally-return whether-found))

;; Equivalent to above.
(loopy (list i '(1 2 3))
(when (> i 4)
(set whether-found i)
(leave))
(else-do (setq whether-found "not found"))
(finally-return whether-found))
#+END_SRC

*** Optimizing Accumulations
Expand Down Expand Up @@ -2983,13 +3020,32 @@ during the loop. They work like a combination of iteration and accumulation
commands, in that values are stored in ~loopy-result~ and that can terminate the
loop.

In boolean commands, ~loopy-result~ is used as the implicit return value of the
loop. These commands exit the loop without forcing a value
([[#exiting-the-loop-early]]). In other words, their exiting the loop does not
prevent optimized accumulations from optimizing their values. Note, though,
that because such need is infrequent and the boolean commands already use
~loopy-result~, such optimized accumulation variables must be created with
the special macro argument =accum-opt= and must be used explicitly.
The behavior and use of the boolean commands is a compromise between consistency
with other commands, similarity to how similar features are used in other
libraries, and convenience for how they are commonly used. This gives us the
following:

- ~loopy-result~ is used as the implicit return value of the loop.

- Like accumulation commands, the keyword =:into= can be used the specify a
variable other than ~loopy-result~.

- Unlike accumulation commands, there is no non-keyword way to specify a
variable. The first argument (the only required argument) of each boolean
command is a condition to check.

- The =always= and =never= commands must use the same variable to work
together correctly. By default, the both use ~loopy-result~.

- These commands exit the loop without forcing a value ([[#exiting-the-loop-early]]).

- Therefore, optimized accumulation variables can be finalized even when the
loop ends, as happens with the =leave= command.

- However, because the boolean commands already use ~loopy-result~, such
optimized accumulation variables must be created with the special macro
argument =accum-opt= and must be used explicitly, as in the below example.


#+begin_src emacs-lisp
;; A maybe unidiomatic example:
Expand Down Expand Up @@ -3019,21 +3075,13 @@ the special macro argument =accum-opt= and must be used explicitly.
collect i)
#+end_src


#+attr_texinfo: :tag Warn
#+begin_quote
Using the command =thereis= is incompatible with using the commands =always= and
=never=, as this would create conflicting initial values for the implicit return
value (both using ~loopy-result~).
#+end_quote

Like accumulation commands, these boolean commands support the keyword =:into=,
which changes the variable used to store the implicit return value. Unlike
accumulation commands, and as in ~cl-loop~ and Common Lisp's ~iterate~, there is
no non-keyword way to specify the receiving variable. Note that it is expected
that the commands =always= and =never= use the same variable.


#+findex: always
- =(always EXPR [EXPRS] &key into)= :: Check the result of each condition
=EXPR=. If any condition evaluates to ~nil~, end the loop. Otherwise, the
Expand Down
Loading

0 comments on commit f4f389f

Please sign in to comment.