From edbe8e3b7f589523b79cc81b61be687c8e1edcf3 Mon Sep 17 00:00:00 2001 From: Oskar Kvist Date: Mon, 11 Jun 2018 17:37:31 +0200 Subject: [PATCH] Make defmacro! work with optional args --- NEWS.rst | 1 + hy/core/macros.hy | 7 ++++++- tests/native_tests/native_macros.hy | 9 ++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 5ca0d90..159fdfd 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -54,6 +54,7 @@ New Features * `while` and `for` are allowed to have empty bodies * `for` supports the various new clause types offered by `lfor` * Added a new module ``hy.model_patterns`` +* `defmacro!` now allows optional args Bug Fixes ------------------------------ diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 3c65225..c607c74 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -206,7 +206,12 @@ the second form, the second result is inserted into the third form, and so on." "Like `defmacro/g!`, with automatic once-only evaluation for 'o!' params. Such 'o!' params are available within `body` as the equivalent 'g!' symbol." - (setv os (lfor s args :if (.startswith s "o!") s) + (defn extract-o!-sym [arg] + (cond [(and (symbol? arg) (.startswith arg "o!")) + arg] + [(and (instance? list arg) (.startswith (first arg) "o!")) + (first arg)])) + (setv os (list (filter identity (map extract-o!-sym args))) gs (lfor s os (HySymbol (+ "g!" (cut s 2))))) `(defmacro/g! ~name ~args `(do (setv ~@(interleave ~gs ~os)) diff --git a/tests/native_tests/native_macros.hy b/tests/native_tests/native_macros.hy index 79ae560..e58c911 100644 --- a/tests/native_tests/native_macros.hy +++ b/tests/native_tests/native_macros.hy @@ -257,7 +257,14 @@ ;; test that o! is evaluated once only (setv foo 40) (foo! (+= foo 1)) - (assert (= 41 foo))) + (assert (= 41 foo)) + ;; test &optional args + (defmacro! bar! [o!a &optional [o!b 1]] `(do ~g!a ~g!a ~g!b ~g!b)) + ;; test that o!s are evaluated once only + (bar! (+= foo 1) (+= foo 1)) + (assert (= 43 foo)) + ;; test that the optional arg works + (assert (= (bar! 2) 1))) (defn test-if-not []