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.
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.
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.