home *** CD-ROM | disk | FTP | other *** search
/ Eagles Nest BBS 8 / Eagles_Nest_Mac_Collection_Disc_8.TOAST / Developer Tools⁄Additions / MacScheme20 / Contributed / ExtendSyntax / extendsyntax.sch < prev   
Encoding:
Text File  |  1988-12-15  |  13.5 KB  |  388 lines  |  [TEXT/EDIT]

  1. ; This code, contributed by Jeff De Vries, has been modified to remove the
  2. ; assumption that #f is the same as the empty list.  Three changes were
  3. ; required: changing a null? to a not in add-car, add-cdr, and gen.
  4. ;
  5. ; From: jdevries@ads.arpa (Jeff De Vries)
  6. ; Subject: Extend-Syntax for Everybody!
  7. ; Date: 15 Nov 87 20:54:13 GMT
  8. ; By popular demand I have decided to go ahead and post the code for the
  9. ; MacScheme version of extend-syntax.  I had (have?) over 40 requests,
  10. ; (some of which I can't seem to respond to due to always getting bounced),
  11. ; plus other indicators that some people are just waiting for me to post it.
  12. ; To those of you who have no interest in this, I apologize for the long
  13. ; posting, (just hit your 'junk' key, if you have one).  
  14. ; But first, a few words:
  15. ; The theoretical work and basic design behind extend-syntax was the work of 
  16. ; Eugene Kohlbecker.  It was part of his Ph.D. dissertation, "Syntactic 
  17. ; Extensions in the Programming Language LISP", (Indiana University, 1986).  
  18. ; The enhanced version of the code that I used for the MacScheme version was 
  19. ; written by R. Kent Dybvig, and made available by him.
  20. ; A more complete description of Kent's book is:
  21. ;  The Scheme Programming Language
  22. ;  R. Kent Dybvig
  23. ;  Prentice-Hall, Englewood Cliffs, New Jersey, 07632 (1987)
  24. ;  Library of Congress Catalog Card Number 86-63489
  25. ; If you are using a version of Scheme other than MacScheme, you should be
  26. ; able to convert this to whatever you are using.  The main thing to change
  27. ; is the way macros are defined.  There are two macros, (extend-syntax and
  28. ; extend-syntax/code), plus the macro defining form embedded inside of
  29. ; extend-syntax.  You may have to add (or delete) a support function or two.
  30. ; ENJOY!!! :-)
  31. ; Jeff
  32. ; ------------------------distribution starts here------------------------
  33. ; Here is the code for extend-syntax.  It includes the code for:
  34. ;  when
  35. ;  unless
  36. ;  andmap
  37. ;  syntax-match?
  38. ;  extend-syntax
  39. ;  extend-syntax/code
  40. ; To load it, just enter
  41. ;  (load "extend.sch")
  42. ; It takes a while to load and will print out:
  43. ;  when
  44. ;  unless
  45. ;  andmap
  46. ;  syntax-match?
  47. ;  extend-syntax/code
  48. ; (note: extend-syntax gets compiled even though its name doesn't get
  49. ;  printed.  It doesn't get printed because it's inside the LET)
  50. ; After you load it, you may want to do a (dumpheap)  See the MacScheme
  51. ; manual for details.
  52. ; The documentation for extend-syntax is in "The Scheme Programming
  53. ; Language" by R. Kent Dybvig.  Buy the book.  (No, I don't get any
  54. ; kickbacks).  extend-syntax/code returns the source for the
  55. ; lambda expression that would have been bound to the macro, which is
  56. ; helpful during debugging and for getting a feel for how extend-syntax
  57. ; works.  You might try (pretty-print (extend-syntax/code --- etc. if
  58. ; you want to be able to read it easily.  Note that the output isn't
  59. ; directly useable because of gensym'ed variables and how MacScheme
  60. ; prints quasiquotes, etc.  Use extend-syntax to make the macros.
  61. ; If you have any comments or problems, feel free to contact me.  I won't
  62. ; promise anything, but I'll give it a look.  If you port the code to another
  63. ; version of Scheme, I would be interested in hearing about it.
  64. ; Jeff De Vries
  65. ; (ARPA: jdevries@ads.arpa)
  66. ; DISCLAIMER: All the usual stuff...
  67. ; -----------------------------snip here---------------------------------
  68. ;;; extend.sch
  69. ;;; Copyright (C) 1987 Cadence Research Systems
  70. ;;; Permission to copy this software, in whole or in part, to use this
  71. ;;; software for any lawful noncommercial purpose, and to redistribute
  72. ;;; this software is granted subject to the restriction that all copies
  73. ;;; made of this software must include this copyright notice in full.
  74. ;;; Cadence makes no warranties or representations of any kind, either
  75. ;;; express or implied, including but not limited to implied warranties
  76. ;;; of merchantability or fitness for any particular purpose.
  77.  
  78. ;;; The basic design of extend-syntax is due to Eugene Kohlbecker.  See
  79. ;;; "E. Kohlbecker: Syntactic Extensions in the Programming Language Lisp",
  80. ;;; Ph.D.  Dissertation, Indiana University, 1986."  The structure of "with"
  81. ;;; pattern/value clauses, the method for compiling extend-syntax into
  82. ;;; Scheme code, and the actual implementation are due to Kent Dybvig.
  83.  
  84. ;;; Made available courtesy R. Kent Dybvig
  85. ;;; MacScheme conversion by Jeff De Vries
  86. ;;; note: requires the use of MacScheme Version 1.2 or greater
  87.  
  88. ;;; the following routines are provided for compatibility with TSPL:
  89. (macro when
  90.        (lambda (args)
  91.          `(if ,(cadr args)
  92.               (begin ,@(cddr args))
  93.               #f)))
  94. (macro unless
  95.        (lambda (args)
  96.          `(if ,(cadr args)
  97.               #t
  98.               (begin ,@(cddr args)))))
  99.  
  100. (define (andmap p . args)
  101.   ;; use "first-finish" rule
  102.   (let andmap ((args args) (value #t))
  103.     (if (let any-at-end? ((ls args))
  104.           (and (pair? ls)
  105.                (or (not (pair? (car ls)))
  106.                    (any-at-end? (cdr ls)))))
  107.         value
  108.         (let ((value (apply p (map car args))))
  109.           (and value (andmap (map cdr args) value))))))
  110.  
  111. ;;; syntax-match? is used by extend-syntax to choose among clauses and
  112. ;;; to check for syntactic errors.  It is also available to the user.
  113. (define syntax-match?
  114.   (lambda (keys pat exp)
  115.     (cond
  116.      ((symbol? pat) (if (memq pat keys) (eq? exp pat) #t))
  117.      ((pair? pat)
  118.       (if (equal? (cdr pat) '(...))
  119.           (let f ((lst exp))
  120.             (or (null? lst)
  121.                 (and (pair? lst)
  122.                      (syntax-match? keys (car pat) (car lst))
  123.                      (f (cdr lst)))))
  124.           (and (pair? exp)
  125.                (syntax-match? keys (car pat) (car exp))
  126.                (syntax-match? keys (cdr pat) (cdr exp)))))
  127.      (else (equal? exp pat)))))
  128.  
  129. ;;; The main code!
  130. (let ()
  131.   (define id
  132.     (lambda (name access control)
  133.       (list name access control)))
  134.   (define id-name car)
  135.   (define id-access cadr)
  136.   (define id-control caddr)
  137.   
  138.   (define loop
  139.     (lambda ()
  140.       (list '())))
  141.   (define loop-ids car)
  142.   (define loop-ids! set-car!)
  143.   
  144.   (define c...rs
  145.     `((car caar . cdar)
  146.       (cdr cadr . cddr)
  147.       (caar caaar . cdaar)
  148.       (cadr caadr . cdadr)
  149.       (cdar cadar . cddar)
  150.       (cddr caddr . cdddr)
  151.       (caaar caaaar . cdaaar)
  152.       (caadr caaadr . cdaadr)
  153.       (cadar caadar . cdadar)
  154.       (caddr caaddr . cdaddr)
  155.       (cdaar cadaar . cddaar)
  156.       (cdadr cadadr . cddadr)
  157.       (cddar caddar . cdddar)
  158.       (cdddr cadddr . cddddr)))
  159.   
  160.   (define add-car
  161.     (lambda (access)
  162.       (let ((x (and (pair? access) (assq (car access) c...rs))))
  163.         (if (not x)
  164.             `(car ,access)
  165.             `(,(cadr x) ,@(cdr access))))))
  166.   
  167.   (define add-cdr
  168.     (lambda (access)
  169.       (let ((x (and (pair? access) (assq (car access) c...rs))))
  170.         (if (not x)
  171.             `(cdr ,access)
  172.             `(,(cddr x) ,@(cdr access))))))
  173.   
  174.   (define parse
  175.     (lambda (keys pat acc cntl ids)
  176.       (cond
  177.        ((symbol? pat)
  178.         (if (memq pat keys)
  179.             ids
  180.             (cons (id pat acc cntl) ids)))
  181.        ((pair? pat)
  182.         (if (equal? (cdr pat) '(...))
  183.             (let ((x (gensym)))
  184.               (parse keys (car pat) x (id x acc cntl) ids))
  185.             (parse keys
  186.                    (car pat)
  187.                    (add-car acc)
  188.                    cntl
  189.                    (parse keys (cdr pat) (add-cdr acc) cntl ids))))
  190.        (else ids))))
  191.   
  192.   (define gen
  193.     (lambda (keys exp ids loops)
  194.       (cond
  195.        ((symbol? exp)
  196.         (let ((id (lookup exp ids)))
  197.           (if (not id)
  198.               exp
  199.               (begin
  200.                (add-control! (id-control id) loops)
  201.                (list 'unquote (id-access id))))))
  202.        ((pair? exp)
  203.         (cond
  204.          ((eq? (car exp) 'with)
  205.           (unless (syntax-match? '(with) '(with ((p x) ...) e) exp)
  206.                   (error 'extend-syntax "invalid 'with' form" exp))
  207.           (list 'unquote
  208.                 (gen-with
  209.                  keys
  210.                  (map car (cadr exp))
  211.                  (map cadr (cadr exp))
  212.                  (caddr exp)
  213.                  ids
  214.                  loops)))
  215.          ((and (pair? (cdr exp)) (eq? (cadr exp) '...))
  216.           (let ((x (loop)))
  217.             (make-loop
  218.              x
  219.              (gen keys (car exp) ids (cons x loops))
  220.              (gen keys (cddr exp) ids loops))))
  221.          (else
  222.           (let ((a (gen keys (car exp) ids loops))
  223.                 (d (gen keys (cdr exp) ids loops)))
  224.             (if (and (pair? d) (eq? (car d) 'unquote))
  225.                 (list a (list 'unquote-splicing (cadr d)))
  226.                 (cons a d))))))
  227.        (else exp))))
  228.   
  229.   (define gen-with
  230.     (lambda (keys pats exps body ids loops)
  231.       (if (null? pats)
  232.           (make-quasi (gen keys body ids loops))
  233.           (let ((p (car pats)) (e (car exps)) (g (gensym)))
  234.             `(let ((,g ,(gen-quotes keys e ids loops)))
  235.                   (if (syntax-match? '() ',p ,g)
  236.                       ,(gen-with
  237.                         keys
  238.                         (cdr pats)
  239.                         (cdr exps)
  240.                         body
  241.                         (parse '() p g '() ids)
  242.                         loops)
  243.                       (error ',(car keys)
  244.                              "does not fit 'with' pattern"
  245.                              ,g
  246.                               ',p)))))))
  247.   
  248.   (define gen-quotes
  249.     (lambda (keys exp ids loops)
  250.       (cond
  251.        ((syntax-match? '(quote) '(quote x) exp)
  252.         (make-quasi (gen keys (cadr exp) ids loops)))
  253.        ((pair? exp)
  254.         (cons (gen-quotes keys (car exp) ids loops)
  255.               (gen-quotes keys (cdr exp) ids loops)))
  256.        (else exp))))
  257.   
  258.   (define lookup
  259.     (lambda (sym ids)
  260.       (let loop ((ls ids))
  261.         (cond
  262.          ((null? ls) #f)
  263.          ((eq? (id-name (car ls)) sym) (car ls))
  264.          (else (loop (cdr ls)))))))
  265.   
  266.   (define add-control!
  267.     (lambda (id loops)
  268.       (unless (null? id)
  269.               (when (null? loops)
  270.                     (error 'extend-syntax "missing ellipsis in expansion"))
  271.               (let ((x (loop-ids (car loops))))
  272.                 (unless (memq id x)
  273.                         (loop-ids! (car loops) (cons id x))))
  274.               (add-control! (id-control id) (cdr loops)))))
  275.   
  276.   (define make-loop
  277.     (lambda (loop body tail)
  278.       (let ((ids (loop-ids loop)))
  279.         (when (null? ids)
  280.               (error 'extend-syntax "extra ellipsis in expansion"))
  281.         (cond
  282.          ((equal? body (list 'unquote (id-name (car ids))))
  283.           (if (null? tail)
  284.               (list 'unquote (id-access (car ids)))
  285.               (cons (list 'unquote-splicing (id-access (car ids)))
  286.                     tail)))
  287.          ((and (null? (cdr ids))
  288.                (syntax-match? '(unquote) '(unquote (f x)) body)
  289.                (eq? (cadadr body) (id-name (car ids))))
  290.           (let ((x `(map ,(caadr body) ,(id-access (car ids)))))
  291.             (if (null? tail)
  292.                 (list 'unquote x)
  293.                 (cons (list 'unquote-splicing x) tail))))
  294.          (else
  295.           (let ((x `(map (lambda ,(map id-name ids) ,(make-quasi body))
  296.                          ,@(map id-access ids))))
  297.             (if (null? tail)
  298.                 (list 'unquote x)
  299.                 (cons (list 'unquote-splicing x) tail))))))))
  300.   
  301.   (define make-quasi
  302.     (lambda (exp)
  303.       (if (and (pair? exp) (eq? (car exp) 'unquote))
  304.           (cadr exp)
  305.           (list 'quasiquote exp))))
  306.   
  307.   (define make-clause
  308.     (lambda (keys cl x)
  309.       (cond
  310.        ((syntax-match? '() '(pat fender exp) cl)
  311.         (let ((pat (car cl)) (fender (cadr cl)) (exp (caddr cl)))
  312.           (let ((ids (parse keys pat x '() '())))
  313.             `((and (syntax-match? ',keys ',pat ,x)
  314.                    ,(gen-quotes keys fender ids '()))
  315.               ,(make-quasi (gen keys exp ids '()))))))
  316.        ((syntax-match? '() '(pat exp) cl)
  317.         (let ((pat (car cl)) (exp (cadr cl)))
  318.           (let ((ids (parse keys pat x '() '())))
  319.             `((syntax-match? ',keys ',pat ,x)
  320.               ,(make-quasi (gen keys exp ids '()))))))
  321.        (else
  322.         (error 'extend-syntax "invalid clause" cl)))))
  323.   
  324.   (define make-syntax
  325.     (let ((x (gensym "x")))
  326.       (lambda (keys clauses)
  327.         `(lambda (,x)
  328.                  (cond
  329.                   ,@(map (lambda (cl) (make-clause keys cl x)) clauses)
  330.                     (else
  331.                      (error ',(car keys) "invalid syntax" ,x)))))))
  332.   
  333.   (macro extend-syntax
  334.          (lambda (x)
  335.            (cond
  336.             ((and
  337.               (syntax-match?
  338.                '(extend-syntax)
  339.                '(extend-syntax (key1 key2 ...) clause ...)
  340.                x)
  341.               (andmap symbol? `(,(caadr x) ,@(cdadr x))))
  342.              (let
  343.                ((f (make-syntax `(,(caadr x) ,@(cdadr x)) (cddr x))))
  344.                (if (syntax-match? '() 'proc f)
  345.                    `(macro ,(caadr x) ,f)
  346.                    (error 'extend-syntax
  347.                           "does not fit 'with' pattern"
  348.                           f
  349.                           'proc))))
  350.             (else (error 'extend-syntax "invalid syntax" x)))))
  351.   
  352.   (macro extend-syntax/code
  353.          (lambda (x)
  354.            (cond
  355.             ((and
  356.               (syntax-match?
  357.                '(extend-syntax/code)
  358.                '(extend-syntax/code (key1 key2 ...) clause ...)
  359.                x)
  360.               (andmap symbol? `(,(caadr x) ,@(cdadr x))))
  361.              (let
  362.                ((f (make-syntax `(,(caadr x) ,@(cdadr x)) (cddr x))))
  363.                (if (syntax-match? '() 'proc f)
  364.                    `',f
  365.                       (error 'extend-syntax/code
  366.                              "does not fit 'with' pattern"
  367.                              f
  368.                              'proc))))
  369.             (else (error 'extend-syntax/code "invalid syntax" x)))))
  370.   
  371.   ) ;;; end of let
  372. ;;; end extend.sch
  373.