Skip to content

Commit

Permalink
Merge pull request #109 from Kodiologist/false-false
Browse files Browse the repository at this point in the history
`lif` adjustments
  • Loading branch information
Kodiologist authored Dec 19, 2024
2 parents ffbd27d + 36ff818 commit 08bd9a4
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 19 deletions.
2 changes: 2 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Breaking Changes
* `recur` is now a real object that must be imported from Hyrule when
using `loop`.
* `macroexpand-all` now uses the same parameters as `hy.macroexpand`.
* `lif` now treats `False` as false.

New Features
------------------------------
Expand All @@ -29,6 +30,7 @@ Bug Fixes
* `loop` now works when nested.
* `macroexpand-all` no longer crashes on stub macros.
* `macroexpand-all` now recognizes macro names properly.
* `lif` now works when renamed, or when invoked with `hy.R`.

0.7.0 (released 2024-09-22; uses Hy ≥ 1)
======================================================
Expand Down
37 changes: 21 additions & 16 deletions hyrule/control.hy
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,10 @@
(defmacro lif [#* args]
#[[A "Lispy if" similar to :hy:func:`if` and :hy:func:`cond
<hy.core.macros.cond>`. Its most notable property is that it tests
the condition with ``(is-not condition None)`` instead of ``(bool
condition)``, so values such as the integer 0, the empty string, and
``False`` are considered true, not false. The general
syntax is
the condition values against ``None`` and ``False`` with
:hy:func:`is-not <hy.pyops.is-not>`, rather than calling
:py:class:`bool`. Thus, values such as the integer 0 and the empty
string are considered true, not false. The general syntax is
::
(lif
Expand All @@ -220,19 +220,24 @@
::
(cond
(is-not condition1 None) result1
(is-not condition2 None) result2
(is-not None condition1 False) result1
(is-not None condition2 False) result2
True else-value)
When no condition matches and there is no else-value, the result is ``None``.]]
(setv n (len args))
(when n
(if (= n 1)
(get args 0)
`(if (is-not ~(get args 0) None)
~(get args 1)
(lif ~@(cut args 2 None))))))
True else-value)
When no condition obtains and there is no else-value, the result is ``None``.]]

(_lif args))

(defn _lif [args]
(cond
(= (len args) 1)
(get args 0)
args (do
(setv [condition result #* rest] args)
`(if (is-not None ~condition False)
~result
~(_lif rest)))))


(defmacro list-n [count-form #* body]
Expand Down
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
python_functions=test_* hyx_test_*
filterwarnings =
ignore::pytest.PytestReturnNotNoneWarning
ignore::SyntaxWarning
15 changes: 12 additions & 3 deletions tests/test_control.hy
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(require
hyrule [block branch ebranch case ecase cfor do-n lif list-n unless])
(import
types [ModuleType]
pytest)


Expand Down Expand Up @@ -314,11 +315,12 @@
(defn test-lif []
;; None is false
;; `None` and `False` are false
(assert (= (lif None "true" "false") "false"))
(assert (= (lif False "true" "false") "false"))
;; But everything else is True! Even falsey things.
(for [x [True False 0 "some-string" "" (+ 1 2 3)]]
(for [x [True 0 "some-string" "" (+ 1 2 3)]]
(assert (= (lif x "true" "false") "true")))
;; Test ellif [sic]
Expand All @@ -327,7 +329,14 @@
None 1
x 2
3)
2)))
2))
;; It should still work with a different name.
(assert (=
(hy.eval '(foo None 1 0 2 8 3)
:module (ModuleType "M")
:macros {"foo" (get-macro lif)})
2)))
(defn test-list-n []
Expand Down

0 comments on commit 08bd9a4

Please sign in to comment.