mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-01 04:10:18 +02:00
* 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.
267 lines
7.8 KiB
Scheme
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))))))
|