Previous: Function Bindings, Up: Variable Bindings

4.3.3 Macro Bindings

These forms create local macros and “symbol macros”.

— Macro: cl-macrolet (bindings...) forms...

This form is analogous to cl-flet, but for macros instead of functions. Each binding is a list of the same form as the arguments to cl-defmacro (i.e., a macro name, argument list, and macro-expander forms). The macro is defined accordingly for use within the body of the cl-macrolet.

Because of the nature of macros, cl-macrolet is always lexically scoped. The cl-macrolet binding will affect only calls that appear physically within the body forms, possibly after expansion of other macros in the body.

— Macro: cl-symbol-macrolet (bindings...) forms...

This form creates symbol macros, which are macros that look like variable references rather than function calls. Each binding is a list ‘(var expansion)’; any reference to var within the body forms is replaced by expansion.

          (setq bar '(5 . 9))
          (cl-symbol-macrolet ((foo (car bar)))
            (cl-incf foo))
          bar
               ⇒ (6 . 9)

A setq of a symbol macro is treated the same as a setf. I.e., (setq foo 4) in the above would be equivalent to (setf foo 4), which in turn expands to (setf (car bar) 4).

Likewise, a let or let* binding a symbol macro is treated like a cl-letf or cl-letf*. This differs from true Common Lisp, where the rules of lexical scoping cause a let binding to shadow a symbol-macrolet binding. In this package, such shadowing does not occur, even when lexical-binding is t. (This behavior predates the addition of lexical binding to Emacs Lisp, and may change in future to respect lexical-binding.) At present in this package, only lexical-let and lexical-let* will shadow a symbol macro. See Obsolete Lexical Binding.

There is no analogue of defmacro for symbol macros; all symbol macros are local. A typical use of cl-symbol-macrolet is in the expansion of another macro:

          (cl-defmacro my-dolist ((x list) &rest body)
            (let ((var (cl-gensym)))
              (list 'cl-loop 'for var 'on list 'do
                    (cl-list* 'cl-symbol-macrolet
                              (list (list x (list 'car var)))
                              body))))
          
          (setq mylist '(1 2 3 4))
          (my-dolist (x mylist) (cl-incf x))
          mylist
               ⇒ (2 3 4 5)

In this example, the my-dolist macro is similar to dolist (see Iteration) except that the variable x becomes a true reference onto the elements of the list. The my-dolist call shown here expands to

          (cl-loop for G1234 on mylist do
                (cl-symbol-macrolet ((x (car G1234)))
                  (cl-incf x)))

which in turn expands to

          (cl-loop for G1234 on mylist do (cl-incf (car G1234)))

See Loop Facility, for a description of the cl-loop macro. This package defines a nonstandard in-ref loop clause that works much like my-dolist.