name-with-attributes

clojure.contrib.def

  • (name-with-attributes name macro-args)
To be used in macro definitions.
Handles optional docstrings and attribute maps for a name to be defined
in a list of macro arguments. If the first macro argument is a string,
it is added as a docstring to name and removed from the macro argument
list. If afterwards the first macro argument is a map, its entries are
added to the name's metadata map and the map is removed from the
macro argument list. The return value is a vector containing the name
with its extended metadata map and the list of unprocessed macro
arguments.

1 Example top

  • ;; Here I use name-with-attributes to create a macro writing
    ;; macro defmacro! that accepts the same args as defmacro itself,
    ;; i.e., an optional docstring and an optional metadata map.
    ;; (In contrast to defmacro, overloading is not supported.)
    
    ;; Only a helper...
    (defn bang-symbol?
      "Returns true, if sym is a symbol with name ending in a exclamation
      mark (bang)."
      [sym]
      (and (symbol? sym)
           (= (last (name sym)) \!)))
    
    (defmacro defmacro!
      "Defines a macro name with the given docstring, args, and body.
      All args ending in an exclamation mark (!, bang) will be evaluated
      only once in the expansion, even if they are unquoted at several
      places in body.  This is especially important for args whose
      evaluation has side-effecs or who are expensive to evaluate."
      {:arglists '([name doc-string? attr-map? [params*] body])}
      [name & args]
      (let [[name attrs] (tm/name-with-attributes name args)
            meta-map     (meta name)
            args         (first attrs)
            body         (next attrs)
            bang-syms    (filter bang-symbol? (flatten args))
            rep-map      (apply hash-map
                                (mapcat (fn [s] [s `(quote ~(gensym))])
                                        bang-syms))]
        `(defmacro ~name
           ~@(when (seq meta-map) [meta-map])
           ~args
           `(let ~~(vec (mapcat (fn [[s t]] [t s]) rep-map))
              ~(clojure.walk/prewalk-replace ~rep-map ~@body)))))
Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/contrib/def.clj:96 top

(defn name-with-attributes
  "To be used in macro definitions.
   Handles optional docstrings and attribute maps for a name to be defined
   in a list of macro arguments. If the first macro argument is a string,
   it is added as a docstring to name and removed from the macro argument
   list. If afterwards the first macro argument is a map, its entries are
   added to the name's metadata map and the map is removed from the
   macro argument list. The return value is a vector containing the name
   with its extended metadata map and the list of unprocessed macro
   arguments."
  [name macro-args]
  (let [[docstring macro-args] (if (string? (first macro-args))
                                 [(first macro-args) (next macro-args)]
                                 [nil macro-args])
    [attr macro-args]          (if (map? (first macro-args))
                                 [(first macro-args) (next macro-args)]
                                 [{} macro-args])
    attr                       (if docstring
                                 (assoc attr :doc docstring)
                                 attr)
    attr                       (if (meta name)
                                 (conj (meta name) attr)
                                 attr)]
    [(with-meta name attr) macro-args]))
Vars in clojure.contrib.def/name-with-attributes: defn let
Used in 0 other vars

Comments top

No comments for name-with-attributes. Log in to add a comment.