syntax.scm 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees
  3. ; Rewrite-rule compiler (a.k.a. "extend-syntax")
  4. ; Example:
  5. ;
  6. ; (define-syntax or
  7. ; (syntax-rules ()
  8. ; ((or) #f)
  9. ; ((or e) e)
  10. ; ((or e1 e ...) (let ((temp e1))
  11. ; (if temp temp (or e ...))))))
  12. (define-syntax syntax-rules
  13. (let ()
  14. (define name? symbol?)
  15. (define (segment-pattern? pattern)
  16. (and (segment-template? pattern)
  17. (or (null? (cddr pattern))
  18. (syntax-error "segment matching not implemented" pattern))))
  19. (define (segment-template? pattern)
  20. (and (pair? pattern)
  21. (pair? (cdr pattern))
  22. (memq (cadr pattern) indicators-for-zero-or-more)))
  23. (define indicators-for-zero-or-more (list (string->symbol "...") '---))
  24. (lambda (exp r c)
  25. (define %input (r '%input)) ;Gensym these, if you like.
  26. (define %compare (r '%compare))
  27. (define %rename (r '%rename))
  28. (define %tail (r '%tail))
  29. (define %temp (r '%temp))
  30. (define rules (cddr exp))
  31. (define subkeywords (cadr exp))
  32. (define (make-transformer rules)
  33. `(lambda (,%input ,%rename ,%compare)
  34. (let ((,%tail (cdr ,%input)))
  35. (cond ,@(map process-rule rules)
  36. (else
  37. (syntax-error
  38. "use of macro doesn't match definition"
  39. ,%input))))))
  40. (define (process-rule rule)
  41. (if (and (pair? rule)
  42. (pair? (cdr rule))
  43. (null? (cddr rule)))
  44. (let ((pattern (cdar rule))
  45. (template (cadr rule)))
  46. `((and ,@(process-match %tail pattern))
  47. (let* ,(process-pattern pattern
  48. %tail
  49. (lambda (x) x))
  50. ,(process-template template
  51. 0
  52. (meta-variables pattern 0 '())))))
  53. (syntax-error "ill-formed syntax rule" rule)))
  54. ; Generate code to test whether input expression matches pattern
  55. (define (process-match input pattern)
  56. (cond ((name? pattern)
  57. (if (member pattern subkeywords)
  58. `((,%compare ,input (,%rename ',pattern)))
  59. `()))
  60. ((segment-pattern? pattern)
  61. (process-segment-match input (car pattern)))
  62. ((pair? pattern)
  63. `((let ((,%temp ,input))
  64. (and (pair? ,%temp)
  65. ,@(process-match `(car ,%temp) (car pattern))
  66. ,@(process-match `(cdr ,%temp) (cdr pattern))))))
  67. ((or (null? pattern) (boolean? pattern) (char? pattern))
  68. `((eq? ,input ',pattern)))
  69. (else
  70. `((equal? ,input ',pattern)))))
  71. (define (process-segment-match input pattern)
  72. (let ((conjuncts (process-match '(car l) pattern)))
  73. (if (null? conjuncts)
  74. `((list? ,input)) ;+++
  75. `((let loop ((l ,input))
  76. (or (null? l)
  77. (and (pair? l)
  78. ,@conjuncts
  79. (loop (cdr l)))))))))
  80. ; Generate code to take apart the input expression
  81. ; This is pretty bad, but it seems to work (can't say why).
  82. (define (process-pattern pattern path mapit)
  83. (cond ((name? pattern)
  84. (if (memq pattern subkeywords)
  85. '()
  86. (list (list pattern (mapit path)))))
  87. ((segment-pattern? pattern)
  88. (process-pattern (car pattern)
  89. %temp
  90. (lambda (x) ;temp is free in x
  91. (mapit (if (eq? %temp x)
  92. path ;+++
  93. `(map (lambda (,%temp) ,x)
  94. ,path))))))
  95. ((pair? pattern)
  96. (append (process-pattern (car pattern) `(car ,path) mapit)
  97. (process-pattern (cdr pattern) `(cdr ,path) mapit)))
  98. (else '())))
  99. ; Generate code to compose the output expression according to template
  100. (define (process-template template rank env)
  101. (cond ((name? template)
  102. (let ((probe (assq template env)))
  103. (if probe
  104. (if (<= (cdr probe) rank)
  105. template
  106. (syntax-error "template rank error (too few ...'s?)"
  107. template))
  108. `(,%rename ',template))))
  109. ((segment-template? template)
  110. (let ((vars
  111. (free-meta-variables (car template) (+ rank 1) env '())))
  112. (if (null? vars)
  113. (syntax-error "too many ...'s" template)
  114. (let* ((x (process-template (car template)
  115. (+ rank 1)
  116. env))
  117. (gen (if (equal? (list x) vars)
  118. x ;+++
  119. `(map (lambda ,vars ,x)
  120. ,@vars))))
  121. (if (null? (cddr template))
  122. gen ;+++
  123. `(append ,gen ,(process-template (cddr template)
  124. rank env)))))))
  125. ((pair? template)
  126. `(cons ,(process-template (car template) rank env)
  127. ,(process-template (cdr template) rank env)))
  128. (else `(quote ,template))))
  129. ; Return an association list of (var . rank)
  130. (define (meta-variables pattern rank vars)
  131. (cond ((name? pattern)
  132. (if (memq pattern subkeywords)
  133. vars
  134. (cons (cons pattern rank) vars)))
  135. ((segment-pattern? pattern)
  136. (meta-variables (car pattern) (+ rank 1) vars))
  137. ((pair? pattern)
  138. (meta-variables (car pattern) rank
  139. (meta-variables (cdr pattern) rank vars)))
  140. (else vars)))
  141. ; Return a list of meta-variables of given higher rank
  142. (define (free-meta-variables template rank env free)
  143. (cond ((name? template)
  144. (if (and (not (memq template free))
  145. (let ((probe (assq template env)))
  146. (and probe (>= (cdr probe) rank))))
  147. (cons template free)
  148. free))
  149. ((segment-template? template)
  150. (free-meta-variables (car template)
  151. rank env
  152. (free-meta-variables (cddr template)
  153. rank env free)))
  154. ((pair? template)
  155. (free-meta-variables (car template)
  156. rank env
  157. (free-meta-variables (cdr template)
  158. rank env free)))
  159. (else free)))
  160. c ;ignored
  161. ;; Kludge for Scheme 48 static linker.
  162. ;; `(cons ,(make-transformer rules)
  163. ;; ',(find-free-names-in-syntax-rules subkeywords rules))
  164. (make-transformer rules))))