1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 04:10:18 +02:00
guile/lang/elisp/primitives/syntax.scm
Andy Wingo 39f30ea29d Fix the elisp memoizer code for syncase-in-boot-9
* lang/elisp/interface.scm:
* lang/elisp/internals/lambda.scm:
* lang/elisp/primitives/syntax.scm:
* lang/elisp/transform.scm: Use (lang elisp expand) as the transformer,
  because we really are intending this code for the memoizer and not the
  compiler.

* lang/elisp/expand.scm: A null expander.

* lang/elisp/interface.scm (use-elisp-file, use-elisp-library):
* lang/elisp/transform.scm (scheme): Turn these defmacros into
  procedure->memoizing-macro calls, given that without syncase we have no
  defmacro either.

* lang/elisp/primitives/fns.scm (macroexpand): Comment out, as Scheme's
  macro expander (temporarily on hiatus) won't work with elisp.
2009-04-25 19:09:19 +02:00

267 lines
7.8 KiB
Scheme

(define-module (lang elisp primitives syntax)
#:use-syntax (lang elisp expand)
#:use-module (lang elisp internals evaluation)
#:use-module (lang elisp internals fset)
#:use-module (lang elisp internals lambda)
#:use-module (lang elisp internals set)
#:use-module (lang elisp internals trace)
#:use-module (lang elisp transform))
;;; Define Emacs Lisp special forms as macros. This is more flexible
;;; than handling them specially in the translator: allows them to be
;;; redefined, and hopefully allows better source location tracking.
;;; {Variables}
(define (setq exp env)
(cons begin
(let loop ((sets (cdr exp)))
(if (null? sets)
'()
(cons `(,set (,quote ,(car sets)) ,(transformer (cadr sets)))
(loop (cddr sets)))))))
(fset 'setq
(procedure->memoizing-macro setq))
(fset 'defvar
(procedure->memoizing-macro
(lambda (exp env)
(trc 'defvar (cadr exp))
(if (null? (cddr exp))
`(,quote ,(cadr exp))
`(,begin (,if (,not (,defined? (,quote ,(cadr exp))))
,(setq (list (car exp) (cadr exp) (caddr exp)) env))
(,quote ,(cadr exp)))))))
(fset 'defconst
(procedure->memoizing-macro
(lambda (exp env)
(trc 'defconst (cadr exp))
`(,begin ,(setq (list (car exp) (cadr exp) (caddr exp)) env)
(,quote ,(cadr exp))))))
;;; {lambda, function and macro definitions}
(fset 'lambda
(procedure->memoizing-macro
(lambda (exp env)
(transform-lambda/interactive exp '<elisp-lambda>))))
(fset 'defun
(procedure->memoizing-macro
(lambda (exp env)
(trc 'defun (cadr exp))
`(,begin (,fset (,quote ,(cadr exp))
,(transform-lambda/interactive (cdr exp)
(symbol-append '<elisp-defun:
(cadr exp)
'>)))
(,quote ,(cadr exp))))))
(fset 'interactive
(procedure->memoizing-macro
(lambda (exp env)
(fluid-set! interactive-spec exp)
#f)))
(fset 'defmacro
(procedure->memoizing-macro
(lambda (exp env)
(trc 'defmacro (cadr exp))
(call-with-values (lambda () (parse-formals (caddr exp)))
(lambda (required optional rest)
(let ((num-required (length required))
(num-optional (length optional)))
`(,begin (,fset (,quote ,(cadr exp))
(,procedure->memoizing-macro
(,lambda (exp1 env1)
(,trc (,quote using) (,quote ,(cadr exp)))
(,let* ((%--args (,cdr exp1))
(%--num-args (,length %--args)))
(,cond ((,< %--num-args ,num-required)
(,error "Wrong number of args (not enough required args)"))
,@(if rest
'()
`(((,> %--num-args ,(+ num-required num-optional))
(,error "Wrong number of args (too many args)"))))
(else (,transformer
(, @bind ,(append (map (lambda (i)
(list (list-ref required i)
`(,list-ref %--args ,i)))
(iota num-required))
(map (lambda (i)
(let ((i+nr (+ i num-required)))
(list (list-ref optional i)
`(,if (,> %--num-args ,i+nr)
(,list-ref %--args ,i+nr)
,%nil))))
(iota num-optional))
(if rest
(list (list rest
`(,if (,> %--num-args
,(+ num-required
num-optional))
(,list-tail %--args
,(+ num-required
num-optional))
,%nil)))
'()))
,@(map transformer (cdddr exp)))))))))))))))))
;;; {Sequencing}
(fset 'progn
(procedure->memoizing-macro
(lambda (exp env)
`(,begin ,@(map transformer (cdr exp))))))
(fset 'prog1
(procedure->memoizing-macro
(lambda (exp env)
`(,let ((%--res1 ,(transformer (cadr exp))))
,@(map transformer (cddr exp))
%--res1))))
(fset 'prog2
(procedure->memoizing-macro
(lambda (exp env)
`(,begin ,(transformer (cadr exp))
(,let ((%--res2 ,(transformer (caddr exp))))
,@(map transformer (cdddr exp))
%--res2)))))
;;; {Conditionals}
(fset 'if
(procedure->memoizing-macro
(lambda (exp env)
(let ((else-case (cdddr exp)))
(cond ((null? else-case)
`(,nil-cond ,(transformer (cadr exp)) ,(transformer (caddr exp)) ,%nil))
((null? (cdr else-case))
`(,nil-cond ,(transformer (cadr exp))
,(transformer (caddr exp))
,(transformer (car else-case))))
(else
`(,nil-cond ,(transformer (cadr exp))
,(transformer (caddr exp))
(,begin ,@(map transformer else-case)))))))))
(fset 'and
(procedure->memoizing-macro
(lambda (exp env)
(cond ((null? (cdr exp)) #t)
((null? (cddr exp)) (transformer (cadr exp)))
(else
(cons nil-cond
(let loop ((args (cdr exp)))
(if (null? (cdr args))
(list (transformer (car args)))
(cons (list not (transformer (car args)))
(cons %nil
(loop (cdr args))))))))))))
;;; NIL-COND expressions have the form:
;;;
;;; (nil-cond COND VAL COND VAL ... ELSEVAL)
;;;
;;; The CONDs are evaluated in order until one of them returns true
;;; (in the Elisp sense, so not including empty lists). If a COND
;;; returns true, its corresponding VAL is evaluated and returned,
;;; except if that VAL is the unspecified value, in which case the
;;; result of evaluating the COND is returned. If none of the COND's
;;; returns true, ELSEVAL is evaluated and its value returned.
(define <-- *unspecified*)
(fset 'or
(procedure->memoizing-macro
(lambda (exp env)
(cond ((null? (cdr exp)) %nil)
((null? (cddr exp)) (transformer (cadr exp)))
(else
(cons nil-cond
(let loop ((args (cdr exp)))
(if (null? (cdr args))
(list (transformer (car args)))
(cons (transformer (car args))
(cons <--
(loop (cdr args))))))))))))
(fset 'cond
(procedure->memoizing-macro
(lambda (exp env)
(if (null? (cdr exp))
%nil
(cons
nil-cond
(let loop ((clauses (cdr exp)))
(if (null? clauses)
(list %nil)
(let ((clause (car clauses)))
(if (eq? (car clause) #t)
(cond ((null? (cdr clause)) (list #t))
((null? (cddr clause))
(list (transformer (cadr clause))))
(else `((,begin ,@(map transformer (cdr clause))))))
(cons (transformer (car clause))
(cons (cond ((null? (cdr clause)) <--)
((null? (cddr clause))
(transformer (cadr clause)))
(else
`(,begin ,@(map transformer (cdr clause)))))
(loop (cdr clauses)))))))))))))
(fset 'while
(procedure->memoizing-macro
(lambda (exp env)
`((,letrec ((%--while (,lambda ()
(,nil-cond ,(transformer (cadr exp))
(,begin ,@(map transformer (cddr exp))
(%--while))
,%nil))))
%--while)))))
;;; {Local binding}
(fset 'let
(procedure->memoizing-macro
(lambda (exp env)
`(, @bind ,(map (lambda (binding)
(trc 'let binding)
(if (pair? binding)
`(,(car binding) ,(transformer (cadr binding)))
`(,binding ,%nil)))
(cadr exp))
,@(map transformer (cddr exp))))))
(fset 'let*
(procedure->memoizing-macro
(lambda (exp env)
(if (null? (cadr exp))
`(,begin ,@(map transformer (cddr exp)))
(car (let loop ((bindings (cadr exp)))
(if (null? bindings)
(map transformer (cddr exp))
`((, @bind (,(let ((binding (car bindings)))
(if (pair? binding)
`(,(car binding) ,(transformer (cadr binding)))
`(,binding ,%nil))))
,@(loop (cdr bindings)))))))))))
;;; {Exception handling}
(fset 'unwind-protect
(procedure->memoizing-macro
(lambda (exp env)
(trc 'unwind-protect (cadr exp))
`(,let ((%--throw-args #f))
(,catch #t
(,lambda ()
,(transformer (cadr exp)))
(,lambda args
(,set! %--throw-args args)))
,@(map transformer (cddr exp))
(,if %--throw-args
(,apply ,throw %--throw-args))))))