branch: master commit 7020c671b048d4ef104ec29da9fbcdbfe4bde60d Author: Artur Malabarba <bruce.connor...@gmail.com> Commit: Artur Malabarba <bruce.connor...@gmail.com>
Implement :functionlike-macros. Affects #17 --- TheNittyGritty.org | 35 +++++++++++++++++++++++++++++++++++ names.el | 27 +++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/TheNittyGritty.org b/TheNittyGritty.org index 78bf88b..84bf6b8 100644 --- a/TheNittyGritty.org +++ b/TheNittyGritty.org @@ -139,6 +139,41 @@ need to worry about, it should just do what you expect from it. This is only relevant if you write your own macros. If you do, remember to add a debug declaration in them. + +*** The theading macros (~->~ and ~-->~) + +The threading macros would require special treatment to namespace +correctly. However, you can use the ~:functionlike-macros~ keyword to +tell *Names* to treat them as regular functions. + +For example, in the following snippet: +#+BEGIN_SRC emacs-lisp +(require 'dash) +(define-namespace foo- +:functionlike-macros (-> ->>) + +(defvar var nil) +(defun fun (x &optional y) + (concat x y)) + +(-> "some string" + (fun var) + fun) +) +#+END_SRC +the ~(fun var)~ part would be namespaced prefectly fine (~fun~ and +~var~ will be identified as a function and variable respectively), +because it looks like a regular function call. However, the second use +of ~fun~ will not be correctly namespaced, because that ~fun~ looks +like a variable. + +In other words, you should use these macros like this instead: +#+BEGIN_SRC emacs-lisp +(-> "some string" + (fun var) + (fun)) +#+END_SRC + ** Accessing Global Symbols If one of your definitions shadows a global definition, you can still access it by prefixing it with =::=. diff --git a/names.el b/names.el index 4cd23a1..7ae9521 100644 --- a/names.el +++ b/names.el @@ -182,6 +182,22 @@ Is only non-nil if the :group keyword is passed to `define-namespace'.") "The version number given by :version. Used to define a constant and a command.") +(defvar names--functionlike-macros nil + "Function-like macros, even if their debug-spec says otherwise. +When expanding the namespace, these macros will be treated +exactly like functions. This means that their contents will be +namespaced like regular function arguments. + +To add macros to this list, pass the :functionlike-macros keyword +to your namespace along with a list of macro names (as unquoted +symbols). +Example: + + (define-namespace foo- + :functionlike-macros (-> ->> thread-first thread-last) + ;; Rest of code + )") + (defconst names--keyword-list `((:group 1 ,(lambda (x) @@ -240,6 +256,12 @@ needed by the :version and :group keywords.") (format "\\`%s" (regexp-quote val))))) "Change the value of the `names--protection' variable.") + (:functionlike-macros + 1 + ,(lambda (x) (setq names--functionlike-macros + (append x names--functionlike-macros))) + "A list of values to be appended to `names--functionlike-macros'.") + (:no-let-vars 0 nil "Indicates variables assigned in let-bind are NOT candidates for namespacing.") @@ -407,6 +429,7 @@ See `define-namespace' for more information." (names--remove-namespace-from-list (names--filter-if-bound byte-compile-macro-environment (lambda (x) (not (names--compat-macrop x)))) (names--filter-if-bound byte-compile-function-environment (lambda (x) (not (names--compat-macrop x)))))) + (names--functionlike-macros names--functionlike-macros) names--keywords names--local-vars key-and-args names--version names--package names--group-parent) ;; Read keywords @@ -742,7 +765,6 @@ returns nil." (and (names--keyword :global) (boundp (names--prepend sbl)))))) -;;; This is calling edebug even on `when' and `unless' (defun names--args-of-function-or-macro (function args macro) "Namespace FUNCTION's arguments ARGS, with special treatment if MACRO is non-nil." (if macro @@ -750,7 +772,8 @@ returns nil." (names--verbose (eq function 'push))) (names--message "Edebug-spec of `%s' is %s" function it) ;; Macros where we evaluate all arguments are like functions. - (if (equal it t) + (if (or (equal it t) + (memq function names--functionlike-macros)) (names--args-of-function-or-macro function args nil) ;; Macros where nothing is evaluated we can just return. (if (equal it 0)