mark multi-form macro expansions with $

A bare list was read as several forms, so a macro returning
`((make-adder 10) 5)' -- a call of what make-adder returns -- was
spliced into two. Add a new $ char to denote splicing, so ($ form ...)
splices.
This commit is contained in:
2026-09-29 23:51:41 +03:00
parent 6f54bfbe08
commit 53f92727a5
3 changed files with 62 additions and 10 deletions

View File

@@ -52,22 +52,29 @@
(cons (car forms) (take-until (cdr forms) tail))))
(define (macroexpand macro-form rest-forms)
;; We want to replace macro with its expansion. The problem is,
;; top-level macro can return either a single form, or a list of
;; forms, when it for example generates some aux
;; structures/functions/typedefs.
;; `(defmacro (two) 2)' expands to `2', and `($ (fn a ...) (fn b ...))'
;; to two forms, spliced where the macro was written. `($)' expands to
;; nothing.
;;
;; Single form we just cons to the top of rest-forms, but multiple
;; forms have to be appended to the rest-forms.
;; Everything else is one form, a list whose head is itself a form
;; included: `((make-adder 10) 5)' calls what `make-adder' returned,
;; and without `$' to mark a splice there is no telling that from a
;; list of the two forms `(make-adder 10)' and `5'.
(let ((res (apply-macro macro-form))
(src (form-source macro-form)))
;; An expansion is fresh structure with no location of its own. Give
;; it the call site's, the way cpp attributes a macro body to where
;; the macro was used
(if (list? (car res))
(append (map (lambda (f) (stamp-form-source! f src)) res)
rest-forms)
(cons (stamp-form-source! res src) rest-forms))))
(cond
((splice-form? res)
(append (map (lambda (f) (stamp-form-source! f src)) (cdr res))
rest-forms))
((null? res) rest-forms)
(else
(cons (stamp-form-source! res src) rest-forms)))))
(define (splice-form? form)
(and (pair? form) (list? form) (eq? '$ (car form))))
(define (match-sex-form sex-form acc)
(match sex-form