From b5f1136ba577d1738f921b9179bef797a25fa1d1 Mon Sep 17 00:00:00 2001 From: gilch Date: Sun, 22 Oct 2017 21:36:30 -0600 Subject: [PATCH] %* %** parameters for #% tag macro --- NEWS | 3 ++- docs/extra/anaphoric.rst | 9 ++++---- hy/extra/anaphoric.hy | 32 +++++++++++++++------------ tests/native_tests/extra/anaphoric.hy | 14 +++++++----- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/NEWS b/NEWS index 3f0e702..582544b 100644 --- a/NEWS +++ b/NEWS @@ -22,7 +22,8 @@ Changes from 0.13.0 * support EDN `#_` syntax to discard the next term * `return` has been implemented as a special form * `while` loops may now contain an `else` clause, like `for` loops - * `xi` from `hy.extra.anaphoric` is now the `#%` tag macro. + * `xi` from `hy.extra.anaphoric` is now the `#%` tag macro + * `#%` also has a new `&kwargs` parameter `%**`. [ Bug Fixes ] * Numeric literals are no longer parsed as symbols when followed by a dot diff --git a/docs/extra/anaphoric.rst b/docs/extra/anaphoric.rst index 56b7cf7..1e4d062 100644 --- a/docs/extra/anaphoric.rst +++ b/docs/extra/anaphoric.rst @@ -236,16 +236,17 @@ Returns a function which applies several forms in series from left to right. The Usage ``#%(body ...)`` -Returns a function with parameters implicitly determined by the presence in -the body of %i parameters. A %i symbol designates the ith parameter -(1-based, e.g. ``%1 %2 %3`` etc.), or all remaining parameters for ``%&``. +Makes a function with an implicit parameter list from ``%`` parameters. + +A ``%i`` symbol designates the `i` th parameter (1-based, e.g. ``%1 %2 %3`` etc.). +``%*`` and ``%**`` name the ``&rest`` and ``&kwargs`` parameters, respectively. Nesting of ``#%()`` forms is not recommended. This is similar to Clojure's anonymous function literals (``#()``). .. code-block:: hy - => (#%(identity [%1 %5 [%2 %3] %& %4]) 1 2 3 4 5 6 7 8) + => (#%(identity [%1 %5 [%2 %3] %* %4]) 1 2 3 4 5 6 7 8) [1, 5, [2, 3,] (6, 7, 8), 4] => (def add-10 #%(+ 10 %1)) => (add-10 6) diff --git a/hy/extra/anaphoric.hy b/hy/extra/anaphoric.hy index f93405a..73dc5fb 100644 --- a/hy/extra/anaphoric.hy +++ b/hy/extra/anaphoric.hy @@ -113,24 +113,28 @@ `(fn [var] (ap-pipe var ~@forms))) (deftag % [body] - "Returns a function with parameters implicitly determined by the presence in - the body of %i parameters. A %i symbol designates the ith parameter - (1-based, e.g. %1, %2, %3, etc.), or all remaining parameters for %&. - Nesting of #%() forms is not recommended." + "makes a function with an implicit parameter list from `%` parameters. + + A %i symbol designates the ith parameter (1-based, e.g. `%1 %2 %3` etc.). + `%*` and `%**` name the `&rest` and `&kwargs` parameters, respectively. + Nesting of `#%()` forms is not recommended." (setv flatbody (flatten body)) `(fn [;; generate all %i symbols up to the maximum found in body ~@(genexpr (HySymbol (+ "%" (str i))) [i (range 1 ;; find the maximum %i - (inc (max (+ (list-comp (int (cut a 1)) - [a flatbody] - (and (symbol? a) - (.startswith a '%) - (.isdigit (cut a 1)))) - [0]))))]) - ;; generate the &rest parameter only if '%& is present in body - ~@(if (in '%& flatbody) - '(&rest %&) - '())] + (-> (list-comp (int (cut a 1)) + [a flatbody] + (and (symbol? a) + (.startswith a '%) + (.isdigit (cut a 1)))) + (+ [0]) + max + inc))]) + ;; generate the &rest parameter only if '%* is present in body + ~@(if (in '%* flatbody) + '(&rest %*)) + ~@(if (in '%** flatbody) + '(&kwargs %**))] (~@body))) diff --git a/tests/native_tests/extra/anaphoric.hy b/tests/native_tests/extra/anaphoric.hy index fc45ca5..e0ab038 100644 --- a/tests/native_tests/extra/anaphoric.hy +++ b/tests/native_tests/extra/anaphoric.hy @@ -108,19 +108,23 @@ (assert-equal (#%(identity (, %1 %2 %3 %4 %5)) 1 2 3 4 5) (, 1 2 3 4 5)) (assert-equal (#%(identity (, %1 %5 %2 %3 %4)) 1 2 3 4 5) (, 1 5 2 3 4)) ;; test &rest - (assert-equal (#%(sum %&) 1 2 3) 6) - (assert-equal (#%(identity (, %1 %&)) 10 1 2 3) (, 10 (, 1 2 3))) + (assert-equal (#%(sum %*) 1 2 3) 6) + (assert-equal (#%(identity (, %1 %*)) 10 1 2 3) (, 10 (, 1 2 3))) ;; no parameters (assert-equal (#%(list)) []) (assert-equal (#%(identity "Hy!")) "Hy!") - (assert-equal (#%(identity "%&")) "%&") + (assert-equal (#%(identity "%*")) "%*") (assert-equal (#%(+ "Hy " "world!")) "Hy world!") ;; test skipped parameters (assert-equal (#%(identity [%3 %1]) 1 2 3) [3 1]) ;; test nesting - (assert-equal (#%(identity [%1 (, %2 [%3] "Hy" [%&])]) 1 2 3 4 5) + (assert-equal (#%(identity [%1 (, %2 [%3] "Hy" [%*])]) 1 2 3 4 5) [1 (, 2 [3] "Hy" [(, 4 5)])]) ;; test arg as function (assert-equal (#%(%1 2 4) +) 6) (assert-equal (#%(%1 2 4) -) -2) - (assert-equal (#%(%1 2 4) /) 0.5)) + (assert-equal (#%(%1 2 4) /) 0.5) + ;; test &rest &kwargs + (assert-equal (#%(, %* %**) 1 2 :a 'b) + (, (, 1 2) + (dict :a 'b))))