Inspect common lisp macro source
Asked Answered
B

1

1

I wonder, if there is a way to inspect defined and loaded macros' source code from the repl?

Sort of macroexpand-1, but without the expansion.

Bolt answered 6/7, 2013 at 16:53 Comment(2)
Do you mean that you're looking for a way to, from a use of a macro, e.g., with-resource, such as (with-resource (...) ...), go to the corresponding definition (defmacro with-resource (...) ...)?Skinnydip
Yes, I meant exactly that.Bolt
M
5

You can get the macro definition using macro-function:

> (defmacro foo (x) `(* ,x ,x))
FOO
> (macro-function 'foo)
#<FUNCTION FOO (SYSTEM::<MACRO-FORM> SYSTEM::<ENV-ARG>) (DECLARE (CONS SYSTEM::<MACRO-FORM>))
  (DECLARE (IGNORE SYSTEM::<ENV-ARG>))
  (IF (NOT (SYSTEM::LIST-LENGTH-IN-BOUNDS-P SYSTEM::<MACRO-FORM> 2 2 NIL))
   (SYSTEM::MACRO-CALL-ERROR SYSTEM::<MACRO-FORM>)
   (LET* ((X (CADR SYSTEM::<MACRO-FORM>))) (BLOCK FOO `(* ,X ,X))))>

however, for most macros (especially the system ones) the code would be compiled:

> (macro-function 'with-open-file)
#<COMPILED-FUNCTION WITH-OPEN-FILE>

so, to understand how it works, you will have to disassemble it:

> (disassemble (macro-function 'with-open-file))

Disassembly of function WITH-OPEN-FILE
(CONST 0) = 2
(CONST 1) = SYSTEM::LIST-LENGTH-IN-BOUNDS-P
(CONST 2) = SYSTEM::MACRO-CALL-ERROR
(CONST 3) = 1
(CONST 4) = SOURCE-PROGRAM-ERROR
(CONST 5) = :FORM
(CONST 6) = :DETAIL
(CONST 7) = "~S: ~S does not match lambda list element ~:S"
(CONST 8) = SYSTEM::TEXT
(CONST 9) = WITH-OPEN-FILE
(CONST 10) = (STREAM &REST SYSTEM::OPTIONS)
(CONST 11) = LET
(CONST 12) = OPEN
(CONST 13) = DECLARE
(CONST 14) = SYSTEM::READ-ONLY
(CONST 15) = UNWIND-PROTECT
(CONST 16) = MULTIPLE-VALUE-PROG1
(CONST 17) = PROGN
(CONST 18) = WHEN
(CONST 19) = CLOSE
(CONST 20) = (:ABORT T)
2 required arguments
0 optional arguments
No rest parameter
No keyword parameters
78 byte-code instructions:
0     (LOAD&PUSH 2)
1     (CONST&PUSH 0)                      ; 2
2     (CONST&PUSH 0)                      ; 2
3     (T&PUSH)
4     (CALL 4 1)                          ; SYSTEM::LIST-LENGTH-IN-BOUNDS-P
7     (JMPIFNOT L85)
10    (LOAD 2)
11    (CDR)
12    (CAR&PUSH)
13    (LOAD&PUSH 0)
14    (CONST&PUSH 3)                      ; 1
15    (CONST&PUSH 3)                      ; 1
16    (T&PUSH)
17    (CALL 4 1)                          ; SYSTEM::LIST-LENGTH-IN-BOUNDS-P
20    (JMPIFNOT L90)
23    (LOAD&PUSH 0)
24    (LOAD&CAR&PUSH 0)
26    (LOAD&CDR&PUSH 1)
28    (LOAD 6)
29    (CDR)
30    (CDR&PUSH)
31    (LOAD&PUSH 0)
32    (PUSH-UNBOUND 1)
34    (CALLS1 105)                        ; SYSTEM::PARSE-BODY
36    (NV-TO-STACK 2)
38    (CONST&PUSH 11)                     ; LET
39    (LOAD&PUSH 5)
40    (CONST&PUSH 12)                     ; OPEN
41    (LOAD 6)
42    (CONS&PUSH)
43    (LIST&PUSH 2)
45    (LIST&PUSH 1)
47    (CONST&PUSH 13)                     ; DECLARE
48    (CONST&PUSH 14)                     ; SYSTEM::READ-ONLY
49    (LOAD&PUSH 8)
50    (LIST&PUSH 2)
52    (LOAD 4)
53    (CONS)
54    (CONS&PUSH)
55    (CONST&PUSH 15)                     ; UNWIND-PROTECT
56    (CONST&PUSH 16)                     ; MULTIPLE-VALUE-PROG1
57    (CONST&PUSH 17)                     ; PROGN
58    (LOAD 7)
59    (CONS&PUSH)
60    (CONST&PUSH 18)                     ; WHEN
61    (LOAD&PUSH 11)
62    (CONST&PUSH 19)                     ; CLOSE
63    (LOAD&PUSH 13)
64    (LIST&PUSH 2)
66    (LIST&PUSH 3)
68    (LIST&PUSH 3)
70    (CONST&PUSH 18)                     ; WHEN
71    (LOAD&PUSH 10)
72    (CONST&PUSH 19)                     ; CLOSE
73    (LOAD&PUSH 12)
74    (CONST 20)                          ; (:ABORT T)
75    (CONS)
76    (CONS&PUSH)
77    (LIST&PUSH 3)
79    (LIST&PUSH 3)
81    (LIST 4)
83    (SKIP&RET 10)
85    L85
85    (LOAD&PUSH 2)
86    (CALL1 2)                           ; SYSTEM::MACRO-CALL-ERROR
88    (SKIP&RET 3)
90    L90
90    (CONST&PUSH 4)                      ; SOURCE-PROGRAM-ERROR
91    (CONST&PUSH 5)                      ; :FORM
92    (LOAD&PUSH 5)
93    (CONST&PUSH 6)                      ; :DETAIL
94    (LOAD&PUSH 4)
95    (CONST&PUSH 7)                      ; "~S: ~S does not match lambda list element ~:S"
96    (CALL1&PUSH 8)                      ; SYSTEM::TEXT
98    (CONST&PUSH 9)                      ; WITH-OPEN-FILE
99    (LOAD&PUSH 7)
100   (CONST&PUSH 10)                     ; (STREAM &REST SYSTEM::OPTIONS)
101   (CALLSR 7 31)                       ; SYSTEM::ERROR-OF-TYPE

which is probably not very instructive for a novice.

Manly answered 10/7, 2013 at 21:16 Comment(1)
Oh, I had no idea that macros could be compiled, for some reason. Thank you.Bolt

© 2022 - 2024 — McMap. All rights reserved.