60 lines
1.9 KiB
Plaintext
60 lines
1.9 KiB
Plaintext
;;;; Macros that write macros: a quasiquote inside a quasiquote.
|
|
;;;;
|
|
;;;; The outer quasiquote is desugared when the file is read, and the inner one
|
|
;;;; is data until the outer macro runs. What that macro answers is a defmacro
|
|
;;;; holding the inner quasiquote, which is desugared then, and the macro it
|
|
;;;; defines is compiled and called like one written by hand.
|
|
|
|
;; The inner ~x belongs to the inner quasiquote, so it is the generated
|
|
;; macro's own parameter and nothing the outer macro evaluates.
|
|
(defmacro defsquare [name]
|
|
`(defmacro ~name [x]
|
|
`(* ~x ~x)))
|
|
|
|
;; ~~n reaches out two levels: n is evaluated when defadder runs, and what it
|
|
;; holds is pasted into the inner template as an expression the generated
|
|
;; macro evaluates. A Form constructor is such an expression, so the literal
|
|
;; arrives as one.
|
|
(defmacro defadder [name n]
|
|
`(defmacro ~name [x]
|
|
`(+ ~x ~~n)))
|
|
|
|
;; ~@ inside the inner template is the inner macro's splice.
|
|
(defmacro defsum [name]
|
|
`(defmacro ~name [& xs]
|
|
`(+ 0 ~@xs)))
|
|
|
|
;; Two levels down: a macro that writes a macro that writes a macro.
|
|
(defmacro defsquarer [name]
|
|
`(defmacro ~name [inner]
|
|
`(defmacro ~inner [x]
|
|
`(* ~x ~x))))
|
|
|
|
;; ~~@xs: each form the outer macro was handed becomes one ~x in the inner
|
|
;; template, in a list and in a vector.
|
|
(defmacro defmany [name & xs]
|
|
`(defmacro ~name []
|
|
`(+ 0 ~~@xs)))
|
|
|
|
(defmacro deflet [name & xs]
|
|
`(defmacro ~name [body]
|
|
`(let [~~@xs] ~body)))
|
|
|
|
(defsquare sq)
|
|
(defmany six (Form.Int {.i 1}) (Form.Int {.i 2}) (Form.Int {.i 3}))
|
|
(deflet with-ab (Form.Sym {.s "a"}) (Form.Int {.i 4})
|
|
(Form.Sym {.s "b"}) (Form.Int {.i 5}))
|
|
(defadder add5 (Form.Int {.i 5}))
|
|
(defsum total)
|
|
(defsquarer defsq2)
|
|
(defsq2 sq2)
|
|
|
|
(defn main [] i32
|
|
(print (sq 7)) (println "")
|
|
(print (add5 10)) (println "")
|
|
(print (total 1 2 3 4)) (println "")
|
|
(print (sq2 9)) (println "")
|
|
(print (six)) (println "")
|
|
(print (with-ab (* a b))) (println "")
|
|
0)
|