]> git.donarmstrong.com Git - lilypond.git/blobdiff - guile18/lang/elisp/primitives/syntax.scm
Import guile-1.8 as multiple upstream tarball component
[lilypond.git] / guile18 / lang / elisp / primitives / syntax.scm
diff --git a/guile18/lang/elisp/primitives/syntax.scm b/guile18/lang/elisp/primitives/syntax.scm
new file mode 100644 (file)
index 0000000..6babb3d
--- /dev/null
@@ -0,0 +1,266 @@
+(define-module (lang elisp primitives syntax)
+  #: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))))))