flan/test/programs/macro-writing.flan

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)