home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / prog_c / schem2c1.lzh / Scheme2C / Scheme-src.lzh / scsc / macros.sc < prev    next >
Encoding:
Text File  |  1991-10-11  |  15.7 KB  |  469 lines

  1. ;;; This file contains the "hard-wired" macros that are recognized by the
  2. ;;; compiler.  For the most part, they are "old-fashioned" macros and thus are
  3. ;;; invoked by the following function.
  4. ;;;
  5.  
  6. ;*              Copyright 1989 Digital Equipment Corporation
  7. ;*                         All Rights Reserved
  8. ;*
  9. ;* Permission to use, copy, and modify this software and its documentation is
  10. ;* hereby granted only under the following terms and conditions.  Both the
  11. ;* above copyright notice and this permission notice must appear in all copies
  12. ;* of the software, derivative works or modified versions, and any portions
  13. ;* thereof, and both notices must appear in supporting documentation.
  14. ;*
  15. ;* Users of this software agree to the terms and conditions set forth herein,
  16. ;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
  17. ;* right and license under any changes, enhancements or extensions made to the
  18. ;* core functions of the software, including but not limited to those affording
  19. ;* compatibility with other hardware or software environments, but excluding
  20. ;* applications which incorporate this software.  Users further agree to use
  21. ;* their best efforts to return to Digital any such changes, enhancements or
  22. ;* extensions that they make and inform Digital of noteworthy uses of this
  23. ;* software.  Correspondence should be provided to Digital at:
  24. ;* 
  25. ;*                       Director of Licensing
  26. ;*                       Western Research Laboratory
  27. ;*                       Digital Equipment Corporation
  28. ;*                       100 Hamilton Avenue
  29. ;*                       Palo Alto, California  94301  
  30. ;* 
  31. ;* This software may be distributed (but not offered for sale or transferred
  32. ;* for compensation) to third parties, provided such third parties agree to
  33. ;* abide by the terms and conditions of this notice.  
  34. ;* 
  35. ;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  36. ;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  37. ;* MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  38. ;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  39. ;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  40. ;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  41. ;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  42. ;* SOFTWARE.
  43.  
  44. (module macros)
  45.  
  46. (define (OLD-MACRO expand)
  47.     (lambda (exp exp-func) (exp-func (expand exp) exp-func)))
  48.  
  49. ;;; (quasiquote x)  ==> ?
  50. ;;;
  51. ;;; Quasiquote expansion is done using the function built into the Scheme
  52. ;;; interpreter.  The result is then macro expanded.
  53.  
  54. (define (QUASIQUOTE-MACRO exp)
  55.     (if (islist exp 2 2)
  56.     (quasiquotation 1 exp)
  57.     (expand-error 'quasiquote exp)))
  58.  
  59. ;;; Derived expression types are expanded in this module using the rules
  60. ;;; given in section 7.3 of Revised**3.
  61.  
  62. ;;; Conditional forms are expanded into if sequences.
  63.  
  64. (define (COND-MACRO exp)
  65.     (let* ((clauses  (cdr exp))
  66.        (clause1  (and clauses (car clauses)))
  67.        (clause2+ (and clause1 (cdr clauses))))
  68.       (cond ((null? clause1)
  69.          #f)
  70.         ((or (not (pair? clause1)) (equal? clause1 '(else)))
  71.          (expand-error 'cond-clause exp))
  72.         ((null? (cdr clause1))
  73.          `(or ,(car clause1) (cond ,@clause2+)))
  74.         ((and (eq? (cadr clause1) '=>) (= (length clause1) 3))
  75.          (let ((test-result (string->uninterned-symbol "TEST")))
  76.               `(let ((,test-result ,(car clause1)))
  77.                 (if ,test-result
  78.                 (,(caddr clause1) ,test-result)
  79.                 (cond ,@clause2+)))))
  80.         ((eq? (car clause1) 'else)
  81.          `(begin ,@(cdr clause1)))
  82.         (else `(if ,(car clause1)
  83.                (begin ,@(cdr clause1))
  84.                (cond ,@clause2+))))))
  85.  
  86. (define (CASE-MACRO exp)
  87.     (cond ((islist exp 3)
  88.        (do ((keyval (cadr exp))
  89.         (key (make-alpha 'k))
  90.         (cases (cddr exp) (cdr cases))
  91.         (ccs '()))
  92.            ((or (not (pair? cases)) (not (islist (car cases) 2)))
  93.         (cond (cases
  94.                (expand-error 'case exp))
  95.               (else
  96.                `(let ((,key ,keyval)) (cond ,@(reverse ccs))))))
  97.            (cond ((eq? (caar cases) 'else)
  98.               (set! ccs (cons (car cases) ccs)))
  99.              ((and (= (length (caar cases)) 1)
  100.                    (not (float? (caaar cases))))
  101.               (set! ccs
  102.                 (cons `((eq? ,key (quote ,(caaar cases)))
  103.                     ,@(cdar cases))
  104.                   ccs)))
  105.              ((= (length (caar cases)) 1)
  106.               (set! ccs
  107.                 (cons `((eqv? ,key (quote ,(caaar cases)))
  108.                     ,@(cdar cases))
  109.                   ccs)))
  110.              (else
  111.               (set! ccs
  112.                 (cons `((memv ,key (quote ,(caar cases)))
  113.                     ,@(cdar cases))
  114.                   ccs))))))
  115.       (else
  116.        (expand-error 'case exp))))
  117.  
  118. ;;; Boolean expressions are expanded here.  Boolean expressions involving
  119. ;;; constants are simplified here to save time during transformations.
  120.  
  121. (define (AND-MACRO exp)
  122.     (if (cdr exp)
  123.     (let ((x (boolean-constant (cadr exp))))
  124.          (cond ((pair? x)
  125.             (if (car x)
  126.             (if (cddr exp) `(and ,@(cddr exp)) (car x))
  127.             (car x)))
  128.            ((null? (cddr exp)) (cadr exp))
  129.            (else (let ((y (boolean-constant `(and ,@(cddr exp)))))
  130.                   (if (pair? y)
  131.                   `(let ((x ,(cadr exp)))
  132.                     (if x ,(car y) x))
  133.                   `(let ((x ,(cadr exp))
  134.                      (thunk (lambda ()
  135.                             (and ,@(cddr exp)))))
  136.                     (if x (thunk) x)))))))
  137.     #t))
  138.  
  139. (define (OR-MACRO exp)
  140.     (if (cdr exp)
  141.     (let ((x (boolean-constant (cadr exp))))
  142.          (cond ((pair? x)
  143.             (if (car x)
  144.             (car x)
  145.             (if (cddr exp) `(or ,@(cddr exp)) (car x))))
  146.            ((null? (cddr exp)) (cadr exp))
  147.            (else (let ((y (boolean-constant `(or ,@(cddr exp)))))
  148.                   (if (pair? y)
  149.                   `(let ((x ,(cadr exp)))
  150.                     (if x x ,(car y)))
  151.                   `(let ((x ,(cadr exp))
  152.                      (thunk (lambda () (or ,@(cddr exp)))))
  153.                     (if x x (thunk))))))))
  154.     #f))
  155.  
  156. (define (NOT-MACRO exp)
  157.     (if (islist exp 2 2)
  158.     (let ((x (boolean-constant (cadr exp))))
  159.          (if (pair? x)
  160.          (if (car x) #f #t)
  161.          `(if ,(cadr exp) #f #t)))
  162.     (expand-error 'not exp)))
  163.  
  164. ;;; Boolean constant expressions are evaluated by the following function.  It
  165. ;;; returns (<constant-value>) when a boolean constant is found, or #f when
  166. ;;; one is not found.
  167.  
  168. (define (BOOLEAN-CONSTANT exp)
  169.     (cond ((or (number? exp) (boolean? exp) (string? exp)
  170.            (and (pair? exp) (eq? (car exp) 'quote) (cadr exp)))
  171.        (list exp))
  172.       ((symbol? exp)
  173.        (let ((x (get exp 'macro)))
  174.         (if (pair? x)
  175.             (boolean-constant (car x))
  176.             #f)))
  177.       ((pair? exp)
  178.        (case (car exp)
  179.          ((not) (boolean-constant (not-macro exp)))
  180.          ((and) (boolean-constant (and-macro exp)))
  181.          ((or)  (boolean-constant (or-macro exp)))
  182.          (else #f)))
  183.       (else #f)))
  184.             
  185. ;;; (begin expression ...)  ==>  (let () expression ...)
  186. ;;;
  187. ;;; BEGIN becomes a let expression with no bindings.  Note the special case
  188. ;;; where a begin with only one expression simply becomes that expression.
  189.  
  190. (define (BEGIN-MACRO exp)
  191.     (cond ((not (islist exp 2))       (expand-error 'begin exp))
  192.       ((= (length exp) 2)       (cadr exp))
  193.       (else               `(let () ,@(cdr exp)))))
  194.  
  195. ;;; (let ((var init)...) body)  ==>  ((lambda (var...) body) init...)
  196. ;;;
  197. ;;; (let var ((v init) ...) body)  ==>  (letrec ((var (lambda (...) body)))
  198. ;;;                        (var init ...))
  199. ;;; LET is expanded into a lambda expression.  While this may make the
  200. ;;; resulting expanded code more difficult to read, later analysis is eased
  201. ;;; because there are fewer forms.  Variable order is retained to make the
  202. ;;; resulting tree easier to compare against the original tree.
  203. ;;;
  204. ;;; A "named let" is expanded into the appropriate letrec expression.  That in
  205. ;;; turn is expanded into the appropriate lambda expression when the letrec
  206. ;;; is expanded.
  207.  
  208. (define (LET-MACRO exp)
  209.     (cond ((and (islist exp 3) (islist (cadr exp) 0))
  210.        (do ((var-inits (cadr exp) (cdr var-inits))
  211.         (vars      '())
  212.         (inits     '()))
  213.            ((or (not (pair? var-inits))
  214.             (not (islist (car var-inits) 2 2))
  215.             (not (symbol? (caar var-inits))))
  216.         (if var-inits
  217.             (expand-error 'let exp)
  218.             `((lambda ,(reverse vars) ,@(cddr exp))
  219.               ,@(reverse inits))))
  220.            (set! vars (cons (caar var-inits) vars))
  221.            (set! inits (cons (cadar var-inits) inits))))
  222.       ((and (islist exp 4) (symbol? (cadr exp)))
  223.        (do ((var-inits (caddr exp) (cdr var-inits))
  224.         (vars      '())
  225.         (inits     '()))
  226.            ((or (not (pair? var-inits))
  227.             (not (islist (car var-inits) 2 2))
  228.             (not (symbol? (caar var-inits))))
  229.         (if var-inits
  230.             (expand-error 'let exp)
  231.             `(letrec ((,(cadr exp)
  232.                    (lambda ,(reverse vars) ,@(cdddr exp))))
  233.                  (,(cadr exp) ,@(reverse inits)))))
  234.            (set! vars (cons (caar var-inits) vars))
  235.            (set! inits (cons (cadar var-inits) inits))))
  236.       (else (expand-error 'let exp))))
  237.  
  238. ;;; (let* ((var init)...) body)  ==>  ((lambda (var)
  239. ;;;                           ((lambda (var) body) init))
  240. ;;;                       init)
  241. ;;;
  242. ;;; LET* is expanded into a set of nested lambda expressions.  While this may
  243. ;;; make the resulting code more difficult to read, later analysis is eased
  244. ;;; because there fewer types of forms to analyze.
  245.  
  246. (define (LET*-MACRO exp)
  247.     (cond ((and (islist exp 3) (islist (cadr exp) 1))
  248.        (do ((var-inits (cadr exp) (cdr var-inits))
  249.         (vars      '())
  250.         (inits     '()))
  251.            ((or (not (pair? var-inits))
  252.             (not (islist (car var-inits) 2 2))
  253.             (not (symbol? (caar var-inits))))
  254.         (if var-inits
  255.             (expand-error 'let* exp)
  256.             (car (let*-result vars inits (cddr exp)))))
  257.            (set! vars (cons (caar var-inits) vars))
  258.            (set! inits (cons (cadar var-inits) inits))))
  259.       ((and (islist exp 3) (null? (cadr exp)))
  260.        `((lambda () ,@(cddr exp))))
  261.       (else    (expand-error 'let* exp))))
  262.  
  263. (define (LET*-RESULT vars inits body)
  264.     (cond ((null? vars) body)
  265.       (else
  266.        (let*-result (cdr vars) (cdr inits)
  267.            `(((lambda (,(car vars)) ,@body) ,(car inits)))))))
  268.  
  269. ;;; (letrec ((var init)...) body)  ==>  ((lambda (var...)
  270. ;;;                         (set! var init) ...)
  271. ;;;                         body)
  272. ;;;                     undefined ...)
  273. ;;;
  274. ;;; LETREC is expanded into a lambda expression which first binds the vars to
  275. ;;; some undefined value and then evalutes the initialization expressions
  276. ;;; within the lambda expression.  Note that the order of evaluation is
  277. ;;; undefined.
  278.  
  279. (define (LETREC-MACRO exp)
  280.     (cond ((and (islist exp 3) (islist (cadr exp) 1))
  281.        (do ((var-inits (cadr exp) (cdr var-inits))
  282.         (vars      '())
  283.         (inits     '())
  284.         (sets      '()))
  285.            ((or (not (pair? var-inits))
  286.             (not (islist (car var-inits) 2 2))
  287.             (not (symbol? (caar var-inits))))
  288.         (if var-inits
  289.             (expand-error 'letrec exp)
  290.             `((lambda ,(reverse vars)
  291.                   ,@(reverse sets)
  292.                   ,@(cddr exp))
  293.               ,@(reverse inits))))
  294.            (let ((var (caar var-inits))
  295.              (init (cadar var-inits)))
  296.             (if (or (number? init)
  297.                 (string? init)
  298.                 (char? init)
  299.                 (memq init '(#t #f))
  300.                 (and (pair? init) (eq? (car init) 'quote)))
  301.             (set! inits (cons init inits))
  302.             (begin (set! inits (cons 0 inits))
  303.                    (set! sets (cons `(set! ,var ,init) sets))))
  304.             (set! vars (cons var vars)))))
  305.       ((and (islist exp 3) (null? (cadr exp)))
  306.        `((lambda () ,@(cddr exp))))
  307.       (else    (expand-error 'letrec exp))))
  308.  
  309. ;;; (do ((v1 i1 s1) ...) (test sequence) body ...)  ==>  (letrec ...)
  310. ;;;
  311. ;;; Expands a DO form into the corresponding letrec form.
  312.  
  313. (define  (DO-MACRO exp)
  314.     (cond ((and (islist exp 3) (islist (cadr exp) 0) (islist (caddr exp) 1))
  315.        (let ((let-bindings  (cadr exp))
  316.          (vars         '())
  317.          (inits     '())
  318.          (steps     '())
  319.          (loop        (string->uninterned-symbol "DOLOOP"))
  320.          (test             (caaddr exp))
  321.          (sequence      (or (cdaddr exp) '(#f)))
  322.          (body             (cdddr exp)))
  323.         (for-each
  324.             (lambda (var-init-step)
  325.                 (if (islist var-init-step 2 3)
  326.                 (let* ((var (car var-init-step))
  327.                        (init (cadr var-init-step))
  328.                        (step (if (cddr var-init-step)
  329.                          (caddr var-init-step)
  330.                          var)))
  331.                       (set! vars (cons var vars))
  332.                       (set! steps (cons step steps))
  333.                       (set! inits (cons init inits)))
  334.                 (expand-error 'do var-init-step)))
  335.             (reverse let-bindings))
  336.         `(letrec ((,loop (lambda ,vars
  337.                      (if ,test
  338.                          (begin ,@sequence)
  339.                          (begin ,@body
  340.                             (,loop ,@steps))))))
  341.              (,loop ,@inits))))
  342.       (else
  343.            (expand-error 'do exp))))
  344.  
  345. ;;; The forms QUOTE, INCLUDE, DEFINE-EXTERNAL and MODULE should not be
  346. ;;; expanded.  This is done by having them use the following macro.
  347.  
  348. (define (QUOTE-MACRO form expander) form)
  349.  
  350. ;;; The form DEFINE is expanded by the following.  Poorly formed
  351. ;;; expressions will be ignored for now, and picked up later when the
  352. ;;; form is evaluated.  Lambda variable lists are checked for duplicates.
  353.  
  354. (define (DEFINE-MACRO form expander)
  355.     (if (islist form 3)
  356.     (begin (cond ((symbol? (cadr form))
  357.               (set! current-define-name (cadr form)))
  358.              ((and (pair? (cadr form)) (symbol? (caadr form)))
  359.               (set! current-define-name (caadr form))
  360.               (duplicate-lambda-vars (cdadr form))))
  361.            (cons* (car form)
  362.               (cadr form)
  363.               (map (lambda (x) (expander x expander)) (cddr form))))
  364.     form))
  365.  
  366. ;;; The form LAMBDA is expanded by the following.  Poorly formed
  367. ;;; expressions will be ignored for now, and picked up later when the
  368. ;;; form is evaluated.  Variable lists are checked for duplicates.
  369.  
  370. (define (LAMBDA-MACRO form expander)
  371.     (if (islist form 3)
  372.     (begin (duplicate-lambda-vars (cadr form))
  373.            (cons* (car form)
  374.               (cadr form)
  375.               (map (lambda (x) (expander x expander)) (cddr form))))
  376.     form))
  377.  
  378. ;;; The following function checks lambda expression argument lists for
  379. ;;; duplicate variable names.
  380.  
  381. (define (DUPLICATE-LAMBDA-VARS vl)
  382.     (let loop ((vl vl) (seen '()))
  383.      (if (not (null? vl))
  384.          (let ((var (if (pair? vl) (car vl) vl)))
  385.           (if (memq var seen)
  386.               (report-error "Duplicately defined symbol:"
  387.               var))
  388.           (if (pair? vl) (loop (cdr vl) (cons var seen)))))))
  389.  
  390. ;;; The form DEFINE-MACRO is evaluated at macro expansion time as later macro
  391. ;;; expansion may wish to use it.
  392.  
  393. (define (DEFINE-MACRO-MACRO form expander)
  394.     (do-define-macro form)
  395.     form)
  396.  
  397. ;;; The form DEFINE-CONSTANT is evaluated at macro expansion time as later
  398. ;;; macro expansion may wish to use it.
  399.  
  400. (define (DEFINE-CONSTANT-MACRO form expander)
  401.     (do-define-constant form)
  402.     form)
  403.     
  404. ;;; The form EVAL-WHEN is used to provide conditional evaluation in
  405. ;;; various environments.
  406. ;;;
  407. ;;; (EVAL-WHEN situation form ...) ==> (begin form ...)
  408. ;;;                   ==> #f
  409. ;;;
  410. ;;; where situation is a list of any of COMPILE, EVAL, or LOAD.
  411.  
  412. (define (EVAL-WHEN-MACRO form expander)
  413.     (if (and (islist form 3) (islist (cadr form) 1))
  414.     (cond ((memq 'compile (cadr form))
  415.            form)
  416.           ((memq 'load (cadr form))
  417.            (let ((save-define-macro (get 'define-macro 'macro))
  418.              (save-define-constant (get 'define-constant 'macro)))
  419.             (put 'define-macro 'macro
  420.              (lambda (form expander)
  421.                  (expander `(putprop ',(cadr form)
  422.                         '*expander*
  423.                         ,(caddr form))
  424.                      expander)))
  425.             (put 'define-constant 'macro
  426.              (lambda (form expander)
  427.                  (expander `(putprop ',(cadr form)
  428.                         '*expander*
  429.                         (list ,(caddr form)))
  430.                      expander)))
  431.             (expander
  432.             `(begin ,@(cddr form)
  433.                 (eval-when (compile)
  434.                     (put 'define-macro 'macro
  435.                      ',save-define-macro)
  436.                     (put 'define-constant 'macro
  437.                      ',save-define-constant)))
  438.             expander))))
  439.     (expand-error 'EVAL-WHEN form)))
  440.  
  441. ;;; (WHEN test exp ...)  ==>  (if test (begin exp ...))
  442.  
  443. (define (WHEN-MACRO exp)
  444.     (if (islist exp 3)
  445.         `(if ,(cadr exp) (begin ,@(cddr exp)))
  446.         (expand-error 'WHEN exp)))
  447.  
  448. ;;; (UNLESS test exp ...)  ==>  (if (not test) (begin exp ...))
  449.  
  450. (define (UNLESS-MACRO exp)
  451.     (if (islist exp 3)
  452.         `(if (not ,(cadr exp)) (begin ,@(cddr exp)))
  453.         (expand-error 'UNLESS exp)))
  454.  
  455. ;;; LAP and LAP? expressions have their constants expanded by these functions.
  456.  
  457. (define (LAP-MACRO form expander)
  458.     (if (islist form 3)
  459.     (cons* (car form)
  460.            (cadr form)
  461.            (lap-constant-expand (cddr form) lap-constant-expand))
  462.     (expand-error (car form) form)))
  463.  
  464. (define (LAP-CONSTANT-EXPAND x e)
  465.     ((cond ((pair? x)   *sc-application-expander*)
  466.        ((symbol? x) *sc-identifier-expander*)
  467.        (else           (lambda (x e) x)))
  468.      x e))
  469.