1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-02 13:00:26 +02:00

Implemented real quotation (added support for backquotation).

* module/language/elisp/README: Document that.
* module/language/elisp/compile-tree-il.scm: Implement backquote.
* test-suite/tests/elisp-compiler.test: Test quotation and backquotes.
This commit is contained in:
Daniel Kraft 2009-07-18 17:32:59 +02:00
parent e905e490fa
commit 9b5ff6a6e1
3 changed files with 98 additions and 1 deletions

View file

@ -15,6 +15,7 @@ Already implemented:
* some built-ins (mainly numbers/arithmetic) * some built-ins (mainly numbers/arithmetic)
* defconst, defvar, defun * defconst, defvar, defun
* macros * macros
* quotation and backquotation with unquote/unquote-splicing
Especially still missing: Especially still missing:
* other progX forms, will be done in macros * other progX forms, will be done in macros
@ -28,7 +29,6 @@ Especially still missing:
* fset & friends, defalias functions * fset & friends, defalias functions
* advice? * advice?
* defsubst and inlining * defsubst and inlining
* real quoting
* need fluids for function bindings? * need fluids for function bindings?
* recursive macros * recursive macros
* anonymous macros * anonymous macros

View file

@ -50,6 +50,26 @@
(define macro-slot '(language elisp runtime macro-slot)) (define macro-slot '(language elisp runtime macro-slot))
; The backquoting works the same as quasiquotes in Scheme, but the forms are
; named differently; to make easy adaptions, we define these predicates checking
; for a symbol being the car of an unquote/unquote-splicing/backquote form.
; FIXME: Remove the quasiquote/unquote/unquote-splicing symbols when real elisp
; reader is there.
(define (backquote? sym)
(and (symbol? sym) (or (eq? sym 'quasiquote)
(eq? sym '\`))))
(define (unquote? sym)
(and (symbol? sym) (or (eq? sym 'unquote)
(eq? sym '\,))))
(define (unquote-splicing? sym)
(and (symbol? sym) (or (eq? sym 'unquote-splicing)
(eq? sym '\,@))))
; Build a call to a primitive procedure nicely. ; Build a call to a primitive procedure nicely.
(define (call-primitive loc sym . args) (define (call-primitive loc sym . args)
@ -301,6 +321,51 @@
(module-ref (resolve-module macro-slot) sym)) (module-ref (resolve-module macro-slot) sym))
; See if a (backquoted) expression contains any unquotes.
(define (contains-unquotes? expr)
(if (pair? expr)
(if (or (unquote? (car expr)) (unquote-splicing? (car expr)))
#t
(or (contains-unquotes? (car expr))
(contains-unquotes? (cdr expr))))
#f))
; Process a backquoted expression by building up the needed cons/append calls.
; For splicing, it is assumed that the expression spliced in evaluates to a
; list. The emacs manual does not really state either it has to or what to do
; if it does not, but Scheme explicitly forbids it and this seems reasonable
; also for elisp.
(define (unquote-cell? expr)
(and (list? expr) (= (length expr) 2) (unquote? (car expr))))
(define (unquote-splicing-cell? expr)
(and (list? expr) (= (length expr) 2) (unquote-splicing? (car expr))))
(define (process-backquote loc expr)
(if (contains-unquotes? expr)
(if (pair? expr)
(if (or (unquote-cell? expr) (unquote-splicing-cell? expr))
(compile-expr (cadr expr))
(let* ((head (car expr))
(processed-tail (process-backquote loc (cdr expr)))
(head-is-list-2 (and (list? head) (= (length head) 2)))
(head-unquote (and head-is-list-2 (unquote? (car head))))
(head-unquote-splicing (and head-is-list-2
(unquote-splicing? (car head)))))
(if head-unquote-splicing
(call-primitive loc 'append
(compile-expr (cadr head)) processed-tail)
(call-primitive loc 'cons
(if head-unquote
(compile-expr (cadr head))
(process-backquote loc head))
processed-tail))))
(error "non-pair expression contains unquotes" expr))
(make-const loc expr)))
; Compile a symbol expression. This is a variable reference or maybe some ; Compile a symbol expression. This is a variable reference or maybe some
; special value like nil. ; special value like nil.
@ -499,6 +564,10 @@
(define-macro! loc name object) (define-macro! loc name object)
(make-const loc name)))) (make-const loc name))))
((,backq ,val) (guard (backquote? backq))
(process-backquote loc val))
; XXX: Why do we need 'quote here instead of quote?
(('quote ,val) (('quote ,val)
(make-const loc val)) (make-const loc val))

View file

@ -211,6 +211,34 @@
(zerop a))))) (zerop a)))))
; Quoting and Backquotation.
; ==========================
(with-test-prefix/compile "Quotation"
(pass-if "quote"
(and (equal '42 42) (equal '"abc" "abc")
(equal '(1 2 (3 (4) x)) '(1 2 (3 (4) x)))
(not (equal '(1 2 (3 4 (x))) '(1 2 3 4 x)))
(equal '(1 2 . 3) '(1 2 . 3))))
(pass-if "simple backquote"
(and (equal (\` 42) 42)
(equal (\` (1 (a))) '(1 (a)))
(equal (\` (1 . 2)) '(1 . 2))))
(pass-if "unquote"
(progn (setq a 42 l '(18 12))
(and (equal (\` (\, a)) 42)
(equal (\` (1 a ((\, l)) . (\, a))) '(1 a ((18 12)) . 42)))))
(pass-if "unquote splicing"
(progn (setq l '(18 12) empty '())
(and (equal (\` (\,@ l)) '(18 12))
(equal (\` (l 2 (3 (\,@ l)) ((\,@ l)) (\,@ l)))
'(l 2 (3 18 12) (18 12) 18 12))
(equal (\` (1 2 (\,@ empty) 3)) '(1 2 3))))))
; Macros. ; Macros.
; ======= ; =======