README-elpa (10191B)
1 1 macrostep: interactive macro-expander 2 ═══════════════════════════════════════ 3 4 `macrostep' is an Emacs minor mode for interactively stepping through 5 the expansion of macros in Emacs Lisp source code. It lets you see 6 exactly what happens at each step of the expansion process by 7 pretty-printing the expanded forms inline in the source buffer, which 8 is temporarily read-only while macro expansions are visible. You can 9 expand and collapse macro forms one step at a time, and evaluate or 10 instrument the expansions for debugging with Edebug as normal (but see 11 "Bugs and known limitations", below). Single-stepping through the 12 expansion is particularly useful for debugging macros that expand into 13 another macro form. These can be difficult to debug with Emacs' 14 built-in `macroexpand', which continues expansion until the top-level 15 form is no longer a macro call. 16 17 Both globally-visible macros as defined by `defmacro' and local macros 18 bound by `(cl-)macrolet' or another macro-defining form can be 19 expanded. Within macro expansions, calls to macros and compiler 20 macros are fontified specially: macro forms using 21 `macrostep-macro-face', and functions with compiler macros using 22 `macrostep-compiler-macro-face'. Uninterned symbols (gensyms) are 23 fontified based on which step in the expansion created them, to 24 distinguish them both from normal symbols and from other gensyms with 25 the same print name. 26 27 As of version 0.9, it is also possible to extend `macrostep' to work 28 with other languages with macro systems in addition to Emacs Lisp. An 29 extension for Common Lisp (via SLIME) is in the works; contributions 30 for other languages are welcome. See "Extending macrostep" below for 31 details. 32 33 34 1.1 Key-bindings and usage 35 ────────────────────────── 36 37 The standard keybindings in `macrostep-mode' are the following: 38 39 e, =, RET 40 expand the macro form following point one step 41 c, u, DEL 42 collapse the form following point 43 q, C-c C-c 44 collapse all expanded forms and exit macrostep-mode 45 n, TAB 46 jump to the next macro form in the expansion 47 p, M-TAB 48 jump to the previous macro form in the expansion 49 50 It's not very useful to enable and disable macrostep-mode directly. 51 Instead, bind `macrostep-expand' to a key in `emacs-lisp-mode-map', 52 for example C-c e: 53 54 ┌──── 55 │ (define-key emacs-lisp-mode-map (kbd "C-c e") 'macrostep-expand) 56 └──── 57 58 You can then enter macrostep-mode and expand a macro form completely 59 by typing `C-c e e e ...' as many times as necessary. 60 61 Exit macrostep-mode by typing `q' or `C-c C-c', or by successively 62 typing `c' to collapse all surrounding expansions. 63 64 65 1.2 Customization options 66 ───────────────────────── 67 68 Type `M-x customize-group RET macrostep RET' to customize options and 69 faces. 70 71 To display macro expansions in a separate window, instead of inline in 72 the source buffer, customize `macrostep-expand-in-separate-buffer' to 73 `t'. The default is `nil'. Whichever default behavior is selected, 74 the alternative behavior can be obtained temporarily by giving a 75 prefix argument to `macrostep-expand'. 76 77 To have `macrostep' ignore compiler macros, customize 78 `macrostep-expand-compiler-macros' to `nil'. The default is `t'. 79 80 Customize the faces `macrostep-macro-face', 81 `macrostep-compiler-macro-face', and `macrostep-gensym-1' through 82 `macrostep-gensym-5' to alter the appearance of macro expansions. 83 84 85 1.3 Locally-bound macros 86 ──────────────────────── 87 88 As of version 0.9, `macrostep' can expand calls to a locally-bound 89 macro, whether defined by a surrounding `(cl-)macrolet' form, or by 90 another macro-defining macro. In other words, it is possible to 91 expand the inner `local-macro' forms in both the following examples, 92 whether `local-macro' is defined by an enclosing `cl-macrolet' – 93 94 ┌──── 95 │ (cl-macrolet ((local-macro (&rest args) 96 │ `(expansion of ,args))) 97 │ (local-macro (do-something))) 98 └──── 99 100 – or by a macro which expands into `cl-macrolet', provided that its 101 definition of macro is evaluated prior to calling `macrostep-expand': 102 103 ┌──── 104 │ (defmacro with-local-macro (&rest body) 105 │ `(cl-macrolet ((local-macro (&rest args) 106 │ `(expansion of ,args))) 107 │ ,@body)) 108 │ 109 │ (with-local-macro 110 │ (local-macro (do something (else))) 111 └──── 112 113 See the `with-js' macro in Emacs's `js.el' for a real example of the 114 latter kind of macro. 115 116 Expansion of locally-bound macros is implemented by instrumenting 117 Emacs Lisp's macro-expander to capture the environment at point. A 118 similar trick is used to detect macro- and compiler-macro calls within 119 expanded text so that they can be fontified accurately. 120 121 122 1.4 Expanding sub-forms 123 ─────────────────────── 124 125 By moving point around in the macro expansion using 126 `macrostep-next-macro' and `macrostep-prev-macro' (bound to the `n' 127 and `p' keys), it is possible to expand other macro calls within the 128 expansion before expanding the outermost form. This can sometimes be 129 useful, although it does not correspond to the real order of macro 130 expansion in Emacs Lisp, which proceeds by fully expanding the outer 131 form to a non-macro form before expanding sub-forms. 132 133 The main reason to expand sub-forms out of order is to help with 134 debugging macros which programmatically expand their arguments in 135 order to rewrite them. Expanding the arguments of such a macro lets 136 you visualise what the macro definition would compute via 137 `macroexpand-all'. 138 139 140 1.5 Extending macrostep for other languages 141 ─────────────────────────────────────────── 142 143 Since version 0.9, it is possible to extend macrostep to work with 144 other languages besides Emacs Lisp. In typical Emacs fashion, this is 145 implemented by setting buffer-local variables to different function 146 values. Six buffer-local variables define the language-specific part 147 of the implementation: 148 149 • `macrostep-sexp-bounds-function' 150 • `macrostep-sexp-at-point-function' 151 • `macrostep-environment-at-point-function' 152 • `macrostep-expand-1-function' 153 • `macrostep-print-function' 154 • `macrostep-macro-form-p-function' 155 156 Typically, an implementation for another language would set these 157 variables in a major-mode hook. See the docstrings of each variable 158 for details on how each one is called and what it should return. At a 159 minimum, another language implementation needs to provide 160 `macrostep-sexp-at-point-function', `macrostep-expand-1-function', and 161 `macrostep-print-function'. Lisp-like languages may be able to reuse 162 the default `macrostep-sexp-bounds-function' if they provide another 163 implementation of `macrostep-macro-form-p-function'. Languages which 164 do not implement locally-defined macros can set 165 `macrostep-environment-at-point-function' to `ignore'. 166 167 Note that the core `macrostep' machinery only interprets the return 168 value of `macrostep-sexp-bounds-function', so implementations for 169 other languages can use any internal representations of code and 170 environments which is convenient. Although the terminology is 171 Lisp-specific, there is no reason that implementations could not be 172 provided for non-Lisp languages with macro systems, provided there is 173 some way of identifying macro calls and calling the compiler / 174 preprocessor to obtain their expansions. 175 176 177 1.6 Bugs and known limitations 178 ────────────────────────────── 179 180 You can evaluate and edebug macro-expanded forms and step through the 181 macro-expanded version, but the form that `eval-defun' and friends 182 read from the buffer won't have the uninterned symbols of the real 183 macro expansion. This will probably work OK with CL-style gensyms, 184 but may cause problems with `make-symbol' symbols if they have the 185 same print name as another symbol in the expansion. It's possible that 186 using `print-circle' and `print-gensym' could get around this. 187 188 Please send other bug reports and feature requests to the author. 189 190 191 1.7 Acknowledgements 192 ──────────────────── 193 194 Thanks to: 195 • John Wiegley for fixing a bug with the face definitions under Emacs 196 24 & for plugging macrostep in his [EmacsConf presentation]! 197 • George Kettleborough for bug reports, and patches to highlight the 198 expanded region and properly handle backquotes. 199 • Nic Ferrier for suggesting support for local definitions within 200 macrolet forms 201 • Luís Oliveira for suggesting and implementing SLIME support 202 203 `macrostep' was originally inspired by J. V. Toups's 'Deep Emacs Lisp' 204 articles ([part 1], [part 2], [screencast]). 205 206 207 [EmacsConf presentation] <http://youtu.be/RvPFZL6NJNQ> 208 209 [part 1] 210 <http://dorophone.blogspot.co.uk/2011/04/deep-emacs-part-1.html> 211 212 [part 2] 213 <http://dorophone.blogspot.co.uk/2011/04/deep-emacs-lisp-part-2.html> 214 215 [screencast] 216 <http://dorophone.blogspot.co.uk/2011/05/monadic-parser-combinators-in-elisp.html> 217 218 219 1.8 Changelog 220 ───────────── 221 222 • v0.9, 2015-10-01: 223 • separate into Elisp-specific and generic components 224 • highlight and expand compiler macros 225 • improve local macro expansion and macro form identification by 226 instrumenting `macroexpand(-all)' 227 • v0.8, 2014-05-29: fix a bug with printing the first element of lists 228 • v0.7, 2014-05-11: expand locally-defined macros within 229 `(cl-)macrolet' forms 230 • v0.6, 2013-05-04: better handling of quote and backquote 231 • v0.5, 2013-04-16: highlight region, maintain cleaner buffer state 232 • v0.4, 2013-04-07: only enter macrostep-mode on successful 233 macro-expansion 234 • v0.3, 2012-10-30: print dotted lists correctly. autoload 235 definitions.